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