1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "binder/package_version_map.h"
18 #include "common/debug.h"
19 #include "common/expected.h"
20 #include "common/printer.h"
21 #include "common/rx_async.h"
22 #include "common/property.h"
23 #include "common/trace.h"
24 #include "db/app_component_name.h"
25 #include "db/file_models.h"
26 #include "db/models.h"
27 #include "maintenance/controller.h"
28 #include "maintenance/db_cleaner.h"
29 #include "manager/event_manager.h"
30 #include "perfetto/rx_producer.h"
31 #include "prefetcher/read_ahead.h"
32 #include "prefetcher/task_id.h"
33
34 #include <android-base/chrono_utils.h>
35 #include <android-base/strings.h>
36 #include <android-base/properties.h>
37 #include <rxcpp/rx.hpp>
38 #include <server_configurable_flags/get_flags.h>
39 #include <utils/misc.h>
40 #include <utils/Trace.h>
41
42 #include <atomic>
43 #include <filesystem>
44 #include <functional>
45 #include <type_traits>
46 #include <unordered_map>
47
48 using rxcpp::observe_on_one_worker;
49
50 namespace iorap::manager {
51
52 using binder::AppLaunchEvent;
53 using binder::DexOptEvent;
54 using binder::JobScheduledEvent;
55 using binder::RequestId;
56 using binder::TaskResult;
57
58 using common::AsyncPool;
59 using common::RxAsync;
60
61 using perfetto::PerfettoStreamCommand;
62 using perfetto::PerfettoTraceProto;
63
64 using db::AppComponentName;
65
66 const constexpr bool kExcludeDexFilesDefault = true;
67
68 static std::atomic<bool> s_tracing_allowed{false};
69 static std::atomic<bool> s_readahead_allowed{false};
70 static std::atomic<uint64_t> s_min_traces{3};
71
72 struct PackageBlacklister {
73 // "x.y.z;foo.bar.baz" colon-separated list of substrings
PackageBlacklisteriorap::manager::PackageBlacklister74 PackageBlacklister(std::string blacklist_string) {
75 LOG(VERBOSE) << "Configuring package blacklister with string: " << blacklist_string;
76
77 std::vector<std::string> split = ::android::base::Split(blacklist_string, ";");
78
79 // Ignore any l/r whitespace or empty strings.
80 for (const std::string& s : split) {
81 std::string t = ::android::base::Trim(s);
82 if (!t.empty()) {
83 LOG(INFO) << "Blacklisted package: " << t << "; will not optimize.";
84 packages_.push_back(t);
85 }
86 }
87 }
88
89 PackageBlacklister() = default;
90
IsBlacklistediorap::manager::PackageBlacklister91 bool IsBlacklisted(const std::string& package_name) const {
92 return std::find(packages_.begin(), packages_.end(), package_name) != packages_.end();
93 }
94
IsBlacklistediorap::manager::PackageBlacklister95 bool IsBlacklisted(const AppComponentName& component_name) const {
96 return IsBlacklisted(component_name.package);
97 }
98
IsBlacklistediorap::manager::PackageBlacklister99 bool IsBlacklisted(const std::optional<AppComponentName>& component_name) const {
100 return component_name.has_value() && IsBlacklisted(component_name->package);
101 }
102
103 private:
104 std::vector<std::string> packages_;
105 };
106
107 using PackageVersionMap = std::unordered_map<std::string, int64_t>;
108
109 // Main logic of the #OnAppLaunchEvent scan method.
110 //
111 // All functions are called from the same thread as the event manager
112 // functions.
113 //
114 // This is a data type, it's moved (std::move) around from one iteration
115 // of #scan to another.
116 struct AppLaunchEventState {
117 std::optional<AppComponentName> component_name_;
118 // Sequence ID is shared amongst the same app launch sequence,
119 // but changes whenever a new app launch sequence begins.
120 size_t sequence_id_ = static_cast<size_t>(-1);
121 std::optional<AppLaunchEvent::Temperature> temperature_;
122
123 // Push data to perfetto rx chain for associating
124 // the raw_trace with the history_id.
125 std::optional<rxcpp::subscriber<int>> history_id_subscriber_;
126 rxcpp::observable<int> history_id_observable_;
127
128 std::optional<uint64_t> intent_started_ns_;
129 std::optional<uint64_t> total_time_ns_;
130
131 // Used by kReportFullyDrawn to find the right history_id.
132 // We assume no interleaving between different sequences.
133 // This assumption is checked in the Java service code.
134 std::optional<uint64_t> recent_history_id_;
135
136 // labeled as 'shared' due to rx not being able to handle move-only objects.
137 // lifetime: in practice equivalent to unique_ptr.
138 std::shared_ptr<prefetcher::ReadAhead> read_ahead_;
139 bool allowed_readahead_{true};
140 bool is_read_ahead_{false};
141 std::optional<prefetcher::TaskId> read_ahead_task_;
142
143 bool allowed_tracing_{true};
144 bool is_tracing_{false};
145 std::optional<rxcpp::composite_subscription> rx_lifetime_;
146 std::vector<rxcpp::composite_subscription> rx_in_flight_;
147
148 PackageBlacklister package_blacklister_{};
149
150 borrowed<perfetto::RxProducerFactory*> perfetto_factory_; // not null
151 borrowed<observe_on_one_worker*> thread_; // not null
152 borrowed<observe_on_one_worker*> io_thread_; // not null
153 borrowed<AsyncPool*> async_pool_; // not null
154
155 std::shared_ptr<binder::PackageVersionMap> version_map_;
156
AppLaunchEventStateiorap::manager::AppLaunchEventState157 explicit AppLaunchEventState(borrowed<perfetto::RxProducerFactory*> perfetto_factory,
158 bool allowed_readahead,
159 bool allowed_tracing,
160 PackageBlacklister package_blacklister,
161 borrowed<observe_on_one_worker*> thread,
162 borrowed<observe_on_one_worker*> io_thread,
163 borrowed<AsyncPool*> async_pool,
164 std::shared_ptr<binder::PackageVersionMap> version_map)
165 : read_ahead_{std::make_shared<prefetcher::ReadAhead>()}
166 {
167 perfetto_factory_ = perfetto_factory;
168 DCHECK(perfetto_factory_ != nullptr);
169
170 allowed_readahead_ = allowed_readahead;
171 allowed_tracing_ = allowed_tracing;
172
173 package_blacklister_ = package_blacklister;
174
175 thread_ = thread;
176 DCHECK(thread_ != nullptr);
177
178 io_thread_ = io_thread;
179 DCHECK(io_thread_ != nullptr);
180
181 async_pool_ = async_pool;
182 DCHECK(async_pool_ != nullptr);
183
184 version_map_ = version_map;
185 DCHECK(version_map_ != nullptr);
186 }
187
188 // Updates the values in this struct only as a side effect.
189 //
190 // May create and fire a new rx chain on the same threads as passed
191 // in by the constructors.
OnNewEventiorap::manager::AppLaunchEventState192 void OnNewEvent(const AppLaunchEvent& event) {
193 LOG(VERBOSE) << "AppLaunchEventState#OnNewEvent: " << event;
194
195 android::ScopedTrace trace_db_init{ATRACE_TAG_ACTIVITY_MANAGER,
196 "IorapNativeService::OnAppLaunchEvent"};
197
198 using Type = AppLaunchEvent::Type;
199
200 DCHECK_GE(event.sequence_id, 0);
201 sequence_id_ = static_cast<size_t>(event.sequence_id);
202 allowed_readahead_ = s_readahead_allowed;
203 allowed_tracing_ = s_tracing_allowed;
204
205 switch (event.type) {
206 case Type::kIntentStarted: {
207 const std::string& package_name = event.intent_proto->component().package_name();
208 const std::string& class_name = event.intent_proto->component().class_name();
209 AppComponentName component_name{package_name, class_name};
210 component_name = component_name.Canonicalize();
211 component_name_ = component_name;
212
213 if (package_blacklister_.IsBlacklisted(component_name)) {
214 LOG(DEBUG) << "kIntentStarted: package " << component_name.package
215 << " ignored due to blacklisting.";
216 break;
217 }
218
219 // Create a new history ID chain for each new app start-up sequence.
220 auto history_id_observable = rxcpp::observable<>::create<int>(
221 [&](rxcpp::subscriber<int> subscriber) {
222 history_id_subscriber_ = std::move(subscriber);
223 LOG(VERBOSE) << " set up the history id subscriber ";
224 })
225 .tap([](int history_id) { LOG(VERBOSE) << " tap rx history id = " << history_id; })
226 .replay(1); // Remember the history id in case we subscribe too late.
227
228 history_id_observable_ = history_id_observable;
229
230 // Immediately turn observable hot, creating the subscriber.
231 history_id_observable.connect();
232
233 DCHECK(!IsTracing());
234
235 // The time should be set before perfetto tracing.
236 // Record the timestamp even no perfetto tracing is triggered,
237 // because the tracing may start in the following ActivityLaunched
238 // event. Otherwise, there will be no starting timestamp and
239 // trace without starting timestamp is not considered for compilation.
240 if (event.timestamp_nanos >= 0) {
241 intent_started_ns_ = event.timestamp_nanos;
242 } else {
243 LOG(WARNING) << "Negative event timestamp: " << event.timestamp_nanos;
244 }
245 break;
246 }
247 case Type::kIntentFailed:
248 if (package_blacklister_.IsBlacklisted(component_name_)) {
249 LOG(VERBOSE) << "kIntentFailed: package " << component_name_->package
250 << " ignored due to blacklisting.";
251 break;
252 }
253
254 if (history_id_subscriber_) {
255 history_id_subscriber_->on_error(rxcpp::util::make_error_ptr(
256 std::ios_base::failure("Aborting due to intent failed")));
257 history_id_subscriber_ = std::nullopt;
258 }
259
260 break;
261 case Type::kActivityLaunched: {
262 // TODO add test in Android framework to verify this.
263 const std::string& title =
264 event.activity_record_proto->window_token().window_container().identifier().title();
265 if (!AppComponentName::HasAppComponentName(title)) {
266 // Proto comment claim this is sometimes a window title.
267 // We need the actual 'package/component' here, so just ignore it if it's a title.
268 LOG(WARNING) << "App launched without a component name: " << event;
269 break;
270 }
271
272 AppComponentName component_name = AppComponentName::FromString(title);
273 component_name = component_name.Canonicalize();
274 component_name_ = component_name;
275
276 if (package_blacklister_.IsBlacklisted(component_name_)) {
277 LOG(VERBOSE) << "kActivityLaunched: package " << component_name_->package
278 << " ignored due to blacklisting.";
279 break;
280 }
281
282 // Cancel tracing for warm/hot.
283 // Restart tracing if the activity was unexpected.
284
285 AppLaunchEvent::Temperature temperature = event.temperature;
286 temperature_ = temperature;
287 if (temperature != AppLaunchEvent::Temperature::kCold) {
288 LOG(DEBUG) << "AppLaunchEventState#OnNewEvent don't trace due to non-cold temperature";
289 } else if (!IsTracing() && !IsReadAhead()) { // and the temperature is Cold.
290 // Start late trace when intent didn't have a component name
291 LOG(VERBOSE) << "AppLaunchEventState#OnNewEvent need to start new trace";
292
293 if (allowed_readahead_ && !IsReadAhead()) {
294 StartReadAhead(sequence_id_, component_name);
295 }
296 if (allowed_tracing_ && !IsTracing() && !IsReadAhead()) {
297 rx_lifetime_ = StartTracing(std::move(component_name));
298 }
299 } else {
300 // FIXME: match actual component name against intent component name.
301 // abort traces if they don't match.
302
303 if (allowed_tracing_) {
304 LOG(VERBOSE) << "AppLaunchEventState#OnNewEvent already tracing";
305 }
306 LOG(VERBOSE) << "AppLaunchEventState#OnNewEvent already doing readahead";
307 }
308 break;
309 }
310 case Type::kActivityLaunchFinished:
311 if (package_blacklister_.IsBlacklisted(component_name_)) {
312 LOG(VERBOSE) << "kActivityLaunchFinished: package " << component_name_->package
313 << " ignored due to blacklisting.";
314 break;
315 }
316
317 if (event.timestamp_nanos >= 0) {
318 total_time_ns_ = event.timestamp_nanos;
319 }
320 RecordDbLaunchHistory(event.activity_record_proto->proc_id());
321 // Finish tracing and collect trace buffer.
322 //
323 // TODO: this happens automatically when perfetto finishes its
324 // trace duration.
325 if (IsTracing()) {
326 MarkPendingTrace();
327 }
328 FinishReadAhead();
329 break;
330 case Type::kActivityLaunchCancelled:
331 if (package_blacklister_.IsBlacklisted(component_name_)) {
332 LOG(VERBOSE) << "kActivityLaunchCancelled: package " << component_name_->package
333 << " ignored due to blacklisting.";
334 break;
335 }
336
337 // Abort tracing.
338 AbortTrace();
339 AbortReadAhead();
340 break;
341 case Type::kReportFullyDrawn: {
342 if (package_blacklister_.IsBlacklisted(component_name_)) {
343 LOG(VERBOSE) << "kReportFullyDrawn: package " << component_name_->package
344 << " ignored due to blacklisting.";
345 break;
346 }
347
348 if (!recent_history_id_) {
349 LOG(WARNING) << "Dangling kReportFullyDrawn event";
350 return;
351 }
352 UpdateReportFullyDrawn(*recent_history_id_, event.timestamp_nanos);
353 recent_history_id_ = std::nullopt;
354 break;
355 }
356 default:
357 DCHECK(false) << "invalid type: " << event; // binder layer should've rejected this.
358 LOG(ERROR) << "invalid type: " << event; // binder layer should've rejected this.
359 }
360 }
361
362 // Is there an in-flight readahead task currently?
IsReadAheadiorap::manager::AppLaunchEventState363 bool IsReadAhead() const {
364 return read_ahead_task_.has_value();
365 }
366
367 // Gets the compiled trace.
368 // If a compiled trace exists in sqlite, use that one. Otherwise, try
369 // to find a prebuilt one.
GetCompiledTraceiorap::manager::AppLaunchEventState370 std::optional<std::string> GetCompiledTrace(const AppComponentName& component_name) {
371 ScopedFormatTrace atrace_get_compiled_trace(ATRACE_TAG_ACTIVITY_MANAGER, "GetCompiledTrace");
372 // Firstly, try to find the compiled trace from sqlite.
373 android::base::Timer timer{};
374 db::DbHandle db{db::SchemaModel::GetSingleton()};
375 std::optional<int> version =
376 version_map_->GetOrQueryPackageVersion(component_name.package);
377 if (!version) {
378 LOG(DEBUG) << "The version is NULL, maybe package manager is down.";
379 return std::nullopt;
380 }
381 db::VersionedComponentName vcn{component_name.package,
382 component_name.activity_name,
383 *version};
384
385 std::optional<db::PrefetchFileModel> compiled_trace =
386 db::PrefetchFileModel::SelectByVersionedComponentName(db, vcn);
387
388 std::chrono::milliseconds duration_ms = timer.duration();
389 LOG(DEBUG) << "EventManager: Looking up compiled trace done in "
390 << duration_ms.count() // the count of ticks.
391 << "ms.";
392
393 if (compiled_trace) {
394 if (std::filesystem::exists(compiled_trace->file_path)) {
395 return compiled_trace->file_path;
396 } else {
397 LOG(DEBUG) << "Compiled trace in sqlite doesn't exists. file_path: "
398 << compiled_trace->file_path;
399 }
400 }
401
402 LOG(DEBUG) << "Cannot find compiled trace in sqlite for package_name: "
403 << component_name.package
404 << " activity_name: "
405 << component_name.activity_name;
406
407 // If sqlite doesn't have the compiled trace, try the prebuilt path.
408 std::string file_path = "/product/iorap-trace/";
409 file_path += component_name.ToMakeFileSafeEncodedPkgString();
410 file_path += ".compiled_trace.pb";
411
412 if (std::filesystem::exists(file_path)) {
413 return file_path;
414 }
415
416 LOG(DEBUG) << "Prebuilt compiled trace doesn't exists. file_path: "
417 << file_path;
418
419 return std::nullopt;
420 }
421
StartReadAheadiorap::manager::AppLaunchEventState422 void StartReadAhead(size_t id, const AppComponentName& component_name) {
423 DCHECK(allowed_readahead_);
424 DCHECK(!IsReadAhead());
425
426 std::optional<std::string> file_path = GetCompiledTrace(component_name);
427 if (!file_path) {
428 LOG(VERBOSE) << "Cannot find a compiled trace.";
429 return;
430 }
431
432 prefetcher::TaskId task{id, *file_path};
433 read_ahead_->BeginTask(task);
434 // TODO: non-void return signature?
435
436 read_ahead_task_ = std::move(task);
437 }
438
FinishReadAheadiorap::manager::AppLaunchEventState439 void FinishReadAhead() {
440 // if no readahead task exist, do nothing.
441 if (!IsReadAhead()){
442 return;
443 }
444
445 read_ahead_->FinishTask(*read_ahead_task_);
446 read_ahead_task_ = std::nullopt;
447 }
448
AbortReadAheadiorap::manager::AppLaunchEventState449 void AbortReadAhead() {
450 FinishReadAhead();
451 }
452
IsTracingiorap::manager::AppLaunchEventState453 bool IsTracing() const {
454 return is_tracing_;
455 }
456
StartTracingiorap::manager::AppLaunchEventState457 std::optional<rxcpp::composite_subscription> StartTracing(
458 AppComponentName component_name) {
459 DCHECK(allowed_tracing_);
460 DCHECK(!IsTracing());
461
462 std::optional<int> version =
463 version_map_->GetOrQueryPackageVersion(component_name_->package);
464 if (!version) {
465 LOG(DEBUG) << "The version is NULL, maybe package manager is down.";
466 return std::nullopt;
467 }
468 db::VersionedComponentName versioned_component_name{component_name.package,
469 component_name.activity_name,
470 *version};
471 db::DbHandle db{db::SchemaModel::GetSingleton()};
472 {
473 ScopedFormatTrace atrace_traces_number_check(
474 ATRACE_TAG_ACTIVITY_MANAGER, "IorapNativeService::CheckPerfettoTracesNnumber");
475 // Just return if we have enough perfetto traces.
476 if (!db::PerfettoTraceFileModel::NeedMorePerfettoTraces(
477 db, versioned_component_name)) {
478 return std::nullopt;
479 }
480 }
481
482 auto /*observable<PerfettoStreamCommand>*/ perfetto_commands =
483 rxcpp::observable<>::just(PerfettoStreamCommand::kStartTracing)
484 // wait 1x
485 .concat(
486 // Pick a value longer than the perfetto config delay_ms, so that we send
487 // 'kShutdown' after tracing has already finished.
488 rxcpp::observable<>::interval(std::chrono::milliseconds(10000))
489 .take(2) // kStopTracing, kShutdown.
490 .map([](int value) {
491 // value is 1,2,3,...
492 return static_cast<PerfettoStreamCommand>(value); // 1,2, ...
493 })
494 );
495
496 auto /*observable<PerfettoTraceProto>*/ trace_proto_stream =
497 perfetto_factory_->CreateTraceStream(perfetto_commands);
498 // This immediately connects to perfetto asynchronously.
499 //
500 // TODO: create a perfetto handle earlier, to minimize perfetto startup latency.
501
502 rxcpp::composite_subscription lifetime;
503
504 auto stream_via_threads = trace_proto_stream
505 .tap([](const PerfettoTraceProto& trace_proto) {
506 LOG(VERBOSE) << "StartTracing -- PerfettoTraceProto received (1)";
507 })
508 .combine_latest(history_id_observable_)
509 .observe_on(*thread_) // All work prior to 'observe_on' is handled on thread_.
510 .subscribe_on(*thread_) // All work prior to 'observe_on' is handled on thread_.
511 .observe_on(*io_thread_) // Write data on an idle-class-priority thread.
512 .tap([](std::tuple<PerfettoTraceProto, int> trace_tuple) {
513 LOG(VERBOSE) << "StartTracing -- PerfettoTraceProto received (2)";
514 });
515
516 lifetime = RxAsync::SubscribeAsync(*async_pool_,
517 std::move(stream_via_threads),
518 /*on_next*/[versioned_component_name]
519 (std::tuple<PerfettoTraceProto, int> trace_tuple) {
520 PerfettoTraceProto& trace_proto = std::get<0>(trace_tuple);
521 int history_id = std::get<1>(trace_tuple);
522
523 db::PerfettoTraceFileModel file_model =
524 db::PerfettoTraceFileModel::CalculateNewestFilePath(versioned_component_name);
525
526 std::string file_path = file_model.FilePath();
527
528 ScopedFormatTrace atrace_write_to_file(ATRACE_TAG_ACTIVITY_MANAGER,
529 "Perfetto Write Trace To File %s",
530 file_path.c_str());
531
532 if (!file_model.MkdirWithParents()) {
533 LOG(ERROR) << "Cannot save TraceBuffer; failed to mkdirs " << file_path;
534 return;
535 }
536
537 if (!trace_proto.WriteFullyToFile(file_path)) {
538 LOG(ERROR) << "Failed to save TraceBuffer to " << file_path;
539 } else {
540 LOG(INFO) << "Perfetto TraceBuffer saved to file: " << file_path;
541
542 ScopedFormatTrace atrace_update_raw_traces_table(
543 ATRACE_TAG_ACTIVITY_MANAGER,
544 "update raw_traces table history_id = %d",
545 history_id);
546 db::DbHandle db{db::SchemaModel::GetSingleton()};
547 std::optional<db::RawTraceModel> raw_trace =
548 db::RawTraceModel::Insert(db, history_id, file_path);
549
550 if (!raw_trace) {
551 LOG(ERROR) << "Failed to insert raw_traces for " << file_path;
552 } else {
553 LOG(VERBOSE) << "Inserted into db: " << *raw_trace;
554 }
555 }
556 },
557 /*on_error*/[](rxcpp::util::error_ptr err) {
558 LOG(ERROR) << "Perfetto trace proto collection error: " << rxcpp::util::what(err);
559 });
560
561 is_tracing_ = true;
562
563 return lifetime;
564 }
565
AbortTraceiorap::manager::AppLaunchEventState566 void AbortTrace() {
567 LOG(VERBOSE) << "AppLaunchEventState - AbortTrace";
568
569 // if the tracing is not running, do nothing.
570 if (!IsTracing()){
571 return;
572 }
573
574 is_tracing_ = false;
575 if (rx_lifetime_) {
576 // TODO: it would be good to call perfetto Destroy.
577
578 rx_in_flight_.erase(std::remove(rx_in_flight_.begin(),
579 rx_in_flight_.end(), *rx_lifetime_),
580 rx_in_flight_.end());
581
582 LOG(VERBOSE) << "AppLaunchEventState - AbortTrace - Unsubscribe";
583 rx_lifetime_->unsubscribe();
584
585 rx_lifetime_.reset();
586 }
587 }
588
MarkPendingTraceiorap::manager::AppLaunchEventState589 void MarkPendingTrace() {
590 LOG(VERBOSE) << "AppLaunchEventState - MarkPendingTrace";
591 DCHECK(is_tracing_);
592 DCHECK(rx_lifetime_.has_value());
593
594 if (rx_lifetime_) {
595 LOG(VERBOSE) << "AppLaunchEventState - MarkPendingTrace - lifetime moved";
596 // Don't unsubscribe because that would cause the perfetto TraceBuffer
597 // to get dropped on the floor.
598 //
599 // Instead, we want to let it finish and write it out to a file.
600 rx_in_flight_.push_back(*std::move(rx_lifetime_));
601 rx_lifetime_.reset();
602 } else {
603 LOG(VERBOSE) << "AppLaunchEventState - MarkPendingTrace - lifetime was empty";
604 }
605
606 is_tracing_ = false;
607 // FIXME: how do we clear this vector?
608 }
609
RecordDbLaunchHistoryiorap::manager::AppLaunchEventState610 void RecordDbLaunchHistory(int32_t pid) {
611 std::optional<db::AppLaunchHistoryModel> history = InsertDbLaunchHistory(pid);
612
613 // RecordDbLaunchHistory happens-after kIntentStarted
614 if (!history_id_subscriber_.has_value()) {
615 LOG(WARNING) << "Logic error? Should always have a subscriber here.";
616 return;
617 }
618
619 // Ensure that the history id rx chain is terminated either with an error or with
620 // the newly inserted app_launch_histories.id
621 if (!history) {
622 history_id_subscriber_->on_error(rxcpp::util::make_error_ptr(
623 std::ios_base::failure("Failed to insert history id")));
624 recent_history_id_ = std::nullopt;
625 } else {
626 // Note: we must have already subscribed, or this value will disappear.
627 LOG(VERBOSE) << "history_id_subscriber on_next history_id=" << history->id;
628 history_id_subscriber_->on_next(history->id);
629 history_id_subscriber_->on_completed();
630
631 recent_history_id_ = history->id;
632 }
633 history_id_subscriber_ = std::nullopt;
634 }
635
InsertDbLaunchHistoryiorap::manager::AppLaunchEventState636 std::optional<db::AppLaunchHistoryModel> InsertDbLaunchHistory(int32_t pid) {
637 // TODO: deferred queue into a different lower priority thread.
638 if (!component_name_ || !temperature_) {
639 LOG(VERBOSE) << "Skip RecordDbLaunchHistory, no component name available.";
640
641 return std::nullopt;
642 }
643
644 android::ScopedTrace trace{ATRACE_TAG_ACTIVITY_MANAGER,
645 "IorapNativeService::RecordDbLaunchHistory"};
646 db::DbHandle db{db::SchemaModel::GetSingleton()};
647
648 using namespace iorap::db;
649
650 std::optional<int> version =
651 version_map_->GetOrQueryPackageVersion(component_name_->package);
652 if (!version) {
653 LOG(DEBUG) << "The version is NULL, maybe package manager is down.";
654 return std::nullopt;
655 }
656 std::optional<ActivityModel> activity =
657 ActivityModel::SelectOrInsert(db,
658 component_name_->package,
659 *version,
660 component_name_->activity_name);
661
662 if (!activity) {
663 LOG(WARNING) << "Failed to query activity row for : " << *component_name_;
664 return std::nullopt;
665 }
666
667 auto temp = static_cast<db::AppLaunchHistoryModel::Temperature>(*temperature_);
668
669 std::optional<AppLaunchHistoryModel> alh =
670 AppLaunchHistoryModel::Insert(db,
671 activity->id,
672 temp,
673 IsTracing(),
674 IsReadAhead(),
675 intent_started_ns_,
676 total_time_ns_,
677 // ReportFullyDrawn event normally occurs after this. Need update later.
678 /* report_fully_drawn_ns= */ std::nullopt,
679 pid);
680 //Repo
681 if (!alh) {
682 LOG(WARNING) << "Failed to insert app_launch_histories row";
683 return std::nullopt;
684 }
685
686 LOG(VERBOSE) << "RecordDbLaunchHistory: " << *alh;
687 return alh;
688 }
689
UpdateReportFullyDrawniorap::manager::AppLaunchEventState690 void UpdateReportFullyDrawn(int history_id, uint64_t timestamp_ns) {
691 LOG(DEBUG) << "Update kReportFullyDrawn for history_id:"
692 << history_id
693 << " timestamp_ns: "
694 << timestamp_ns;
695
696 android::ScopedTrace trace{ATRACE_TAG_ACTIVITY_MANAGER,
697 "IorapNativeService::UpdateReportFullyDrawn"};
698 db::DbHandle db{db::SchemaModel::GetSingleton()};
699
700 bool result =
701 db::AppLaunchHistoryModel::UpdateReportFullyDrawn(db,
702 history_id,
703 timestamp_ns);
704
705 if (!result) {
706 LOG(WARNING) << "Failed to update app_launch_histories row";
707 }
708 }
709 };
710
711 struct AppLaunchEventDefender {
712 binder::AppLaunchEvent::Type last_event_type_{binder::AppLaunchEvent::Type::kUninitialized};
713
714 enum class Result {
715 kAccept, // Pass-through the new event.
716 kOverwrite, // Overwrite the new event with a different event.
717 kReject // Completely reject the new event, it will not be delivered.
718 };
719
OnAppLaunchEventiorap::manager::AppLaunchEventDefender720 Result OnAppLaunchEvent(binder::RequestId request_id,
721 const binder::AppLaunchEvent& event,
722 binder::AppLaunchEvent* overwrite) {
723 using Type = binder::AppLaunchEvent::Type;
724 CHECK(overwrite != nullptr);
725
726 // Ensure only legal transitions are allowed.
727 switch (last_event_type_) {
728 case Type::kUninitialized:
729 case Type::kIntentFailed:
730 case Type::kActivityLaunchCancelled:
731 case Type::kReportFullyDrawn: { // From a terminal state, only go to kIntentStarted
732 if (event.type != Type::kIntentStarted) {
733 LOG(DEBUG) << "Rejecting transition from " << last_event_type_ << " to " << event.type;
734 last_event_type_ = Type::kUninitialized;
735 return Result::kReject;
736 } else {
737 LOG(VERBOSE) << "Accept transition from " << last_event_type_ << " to " << event.type;
738 last_event_type_ = event.type;
739 return Result::kAccept;
740 }
741 }
742 case Type::kIntentStarted: {
743 if (event.type == Type::kIntentFailed ||
744 event.type == Type::kActivityLaunched) {
745 LOG(VERBOSE) << "Accept transition from " << last_event_type_ << " to " << event.type;
746 last_event_type_ = event.type;
747 return Result::kAccept;
748 } else {
749 LOG(DEBUG) << "Overwriting transition from kIntentStarted to "
750 << event.type << " into kIntentFailed";
751 last_event_type_ = Type::kIntentFailed;
752
753 *overwrite = event;
754 overwrite->type = Type::kIntentFailed;
755 return Result::kOverwrite;
756 }
757 }
758 case Type::kActivityLaunched: {
759 if (event.type == Type::kActivityLaunchFinished ||
760 event.type == Type::kActivityLaunchCancelled) {
761 LOG(VERBOSE) << "Accept transition from " << last_event_type_ << " to " << event.type;
762 last_event_type_ = event.type;
763 return Result::kAccept;
764 } else {
765 LOG(DEBUG) << "Overwriting transition from kActivityLaunched to "
766 << event.type << " into kActivityLaunchCancelled";
767 last_event_type_ = Type::kActivityLaunchCancelled;
768
769 *overwrite = event;
770 overwrite->type = Type::kActivityLaunchCancelled;
771 return Result::kOverwrite;
772 }
773 }
774 case Type::kActivityLaunchFinished: {
775 if (event.type == Type::kIntentStarted ||
776 event.type == Type::kReportFullyDrawn) {
777 LOG(VERBOSE) << "Accept transition from " << last_event_type_ << " to " << event.type;
778 last_event_type_ = event.type;
779 return Result::kAccept;
780 } else {
781 LOG(DEBUG) << "Rejecting transition from " << last_event_type_ << " to " << event.type;
782 last_event_type_ = Type::kUninitialized;
783 return Result::kReject;
784 }
785 }
786 }
787 }
788 };
789
790 // Convert callback pattern into reactive pattern.
791 struct AppLaunchEventSubject {
792 using RefWrapper =
793 std::reference_wrapper<const AppLaunchEvent>;
794
AppLaunchEventSubjectiorap::manager::AppLaunchEventSubject795 AppLaunchEventSubject() {}
796
Subscribeiorap::manager::AppLaunchEventSubject797 void Subscribe(rxcpp::subscriber<RefWrapper> subscriber) {
798 DCHECK(ready_ != true) << "Cannot Subscribe twice";
799
800 subscriber_ = std::move(subscriber);
801
802 // Release edge of synchronizes-with AcquireIsReady.
803 ready_.store(true);
804 }
805
OnNextiorap::manager::AppLaunchEventSubject806 void OnNext(const AppLaunchEvent& e) {
807 if (!AcquireIsReady()) {
808 return;
809 }
810
811 if (!subscriber_->is_subscribed()) {
812 return;
813 }
814
815 /*
816 * TODO: fix upstream.
817 *
818 * Rx workaround: this fails to compile when
819 * the observable is a reference type:
820 *
821 * external/Reactive-Extensions/RxCpp/Rx/v2/src/rxcpp/rx-observer.hpp:354:18: error: multiple overloads of 'on_next' instantiate to the same signature 'void (const iorap::binder::AppLaunchEvent &) const'
822 * virtual void on_next(T&&) const {};
823 *
824 * external/Reactive-Extensions/RxCpp/Rx/v2/src/rxcpp/rx-observer.hpp:353:18: note: previous declaration is here
825 * virtual void on_next(T&) const {};
826 *
827 * (The workaround is to use reference_wrapper instead
828 * of const AppLaunchEvent&)
829 */
830 subscriber_->on_next(std::cref(e));
831
832 }
833
OnCompletediorap::manager::AppLaunchEventSubject834 void OnCompleted() {
835 if (!AcquireIsReady()) {
836 return;
837 }
838
839 subscriber_->on_completed();
840 }
841
842 private:
AcquireIsReadyiorap::manager::AppLaunchEventSubject843 bool AcquireIsReady() {
844 // Synchronizes-with the release-edge in Subscribe.
845 // This can happen much later, only once the subscription actually happens.
846
847 // However, as far as I know, 'rxcpp::subscriber' is not thread safe,
848 // (but the observable chain itself can be made thread-safe via #observe_on, etc).
849 // so we must avoid reading it until it has been fully synchronized.
850 //
851 // TODO: investigate rxcpp subscribers and see if we can get rid of this atomics,
852 // to make it simpler.
853 return ready_.load();
854 }
855
856 // TODO: also track the RequestId ?
857
858 std::atomic<bool> ready_{false};
859
860
861 std::optional<rxcpp::subscriber<RefWrapper>> subscriber_;
862 };
863
864 // Convert callback pattern into reactive pattern.
865 struct JobScheduledEventSubject {
JobScheduledEventSubjectiorap::manager::JobScheduledEventSubject866 JobScheduledEventSubject() {}
867
Subscribeiorap::manager::JobScheduledEventSubject868 void Subscribe(rxcpp::subscriber<std::pair<RequestId, JobScheduledEvent>> subscriber) {
869 DCHECK(ready_ != true) << "Cannot Subscribe twice";
870
871 subscriber_ = std::move(subscriber);
872
873 // Release edge of synchronizes-with AcquireIsReady.
874 ready_.store(true);
875 }
876
OnNextiorap::manager::JobScheduledEventSubject877 void OnNext(RequestId request_id, JobScheduledEvent e) {
878 if (!AcquireIsReady()) {
879 return;
880 }
881
882 if (!subscriber_->is_subscribed()) {
883 return;
884 }
885
886 subscriber_->on_next(std::pair<RequestId, JobScheduledEvent>{std::move(request_id), std::move(e)});
887
888 }
889
OnCompletediorap::manager::JobScheduledEventSubject890 void OnCompleted() {
891 if (!AcquireIsReady()) {
892 return;
893 }
894
895 subscriber_->on_completed();
896 }
897
898 private:
AcquireIsReadyiorap::manager::JobScheduledEventSubject899 bool AcquireIsReady() {
900 // Synchronizes-with the release-edge in Subscribe.
901 // This can happen much later, only once the subscription actually happens.
902
903 // However, as far as I know, 'rxcpp::subscriber' is not thread safe,
904 // (but the observable chain itself can be made thread-safe via #observe_on, etc).
905 // so we must avoid reading it until it has been fully synchronized.
906 //
907 // TODO: investigate rxcpp subscribers and see if we can get rid of this atomics,
908 // to make it simpler.
909 return ready_.load();
910 }
911
912 // TODO: also track the RequestId ?
913
914 std::atomic<bool> ready_{false};
915
916 std::optional<rxcpp::subscriber<std::pair<RequestId, JobScheduledEvent>>> subscriber_;
917 };
918
operator <<(std::ostream & os,const android::content::pm::PackageChangeEvent & event)919 std::ostream& operator<<(std::ostream& os, const android::content::pm::PackageChangeEvent& event) {
920 os << "PackageChangeEvent{";
921 os << "packageName=" << event.packageName << ",";
922 os << "version=" << event.version << ",";
923 os << "lastUpdateTimeMillis=" << event.lastUpdateTimeMillis;
924 os << "}";
925 return os;
926 }
927
928 class EventManager::Impl {
929 public:
Impl(perfetto::RxProducerFactory & perfetto_factory)930 Impl(/*borrow*/perfetto::RxProducerFactory& perfetto_factory)
931 : perfetto_factory_(perfetto_factory),
932 worker_thread_(rxcpp::observe_on_new_thread()),
933 worker_thread2_(rxcpp::observe_on_new_thread()),
934 io_thread_(perfetto::ObserveOnNewIoThread()) {
935 // Try to create version map
936 RetryCreateVersionMap();
937
938 iorap::common::StderrLogPrinter printer{"iorapd"};
939 RefreshSystemProperties(printer);
940
941 rx_lifetime_ = InitializeRxGraph();
942 rx_lifetime_jobs_ = InitializeRxGraphForJobScheduledEvents();
943
944 android::add_sysprop_change_callback(&Impl::OnSyspropChanged, /*priority*/-10000);
945 }
946
RetryCreateVersionMap()947 void RetryCreateVersionMap() {
948 android::base::Timer timer{};
949 version_map_ = binder::PackageVersionMap::Create();
950 std::chrono::milliseconds duration_ms = timer.duration();
951 LOG(DEBUG) << "Got versions for "
952 << version_map_->Size()
953 << " packages in "
954 << duration_ms.count()
955 << "ms";
956 }
957
SetTaskResultCallbacks(std::shared_ptr<TaskResultCallbacks> callbacks)958 void SetTaskResultCallbacks(std::shared_ptr<TaskResultCallbacks> callbacks) {
959 DCHECK(callbacks_.expired());
960 callbacks_ = callbacks;
961 }
962
Join()963 void Join() {
964 async_pool_.Join();
965 }
966
OnAppLaunchEvent(RequestId request_id,const AppLaunchEvent & event)967 bool OnAppLaunchEvent(RequestId request_id,
968 const AppLaunchEvent& event) {
969 LOG(VERBOSE) << "EventManager::OnAppLaunchEvent("
970 << "request_id=" << request_id.request_id << ","
971 << event;
972
973 // Filter any incoming events through a defender that enforces
974 // that all state transitions are as contractually documented in
975 // ActivityMetricsLaunchObserver's javadoc.
976 AppLaunchEvent overwrite_event{};
977 AppLaunchEventDefender::Result result =
978 app_launch_event_defender_.OnAppLaunchEvent(request_id, event, /*out*/&overwrite_event);
979
980 switch (result) {
981 case AppLaunchEventDefender::Result::kAccept:
982 app_launch_event_subject_.OnNext(event);
983 return true;
984 case AppLaunchEventDefender::Result::kOverwrite:
985 app_launch_event_subject_.OnNext(overwrite_event);
986 return false;
987 case AppLaunchEventDefender::Result::kReject:
988 // Intentionally left-empty: we drop the event completely.
989 return false;
990 }
991
992 // In theory returns BAD_VALUE to the other side of this binder connection.
993 // In practice we use 'oneway' flags so this doesn't matter on a regular build.
994 return false;
995 }
996
OnDexOptEvent(RequestId request_id,const DexOptEvent & event)997 bool OnDexOptEvent(RequestId request_id,
998 const DexOptEvent& event) {
999 LOG(VERBOSE) << "EventManager::OnDexOptEvent("
1000 << "request_id=" << request_id.request_id << ","
1001 << event.package_name
1002 << ")";
1003
1004 if (common::ExcludeDexFiles(kExcludeDexFilesDefault)) {
1005 LOG(VERBOSE) << "Dex files are excluded. Skip the purging.";
1006 return true;
1007 }
1008 return PurgePackage(event.package_name);
1009 }
1010
OnJobScheduledEvent(RequestId request_id,const JobScheduledEvent & event)1011 bool OnJobScheduledEvent(RequestId request_id,
1012 const JobScheduledEvent& event) {
1013 LOG(VERBOSE) << "EventManager::OnJobScheduledEvent("
1014 << "request_id=" << request_id.request_id << ",event=TODO).";
1015
1016 job_scheduled_event_subject_.OnNext(std::move(request_id), event);
1017
1018 return true; // No errors.
1019 }
1020
OnPackageChanged(const android::content::pm::PackageChangeEvent & event)1021 bool OnPackageChanged(const android::content::pm::PackageChangeEvent& event) {
1022 LOG(DEBUG) << "Received " << event;
1023 if (event.isDeleted) {
1024 // Do nothing if the package is deleted rignt now.
1025 // The package will be removed from db during maintenance.
1026 return true;
1027 }
1028 // Update the version map.
1029 if (version_map_->Update(event.packageName, event.version)) {
1030 return true;
1031 }
1032
1033 // Sometimes a package is updated without any version change.
1034 // Clean it up in this case.
1035 db::DbHandle db{db::SchemaModel::GetSingleton()};
1036 db::CleanUpFilesForPackage(db, event.packageName, event.version);
1037 return true;
1038 }
1039
Dump(::android::Printer & printer)1040 void Dump(/*borrow*/::android::Printer& printer) {
1041 ::iorap::prefetcher::ReadAhead::Dump(printer);
1042 ::iorap::perfetto::PerfettoConsumerImpl::Dump(/*borrow*/printer);
1043 ::iorap::maintenance::Dump(db::SchemaModel::GetSingleton(), printer);
1044 }
1045
InitializeRxGraph()1046 rxcpp::composite_subscription InitializeRxGraph() {
1047 LOG(VERBOSE) << "EventManager::InitializeRxGraph";
1048
1049 app_launch_events_ = rxcpp::observable<>::create<AppLaunchEventRefWrapper>(
1050 [&](rxcpp::subscriber<AppLaunchEventRefWrapper> subscriber) {
1051 app_launch_event_subject_.Subscribe(std::move(subscriber));
1052 });
1053
1054 rxcpp::composite_subscription lifetime;
1055
1056 if (!tracing_allowed_) {
1057 LOG(WARNING) << "Tracing disabled by system property";
1058 }
1059 if (!readahead_allowed_) {
1060 LOG(WARNING) << "Readahead disabled by system property";
1061 }
1062
1063 AppLaunchEventState initial_state{&perfetto_factory_,
1064 readahead_allowed_,
1065 tracing_allowed_,
1066 package_blacklister_,
1067 &worker_thread2_,
1068 &io_thread_,
1069 &async_pool_,
1070 version_map_};
1071 app_launch_events_
1072 .subscribe_on(worker_thread_)
1073 .scan(std::move(initial_state),
1074 [](AppLaunchEventState state, AppLaunchEventRefWrapper event) {
1075 state.OnNewEvent(event.get());
1076 return state;
1077 })
1078 .subscribe(/*out*/lifetime, [](const AppLaunchEventState& state) {
1079 // Intentionally left blank.
1080 (void)state;
1081 });
1082
1083 return lifetime;
1084 }
1085
1086 // Runs the maintenance code to compile perfetto traces to compiled
1087 // trace for a package.
StartMaintenance(bool output_text,std::optional<std::string> inode_textcache,bool verbose,bool recompile,uint64_t min_traces,std::string package_name,bool should_update_versions)1088 void StartMaintenance(bool output_text,
1089 std::optional<std::string> inode_textcache,
1090 bool verbose,
1091 bool recompile,
1092 uint64_t min_traces,
1093 std::string package_name,
1094 bool should_update_versions) {
1095 ScopedFormatTrace atrace_bg_scope(ATRACE_TAG_PACKAGE_MANAGER,
1096 "Background Job Scope");
1097
1098 db::DbHandle db{db::SchemaModel::GetSingleton()};
1099 if (should_update_versions) {
1100 {
1101 ScopedFormatTrace atrace_update_versions(ATRACE_TAG_PACKAGE_MANAGER,
1102 "Update package versions map cache");
1103 // Update the version map.
1104 version_map_->UpdateAll();
1105 }
1106
1107 {
1108 ScopedFormatTrace atrace_cleanup_db(ATRACE_TAG_PACKAGE_MANAGER,
1109 "Clean up obsolete data in database");
1110 // Cleanup the obsolete data in the database.
1111 maintenance::CleanUpDatabase(db, version_map_);
1112 }
1113 }
1114
1115 {
1116 ScopedFormatTrace atrace_compile_apps(ATRACE_TAG_PACKAGE_MANAGER,
1117 "Compile apps on device");
1118 // Compilation
1119 maintenance::ControllerParameters params{
1120 output_text,
1121 inode_textcache,
1122 verbose,
1123 recompile,
1124 min_traces,
1125 std::make_shared<maintenance::Exec>(),
1126 common::ExcludeDexFiles(kExcludeDexFilesDefault)};
1127
1128 LOG(DEBUG) << "StartMaintenance: min_traces=" << min_traces;
1129 maintenance::CompileSingleAppOnDevice(db, params, package_name);
1130 }
1131 }
1132
InitializeRxGraphForJobScheduledEvents()1133 rxcpp::composite_subscription InitializeRxGraphForJobScheduledEvents() {
1134 LOG(VERBOSE) << "EventManager::InitializeRxGraphForJobScheduledEvents";
1135
1136 using RequestAndJobEvent = std::pair<RequestId, JobScheduledEvent>;
1137
1138 job_scheduled_events_ = rxcpp::observable<>::create<RequestAndJobEvent>(
1139 [&](rxcpp::subscriber<RequestAndJobEvent> subscriber) {
1140 job_scheduled_event_subject_.Subscribe(std::move(subscriber));
1141 });
1142
1143 rxcpp::composite_subscription lifetime;
1144
1145 job_scheduled_events_
1146 .observe_on(worker_thread_) // async handling.
1147 .tap([this](const RequestAndJobEvent& e) {
1148 LOG(VERBOSE) << "EventManager#JobScheduledEvent#tap(1) - job begins";
1149 this->NotifyProgress(e.first, TaskResult{TaskResult::State::kBegan});
1150
1151 LOG(VERBOSE) << "Compile " << std::get<1>(e).package_name;
1152 StartMaintenance(/*output_text=*/false,
1153 /*inode_textcache=*/std::nullopt,
1154 /*verbose=*/false,
1155 /*recompile=*/false,
1156 s_min_traces,
1157 std::get<1>(e).package_name,
1158 std::get<1>(e).should_update_versions);
1159
1160 // TODO: probably this shouldn't be emitted until most of the usual DCHECKs
1161 // (for example, validate a job isn't already started, the request is not reused, etc).
1162 // In this way we could block from the client until it sees 'kBegan' and Log.wtf otherwise.
1163 })
1164 .tap([](const RequestAndJobEvent& e) {
1165 // TODO. Actual work.
1166 LOG(VERBOSE) << "EventManager#JobScheduledEvent#tap(2) - job is being processed";
1167
1168 // TODO: abort functionality for in-flight jobs.
1169 //
1170 // maybe something like scan that returns an observable<Job> + flat map to that job.
1171 // then we could unsubscribe from the scan to do a partial abort? need to try it and see if it works.
1172 //
1173 // other option is to create a new outer subscription for each job id which seems less ideal.
1174 })
1175 .subscribe(/*out*/lifetime,
1176 /*on_next*/
1177 [this](const RequestAndJobEvent& e) {
1178 LOG(VERBOSE) << "EventManager#JobScheduledEvent#subscribe - job completed";
1179 this->NotifyComplete(e.first, TaskResult{TaskResult::State::kCompleted});
1180 }
1181 #if 0
1182 ,
1183 /*on_error*/
1184 [](rxcpp::util::error_ptr err) {
1185 LOG(ERROR) << "Scheduled job event failed: " << rxcpp::util::what(err);
1186
1187 //std::shared_ptr<TaskResultCallbacks> callbacks = callbacks_.lock();
1188 //if (callbacks != nullptr) {
1189 // FIXME: How do we get the request ID back out of the error? Seems like a problem.
1190 // callbacks->OnComplete(, TaskResult{TaskResult::kError});
1191 // We may have to wrap with an iorap::expected instead of using on_error.
1192 //}
1193
1194 // FIXME: need to add a 'OnErrorResumeNext' operator?
1195 DCHECK(false) << "forgot to implement OnErrorResumeNext";
1196 }
1197 #endif
1198 );
1199
1200 // TODO: error output should happen via an observable.
1201
1202 return lifetime;
1203 }
1204
NotifyComplete(RequestId request_id,TaskResult result)1205 void NotifyComplete(RequestId request_id, TaskResult result) {
1206 std::shared_ptr<TaskResultCallbacks> callbacks = callbacks_.lock();
1207 if (callbacks != nullptr) {
1208 callbacks->OnComplete(std::move(request_id), std::move(result));
1209 } else {
1210 LOG(WARNING) << "EventManager: TaskResultCallbacks may have been released early";
1211 }
1212 }
1213
NotifyProgress(RequestId request_id,TaskResult result)1214 void NotifyProgress(RequestId request_id, TaskResult result) {
1215 std::shared_ptr<TaskResultCallbacks> callbacks = callbacks_.lock();
1216 if (callbacks != nullptr) {
1217 callbacks->OnProgress(std::move(request_id), std::move(result));
1218 } else {
1219 LOG(WARNING) << "EventManager: TaskResultCallbacks may have been released early";
1220 }
1221 }
1222
OnSyspropChanged()1223 static void OnSyspropChanged() {
1224 LOG(DEBUG) << "OnSyspropChanged";
1225 }
1226
RefreshSystemProperties(::android::Printer & printer)1227 void RefreshSystemProperties(::android::Printer& printer) {
1228 // TODO: read all properties from one config class.
1229 // PH properties do not work if they contain ".". "_" was instead used here.
1230 tracing_allowed_ = common::IsTracingEnabled(/*default_value=*/"false");
1231 s_tracing_allowed = tracing_allowed_;
1232 printer.printFormatLine("iorapd.perfetto.enable = %s", tracing_allowed_ ? "true" : "false");
1233
1234 readahead_allowed_ = common::IsReadAheadEnabled(/*default_value=*/"false");
1235 s_readahead_allowed = readahead_allowed_;
1236 printer.printFormatLine("iorapd.readahead.enable = %s", s_readahead_allowed ? "true" : "false");
1237
1238 s_min_traces =
1239 ::android::base::GetUintProperty<uint64_t>("iorapd.maintenance.min_traces", /*default*/1);
1240 uint64_t min_traces = s_min_traces;
1241 printer.printFormatLine("iorapd.maintenance.min_traces = %" PRIu64, min_traces);
1242
1243 printer.printFormatLine("iorapd.exclude_dex_files = %s",
1244 common::ExcludeDexFiles(kExcludeDexFilesDefault) ? "true" : "false");
1245
1246 package_blacklister_ = PackageBlacklister{
1247 /* Colon-separated string list of blacklisted packages, e.g.
1248 * "foo.bar.baz;com.fake.name" would blacklist {"foo.bar.baz", "com.fake.name"} packages.
1249 *
1250 * Blacklisted packages are ignored by iorapd.
1251 */
1252 server_configurable_flags::GetServerConfigurableFlag(
1253 common::ph_namespace,
1254 "iorap_blacklisted_packages",
1255 ::android::base::GetProperty("iorapd.blacklist_packages",
1256 /*default*/""))
1257 };
1258
1259 LOG(DEBUG) << "RefreshSystemProperties";
1260 }
1261
PurgePackage(::android::Printer & printer,const std::string & package_name)1262 bool PurgePackage(::android::Printer& printer, const std::string& package_name) {
1263 (void)printer;
1264 return PurgePackage(package_name);
1265 }
1266
PurgePackage(const std::string & package_name)1267 bool PurgePackage(const std::string& package_name) {
1268 db::DbHandle db{db::SchemaModel::GetSingleton()};
1269 db::CleanUpFilesForPackage(db, package_name);
1270 LOG(DEBUG) << "PurgePackage: " << package_name;
1271 return true;
1272 }
1273
CompilePackage(::android::Printer & printer,const std::string & package_name)1274 bool CompilePackage(::android::Printer& printer, const std::string& package_name) {
1275 (void)printer;
1276
1277 ScopedFormatTrace atrace_compile_app(ATRACE_TAG_PACKAGE_MANAGER,
1278 "Compile one app on device");
1279
1280 maintenance::ControllerParameters params{
1281 /*output_text*/false,
1282 /*inode_textcache*/std::nullopt,
1283 WOULD_LOG(VERBOSE),
1284 /*recompile*/false,
1285 s_min_traces,
1286 std::make_shared<maintenance::Exec>(),
1287 common::ExcludeDexFiles(kExcludeDexFilesDefault)};
1288
1289 db::DbHandle db{db::SchemaModel::GetSingleton()};
1290 bool res = maintenance::CompileSingleAppOnDevice(db, std::move(params), package_name);
1291 LOG(DEBUG) << "CompilePackage: " << package_name;
1292
1293 return res;
1294 }
1295
1296 bool readahead_allowed_{true};
1297
1298 perfetto::RxProducerFactory& perfetto_factory_;
1299 bool tracing_allowed_{true};
1300
1301 PackageBlacklister package_blacklister_{};
1302
1303 std::weak_ptr<TaskResultCallbacks> callbacks_; // avoid cycles with weakptr.
1304
1305 using AppLaunchEventRefWrapper = AppLaunchEventSubject::RefWrapper;
1306 rxcpp::observable<AppLaunchEventRefWrapper> app_launch_events_;
1307 AppLaunchEventSubject app_launch_event_subject_;
1308 AppLaunchEventDefender app_launch_event_defender_;
1309
1310 rxcpp::observable<std::pair<RequestId, JobScheduledEvent>> job_scheduled_events_;
1311 JobScheduledEventSubject job_scheduled_event_subject_;
1312
1313 rxcpp::observable<RequestId> completed_requests_;
1314
1315 // regular-priority thread to handle binder callbacks.
1316 observe_on_one_worker worker_thread_;
1317 observe_on_one_worker worker_thread2_;
1318 // low priority idle-class thread for IO operations.
1319 observe_on_one_worker io_thread_;
1320 // async futures pool for async rx operations.
1321 AsyncPool async_pool_;
1322
1323 rxcpp::composite_subscription rx_lifetime_; // app launch events
1324 rxcpp::composite_subscription rx_lifetime_jobs_; // job scheduled events
1325
1326 // package version map
1327 std::shared_ptr<binder::PackageVersionMap> version_map_;
1328
1329 //INTENTIONAL_COMPILER_ERROR_HERE:
1330 // FIXME:
1331 // ok so we want to expose a 'BlockingSubscribe' or a 'Subscribe' or some kind of function
1332 // that the main thread can call. This would subscribe on all the observables we internally
1333 // have here (probably on an event-manager-dedicated thread for simplicity).
1334 //
1335 // ideally we'd just reuse the binder thread to handle the events but I'm not super sure,
1336 // maybe this already works with the identity_current_thread coordination?
1337 };
1338 using Impl = EventManager::Impl;
1339
EventManager(perfetto::RxProducerFactory & perfetto_factory)1340 EventManager::EventManager(perfetto::RxProducerFactory& perfetto_factory)
1341 : impl_(new Impl(perfetto_factory)) {}
1342
Create()1343 std::shared_ptr<EventManager> EventManager::Create() {
1344 static perfetto::PerfettoDependencies::Injector injector{
1345 perfetto::PerfettoDependencies::CreateComponent
1346 };
1347 static perfetto::RxProducerFactory producer_factory{
1348 /*borrow*/injector
1349 };
1350 return EventManager::Create(/*borrow*/producer_factory);
1351 }
1352
Create(perfetto::RxProducerFactory & perfetto_factory)1353 std::shared_ptr<EventManager> EventManager::Create(perfetto::RxProducerFactory& perfetto_factory) {
1354 std::shared_ptr<EventManager> p{new EventManager{/*borrow*/perfetto_factory}};
1355 return p;
1356 }
1357
SetTaskResultCallbacks(std::shared_ptr<TaskResultCallbacks> callbacks)1358 void EventManager::SetTaskResultCallbacks(std::shared_ptr<TaskResultCallbacks> callbacks) {
1359 return impl_->SetTaskResultCallbacks(std::move(callbacks));
1360 }
1361
Join()1362 void EventManager::Join() {
1363 return impl_->Join();
1364 }
1365
OnAppLaunchEvent(RequestId request_id,const AppLaunchEvent & event)1366 bool EventManager::OnAppLaunchEvent(RequestId request_id,
1367 const AppLaunchEvent& event) {
1368 return impl_->OnAppLaunchEvent(request_id, event);
1369 }
1370
OnDexOptEvent(RequestId request_id,const DexOptEvent & event)1371 bool EventManager::OnDexOptEvent(RequestId request_id,
1372 const DexOptEvent& event) {
1373 return impl_->OnDexOptEvent(request_id, event);
1374 }
1375
OnJobScheduledEvent(RequestId request_id,const JobScheduledEvent & event)1376 bool EventManager::OnJobScheduledEvent(RequestId request_id,
1377 const JobScheduledEvent& event) {
1378 return impl_->OnJobScheduledEvent(request_id, event);
1379 }
1380
OnPackageChanged(const android::content::pm::PackageChangeEvent & event)1381 bool EventManager::OnPackageChanged(const android::content::pm::PackageChangeEvent& event) {
1382 return impl_->OnPackageChanged(event);
1383 }
1384
Dump(::android::Printer & printer)1385 void EventManager::Dump(/*borrow*/::android::Printer& printer) {
1386 return impl_->Dump(printer);
1387 }
1388
RefreshSystemProperties(::android::Printer & printer)1389 void EventManager::RefreshSystemProperties(::android::Printer& printer) {
1390 return impl_->RefreshSystemProperties(printer);
1391 }
1392
PurgePackage(::android::Printer & printer,const std::string & package_name)1393 bool EventManager::PurgePackage(::android::Printer& printer, const std::string& package_name) {
1394 return impl_->PurgePackage(printer, package_name);
1395 }
1396
CompilePackage(::android::Printer & printer,const std::string & package_name)1397 bool EventManager::CompilePackage(::android::Printer& printer, const std::string& package_name) {
1398 return impl_->CompilePackage(printer, package_name);
1399 }
1400
1401 } // namespace iorap::manager
1402