Merge Android 12

Bug: 202323961
Merged-In: Ifaf3cdb2ee959482c8a9c8bd134e3fd444483aa6
Change-Id: Iba64d93248748f2894eca7f7fa881f4c3388b920
diff --git a/include/binder/job_scheduled_event.h b/include/binder/job_scheduled_event.h
index f85f39b..6b067d7 100644
--- a/include/binder/job_scheduled_event.h
+++ b/include/binder/job_scheduled_event.h
@@ -32,6 +32,8 @@
 
   Type type;
   int32_t job_id;
+  std::string package_name;
+  bool should_update_versions;
 
   enum class Sort : int32_t {
     kIdleMaintenance = 0,
@@ -42,7 +44,9 @@
   constexpr bool operator==(const JobScheduledEvent& other) const {
     return type == other.type
         && job_id == other.job_id
-        && sort == other.sort;
+        && sort == other.sort
+        && package_name == other.package_name
+        && should_update_versions == other.should_update_versions;
   }
 
   constexpr bool operator!=(const JobScheduledEvent& other) const {
@@ -50,7 +54,8 @@
   }
 };
 
-IORAP_INTROSPECT_ADAPT_STRUCT(JobScheduledEvent, type, job_id, sort);
+IORAP_INTROSPECT_ADAPT_STRUCT(
+    JobScheduledEvent, type, job_id, sort, package_name, should_update_versions);
 
 }
 }
diff --git a/src/common/introspection.h b/src/common/introspection.h
index 8aa1ae5..af64a20 100644
--- a/src/common/introspection.h
+++ b/src/common/introspection.h
@@ -182,7 +182,26 @@
     ); \
   }
 
+#define IORAP_INTROSPECT_ADAPT_STRUCT_IMPL_5(TYPE, m1, m2, m3, m4) \
+  static constexpr auto introspect_members(::iorap::introspect::type<TYPE>) { \
+    return std::make_tuple(::iorap::introspect::member_type<&TYPE::m1>{},\
+                           ::iorap::introspect::member_type<&TYPE::m2>{},\
+                           ::iorap::introspect::member_type<&TYPE::m3>{},\
+                           ::iorap::introspect::member_type<&TYPE::m4>{}\
+    ); \
+  }
+
+#define IORAP_INTROSPECT_ADAPT_STRUCT_IMPL_6(TYPE, m1, m2, m3, m4, m5) \
+  static constexpr auto introspect_members(::iorap::introspect::type<TYPE>) { \
+    return std::make_tuple(::iorap::introspect::member_type<&TYPE::m1>{},\
+                           ::iorap::introspect::member_type<&TYPE::m2>{},\
+                           ::iorap::introspect::member_type<&TYPE::m3>{},\
+                           ::iorap::introspect::member_type<&TYPE::m4>{},\
+                           ::iorap::introspect::member_type<&TYPE::m5>{}\
+    ); \
+  }
+
 // TODO: Consider using IORAP_PP_MAP
 
 
-#endif  // IORAP_COMMON_INTROSPECTION_H
\ No newline at end of file
+#endif  // IORAP_COMMON_INTROSPECTION_H
diff --git a/src/compiler/compiler.cc b/src/compiler/compiler.cc
index 7d0e624..a546c5c 100644
--- a/src/compiler/compiler.cc
+++ b/src/compiler/compiler.cc
@@ -60,6 +60,11 @@
    * It's used to truncate the trace file.
    */
   uint64_t timestamp_limit_ns;
+  /*
+   * The pid of the app.
+   * If positive, it's used to filter out other page cache events.
+   */
+  int32_t pid;
 };
 
 struct PerfettoTracePtrInfo {
@@ -70,6 +75,11 @@
    * It's used to truncate the trace file.
    */
   uint64_t timestamp_limit_ns;
+  /*
+   * The pid of the app.
+   * If positive, it's used to filter out other page cache events.
+   */
+  int32_t pid;
 };
 
 // Attempt to read protobufs from the filenames.
@@ -86,14 +96,15 @@
     .map([](const CompilationInput& file_info) ->
          std::optional<PerfettoTraceProtoInfo> {
       LOG(VERBOSE) << "compiler::ReadProtosFromFileNames " << file_info.filename
-                   << " TimeStampLimit "<< file_info.timestamp_limit_ns << " [begin]";
+                   << " TimeStampLimit "<< file_info.timestamp_limit_ns
+                   << " Pid " << file_info.pid << " [begin]";
       std::optional<BinaryWireProtoT> maybe_proto =
           BinaryWireProtoT::ReadFullyFromFile(file_info.filename);
       if (!maybe_proto) {
         LOG(ERROR) << "Failed to read file: " << file_info.filename;
         return std::nullopt;
       }
-      return {{std::move(maybe_proto.value()), file_info.timestamp_limit_ns}};
+      return {{std::move(maybe_proto.value()), file_info.timestamp_limit_ns, file_info.pid}};
     })
     .filter([](const std::optional<PerfettoTraceProtoInfo>& proto_info) {
       return proto_info.has_value();
@@ -109,7 +120,7 @@
         LOG(ERROR) << "Failed to parse protobuf: ";  // TODO: filename.
         return std::nullopt;
       }
-      return {{std::move(t.value()), proto_info.timestamp_limit_ns}};
+      return {{std::move(t.value()), proto_info.timestamp_limit_ns, proto_info.pid}};
     })
     .filter([](const std::optional<PerfettoTracePtrInfo>& trace_info) {
       return trace_info.has_value();
@@ -291,7 +302,9 @@
   constexpr bool kDebugFunction = true;
 
   return rxcpp::observable<>::create<PageCacheFtraceEvent>(
-      [trace=std::move(trace), timestamp_limit_ns=trace_info.timestamp_limit_ns]
+      [trace=std::move(trace),
+      timestamp_limit_ns=trace_info.timestamp_limit_ns,
+      app_pid=trace_info.pid]
       (rxcpp::subscriber<PageCacheFtraceEvent> sub) {
     uint64_t timestamp = 0;
     uint64_t timestamp_relative = 0;
@@ -347,6 +360,12 @@
             return;
           }
 
+          if (app_pid >= 0 &&
+              (!event.has_pid() ||
+               event.pid() != static_cast<uint32_t>(app_pid))) {
+            continue;
+          }
+
           if (event.has_timestamp()) {
             timestamp = event.timestamp();
             if(timestamp > timestamp_limit_ns) {
@@ -821,7 +840,8 @@
 /** Makes a vector of info that includes filename and timestamp limit. */
 std::vector<CompilationInput> MakeCompilationInputs(
     std::vector<std::string> input_file_names,
-    std::vector<uint64_t> timestamp_limit_ns){
+    std::vector<uint64_t> timestamp_limit_ns,
+    std::vector<int32_t> pids){
   // If the timestamp limit is empty, set the limit to max value
   // for each trace file.
   if (timestamp_limit_ns.empty()) {
@@ -829,10 +849,18 @@
       timestamp_limit_ns.push_back(std::numeric_limits<uint64_t>::max());
     }
   }
+
+  // If the pids is empty, set all of them to -1. Because negative pid means any.
+  if (pids.empty()) {
+    for (size_t i = 0; i < input_file_names.size(); i++) {
+      pids.push_back(-1);
+    }
+  }
+
   DCHECK_EQ(input_file_names.size(), timestamp_limit_ns.size());
   std::vector<CompilationInput> file_infos;
   for (size_t i = 0; i < input_file_names.size(); i++) {
-    file_infos.push_back({input_file_names[i], timestamp_limit_ns[i]});
+    file_infos.push_back({input_file_names[i], timestamp_limit_ns[i], pids[i]});
   }
   return file_infos;
 }
@@ -908,15 +936,30 @@
       }
       int kPageSize = 4096;  // TODO: don't hardcode the page size.
 
-      // Add TraceFileEntry.
-      DCHECK(trace_file_proto->mutable_list() != nullptr);
-      serialize::proto::TraceFileEntry* entry = trace_file_proto->mutable_list()->add_entries();
-      DCHECK(entry != nullptr);
+      int entry_size = trace_file_proto->list().entries_size();
+      bool merged = false;
+      if (entry_size > 0) {
+        serialize::proto::TraceFileEntry* entry =
+            trace_file_proto->mutable_list()->mutable_entries(entry_size-1);
+        if (entry->index_id() == file_handle &&
+            entry->file_offset() + entry->file_length() ==
+            static_cast<int64_t>(event.index) * kPageSize) {
+          entry->set_file_length(entry->file_length() + kPageSize);
+          merged = true;
+        }
+      }
 
-      entry->set_index_id(file_handle);
-      // Page index -> file offset in bytes.
-      entry->set_file_offset(static_cast<int64_t>(event.index) * kPageSize);
-      entry->set_file_length(kPageSize);
+      if (!merged) {
+        // Add TraceFileEntry.
+        DCHECK(trace_file_proto->mutable_list() != nullptr);
+        serialize::proto::TraceFileEntry* entry = trace_file_proto->mutable_list()->add_entries();
+        DCHECK(entry != nullptr);
+
+        entry->set_index_id(file_handle);
+        // Page index -> file offset in bytes.
+        entry->set_file_offset(static_cast<int64_t>(event.index) * kPageSize);
+        entry->set_file_length(kPageSize);
+      }
     })
     .subscribe([&](CompilerPageCacheEvent event) {
       if (!output_proto) {
diff --git a/src/compiler/compiler.h b/src/compiler/compiler.h
index 1fa9ff1..243ab36 100644
--- a/src/compiler/compiler.h
+++ b/src/compiler/compiler.h
@@ -30,6 +30,12 @@
    * It's used to truncate the trace file.
    */
   uint64_t timestamp_limit_ns;
+
+  /*
+   * The pid of the app.
+   * If positive, it's used to filter out other page cache events.
+   */
+  int32_t pid;
 };
 
 // Compile one or more perfetto TracePacket protobufs that are stored on the filesystem
@@ -59,7 +65,8 @@
 // If timestamp_limit_ns is empty, will use the max uint64_t.
 std::vector<CompilationInput> MakeCompilationInputs(
     std::vector<std::string> input_file_names,
-    std::vector<uint64_t> timestamp_limit_ns);
+    std::vector<uint64_t> timestamp_limit_ns,
+    std::vector<int32_t> pids);
 }
 
 #endif  // IORAP_SRC_COMPILER_COMPILER_H_
diff --git a/src/compiler/main.cc b/src/compiler/main.cc
index 4b47232..3036936 100644
--- a/src/compiler/main.cc
+++ b/src/compiler/main.cc
@@ -29,6 +29,37 @@
 
 namespace iorap::compiler {
 
+// Log everything to stderr.
+// Log errors and higher to logd.
+class StderrAndLogdErrorLogger {
+ public:
+  explicit StderrAndLogdErrorLogger(android::base::LogId default_log_id = android::base::MAIN)
+#ifdef __ANDROID__
+      : logd_(default_log_id)
+#endif
+  {
+  }
+
+  void operator()(::android::base::LogId id,
+                  ::android::base::LogSeverity sev,
+                  const char* tag,
+                  const char* file,
+                  unsigned int line,
+                  const char* message) {
+#ifdef __ANDROID__
+    if (static_cast<int>(sev) >= static_cast<int>(::android::base::ERROR)) {
+      logd_(id, sev, tag, file, line, message);
+    }
+#endif
+    StderrLogger(id, sev, tag, file, line, message);
+  }
+
+ private:
+#ifdef __ANDROID__
+  ::android::base::LogdLogger logd_;
+#endif
+};
+
 void Usage(char** argv) {
   std::cerr << "Usage: " << argv[0] << " [--output-proto=output.pb] input1.pb [input2.pb ...]" << std::endl;
   std::cerr << "" << std::endl;
@@ -45,6 +76,7 @@
   std::cerr << "    --inode-textcache $,-it $  Resolve inode->filename from textcache (disables diskscan)." << std::endl;
   std::cerr << "    --verbose,-v               Set verbosity (default off)." << std::endl;
   std::cerr << "    --wait,-w                  Wait for key stroke before continuing (default off)." << std::endl;
+  std::cerr << "    --pid,-p                   Set the pid for the compiled trace" << std::endl;
   std::cerr << "    --timestamp_limit_ns,-tl   Set the limit timestamp in nanoseconds for the compiled trace. "
                                               "The order and size of the timestamp should match that of "
                                               "the input trace files. If not specified at all, All of"
@@ -54,7 +86,7 @@
 
 int Main(int argc, char** argv) {
   android::base::InitLogging(argv);
-  android::base::SetLogger(android::base::StderrLogger);
+  android::base::SetLogger(StderrAndLogdErrorLogger{});
 
   bool wait_for_keystroke = false;
   bool enable_verbose = false;
@@ -65,6 +97,7 @@
   std::optional<std::string> arg_inode_textcache;
 
   std::vector<uint64_t> timestamp_limit_ns;
+  std::vector<int32_t> pids;
 
   if (argc == 1) {
     // Need at least 1 input file to do anything.
@@ -108,6 +141,18 @@
       enable_verbose = true;
     } else if (argstr == "--wait" || argstr == "-w") {
       wait_for_keystroke = true;
+    } else if (argstr == "--pid" || argstr == "-p") {
+      if (!has_arg_next) {
+        std::cerr << "Missing --pid <value>" << std::endl;
+        return 1;
+      }
+      int32_t pid;
+      if (!::android::base::ParseInt<int32_t>(arg_next, &pid)) {
+        std::cerr << "Invalid --pid "<< arg_next << std::endl;
+        return 1;
+      }
+      pids.push_back(pid);
+      ++arg;
     } else if (argstr == "--timestamp_limit_ns" || argstr == "-tl") {
       if (!has_arg_next) {
         std::cerr << "Missing --timestamp_limit_ns <value>" << std::endl;
@@ -132,6 +177,11 @@
     return 1;
   }
 
+  if (!pids.empty() && pids.size() != arg_input_filenames.size()) {
+    std::cerr << "The size of pids doesn't match the size of input files."
+              << std::endl;
+    return 1;
+  }
   if (enable_verbose) {
     android::base::SetMinimumLogSeverity(android::base::VERBOSE);
 
@@ -183,7 +233,7 @@
 
   int return_code = 0;
   std::vector<CompilationInput> perfetto_traces =
-      MakeCompilationInputs(arg_input_filenames, timestamp_limit_ns);
+      MakeCompilationInputs(arg_input_filenames, timestamp_limit_ns, pids);
   return_code =
       !PerformCompilation(std::move(perfetto_traces),
                           std::move(arg_output_proto),
diff --git a/src/db/file_models.cc b/src/db/file_models.cc
index 0fe6d8f..d962d49 100644
--- a/src/db/file_models.cc
+++ b/src/db/file_models.cc
@@ -30,7 +30,7 @@
 
 static constexpr const char* kRootPathProp = "iorapd.root.dir";
 static const unsigned int kPerfettoMaxTraces =
-    ::android::base::GetUintProperty("iorapd.perfetto.max_traces", /*default*/10u);
+    ::android::base::GetUintProperty("iorapd.perfetto.max_traces", /*default*/2u);
 
 static uint64_t GetTimeNanoseconds() {
   struct timespec now;
@@ -132,6 +132,19 @@
   return ss.str();
 }
 
+bool PerfettoTraceFileModel::NeedMorePerfettoTraces(DbHandle& db,
+                                                    VersionedComponentName vcn) {
+  std::vector<RawTraceModel> raw_traces =
+      RawTraceModel::SelectByVersionedComponentName(db, vcn);
+
+  size_t raw_traces_size = raw_traces.size();
+  LOG(VERBOSE) << "The number of perfetto traces is "
+               << raw_traces_size
+               << " The cap is "
+               << kPerfettoMaxTraces ;
+  return raw_traces_size < kPerfettoMaxTraces;
+}
+
 void PerfettoTraceFileModel::DeleteOlderFiles(DbHandle& db, VersionedComponentName vcn) {
   std::vector<RawTraceModel> raw_traces =
       RawTraceModel::SelectByVersionedComponentName(db, vcn);
diff --git a/src/db/file_models.h b/src/db/file_models.h
index 135c98a..984c206 100644
--- a/src/db/file_models.h
+++ b/src/db/file_models.h
@@ -99,6 +99,7 @@
  public:
   static PerfettoTraceFileModel CalculateNewestFilePath(VersionedComponentName vcn);
   static void DeleteOlderFiles(DbHandle& db, VersionedComponentName vcn);
+  static bool NeedMorePerfettoTraces(DbHandle& db, VersionedComponentName vcn);
 
   virtual ~PerfettoTraceFileModel() {}
  private:
diff --git a/src/db/models.h b/src/db/models.h
index df6beb6..79823fd 100644
--- a/src/db/models.h
+++ b/src/db/models.h
@@ -34,7 +34,7 @@
 
 namespace iorap::db {
 
-const constexpr int kDbVersion = 2;
+const constexpr int kDbVersion = 3;
 
 struct SqliteDbDeleter {
   void operator()(sqlite3* db) {
@@ -509,6 +509,8 @@
             total_time_ns INTEGER CHECK(total_time_ns IS NULL or total_time_ns >= 0),
             -- absolute timestamp since epoch
             report_fully_drawn_ns INTEGER CHECK(report_fully_drawn_ns IS NULL or report_fully_drawn_ns >= 0),
+            -- pid of the app
+            pid INTEGER CHECK(pid IS NULL or pid >= 0),
 
             FOREIGN KEY (activity_id) REFERENCES activities (id) ON DELETE CASCADE
         );
@@ -810,7 +812,8 @@
                                     p.readahead_enabled,
                                     p.intent_started_ns,
                                     p.total_time_ns,
-                                    p.report_fully_drawn_ns)) {
+                                    p.report_fully_drawn_ns,
+                                    p.pid)) {
       return std::nullopt;
     }
 
@@ -843,7 +846,8 @@
                                       p.readahead_enabled,
                                       p.intent_started_ns,
                                       p.total_time_ns,
-                                      p.report_fully_drawn_ns)) {
+                                      p.report_fully_drawn_ns,
+                                      p.pid)) {
       result.push_back(p);
     }
     return result;
@@ -856,12 +860,13 @@
                                                      bool readahead_enabled,
                                                      std::optional<uint64_t> intent_started_ns,
                                                      std::optional<uint64_t> total_time_ns,
-                                                     std::optional<uint64_t> report_fully_drawn_ns)
+                                                     std::optional<uint64_t> report_fully_drawn_ns,
+                                                     int32_t pid)
   {
     const char* sql = "INSERT INTO app_launch_histories (activity_id, temperature, trace_enabled, "
                                                         "readahead_enabled, intent_started_ns, "
-                                                        "total_time_ns, report_fully_drawn_ns) "
-                      "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7);";
+                                                        "total_time_ns, report_fully_drawn_ns, pid) "
+                      "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8);";
 
     std::optional<int> inserted_row_id =
         DbQueryBuilder::Insert(db,
@@ -872,7 +877,8 @@
                                readahead_enabled,
                                intent_started_ns,
                                total_time_ns,
-                               report_fully_drawn_ns);
+                               report_fully_drawn_ns,
+                               pid);
     if (!inserted_row_id) {
       return std::nullopt;
     }
@@ -886,6 +892,7 @@
     p.intent_started_ns = intent_started_ns;
     p.total_time_ns = total_time_ns;
     p.report_fully_drawn_ns = report_fully_drawn_ns;
+    p.pid = pid;
 
     return p;
   }
@@ -915,6 +922,7 @@
   std::optional<uint64_t> intent_started_ns;
   std::optional<uint64_t> total_time_ns;
   std::optional<uint64_t> report_fully_drawn_ns;
+  int32_t pid;
 };
 
 inline std::ostream& operator<<(std::ostream& os, const AppLaunchHistoryModel& p) {
@@ -943,6 +951,8 @@
   } else {
     os << "(nullopt)";
   }
+  os << ",";
+  os << "pid=" << p.pid;
   os << "}";
   return os;
 }
diff --git a/src/maintenance/controller.cc b/src/maintenance/controller.cc
index 8f2013f..8929057 100644
--- a/src/maintenance/controller.cc
+++ b/src/maintenance/controller.cc
@@ -90,6 +90,7 @@
   std::vector<std::string> input_pbs;
   std::vector<uint64_t> timestamp_limit_ns;
   std::string output_proto;
+  std::vector<int32_t> pids;
   ControllerParameters controller_params;
 
   CompilerForkParameters(const std::vector<compiler::CompilationInput>& perfetto_traces,
@@ -99,6 +100,7 @@
         for (compiler::CompilationInput perfetto_trace : perfetto_traces) {
           input_pbs.push_back(perfetto_trace.filename);
           timestamp_limit_ns.push_back(perfetto_trace.timestamp_limit_ns);
+          pids.push_back(perfetto_trace.pid);
         }
   }
 };
@@ -109,6 +111,7 @@
 
     common::AppendArgsRepeatedly(argv, params.input_pbs);
     common::AppendArgsRepeatedly(argv, "--timestamp_limit_ns", params.timestamp_limit_ns);
+    common::AppendArgsRepeatedly(argv, "--pid", params.pids);
 
     if (controller_params.output_text) {
       argv.push_back("--output-text");
@@ -232,6 +235,11 @@
       continue;
     }
 
+    if (!history.pid) {
+      LOG(DEBUG) << "Missing pid for history " << history.id;
+      continue;
+    }
+
     uint64_t timestamp_limit = std::numeric_limits<uint64_t>::max();
     // Get corresponding timestamp limit.
     if (history.report_fully_drawn_ns) {
@@ -241,7 +249,7 @@
     } else {
       LOG(DEBUG) << " No timestamp exists. Using the max value.";
     }
-    perfetto_traces.push_back({raw_trace->file_path, timestamp_limit});
+    perfetto_traces.push_back({raw_trace->file_path, timestamp_limit, history.pid});
   }
   return perfetto_traces;
 }
diff --git a/src/manager/event_manager.cc b/src/manager/event_manager.cc
index 86b2f0f..0242c10 100644
--- a/src/manager/event_manager.cc
+++ b/src/manager/event_manager.cc
@@ -242,21 +242,6 @@
         } else {
           LOG(WARNING) << "Negative event timestamp: " << event.timestamp_nanos;
         }
-
-        // Optimistically start tracing if we have the activity in the intent.
-        if (!event.intent_proto->has_component()) {
-          // Can't do anything if there is no component in the proto.
-          LOG(VERBOSE) << "AppLaunchEventState#OnNewEvent: no component, can't trace";
-          break;
-        }
-
-        if (allowed_readahead_) {
-          StartReadAhead(sequence_id_, component_name);
-        }
-        if (allowed_tracing_ && !IsReadAhead()) {
-          rx_lifetime_ = StartTracing(std::move(component_name));
-        }
-
         break;
       }
       case Type::kIntentFailed:
@@ -266,9 +251,6 @@
           break;
         }
 
-        AbortTrace();
-        AbortReadAhead();
-
         if (history_id_subscriber_) {
           history_id_subscriber_->on_error(rxcpp::util::make_error_ptr(
             std::ios_base::failure("Aborting due to intent failed")));
@@ -277,7 +259,9 @@
 
         break;
       case Type::kActivityLaunched: {
-        const std::string& title = event.activity_record_proto->identifier().title();
+        // TODO add test in Android framework to verify this.
+        const std::string& title =
+            event.activity_record_proto->window_token().window_container().identifier().title();
         if (!AppComponentName::HasAppComponentName(title)) {
           // Proto comment claim this is sometimes a window title.
           // We need the actual 'package/component' here, so just ignore it if it's a title.
@@ -301,10 +285,7 @@
         AppLaunchEvent::Temperature temperature = event.temperature;
         temperature_ = temperature;
         if (temperature != AppLaunchEvent::Temperature::kCold) {
-          LOG(DEBUG) << "AppLaunchEventState#OnNewEvent aborting trace due to non-cold temperature";
-
-          AbortTrace();
-          AbortReadAhead();
+          LOG(DEBUG) << "AppLaunchEventState#OnNewEvent don't trace due to non-cold temperature";
         } else if (!IsTracing() && !IsReadAhead()) {  // and the temperature is Cold.
           // Start late trace when intent didn't have a component name
           LOG(VERBOSE) << "AppLaunchEventState#OnNewEvent need to start new trace";
@@ -336,7 +317,7 @@
         if (event.timestamp_nanos >= 0) {
            total_time_ns_ = event.timestamp_nanos;
         }
-        RecordDbLaunchHistory();
+        RecordDbLaunchHistory(event.activity_record_proto->proc_id());
         // Finish tracing and collect trace buffer.
         //
         // TODO: this happens automatically when perfetto finishes its
@@ -478,6 +459,26 @@
     DCHECK(allowed_tracing_);
     DCHECK(!IsTracing());
 
+    std::optional<int> version =
+        version_map_->GetOrQueryPackageVersion(component_name_->package);
+    if (!version) {
+      LOG(DEBUG) << "The version is NULL, maybe package manager is down.";
+      return std::nullopt;
+    }
+    db::VersionedComponentName versioned_component_name{component_name.package,
+                                                        component_name.activity_name,
+                                                        *version};
+    db::DbHandle db{db::SchemaModel::GetSingleton()};
+    {
+      ScopedFormatTrace atrace_traces_number_check(
+          ATRACE_TAG_ACTIVITY_MANAGER, "IorapNativeService::CheckPerfettoTracesNnumber");
+      // Just return if we have enough perfetto traces.
+      if (!db::PerfettoTraceFileModel::NeedMorePerfettoTraces(
+          db, versioned_component_name)) {
+        return std::nullopt;
+      }
+    }
+
     auto /*observable<PerfettoStreamCommand>*/ perfetto_commands =
       rxcpp::observable<>::just(PerfettoStreamCommand::kStartTracing)
           // wait 1x
@@ -512,16 +513,7 @@
              LOG(VERBOSE) << "StartTracing -- PerfettoTraceProto received (2)";
            });
 
-    std::optional<int> version =
-        version_map_->GetOrQueryPackageVersion(component_name_->package);
-    if (!version) {
-      LOG(DEBUG) << "The version is NULL, maybe package manager is down.";
-      return std::nullopt;
-    }
-    db::VersionedComponentName versioned_component_name{component_name.package,
-                                                        component_name.activity_name,
-                                                        *version};
-    lifetime = RxAsync::SubscribeAsync(*async_pool_,
+   lifetime = RxAsync::SubscribeAsync(*async_pool_,
         std::move(stream_via_threads),
         /*on_next*/[versioned_component_name]
         (std::tuple<PerfettoTraceProto, int> trace_tuple) {
@@ -559,13 +551,6 @@
               LOG(ERROR) << "Failed to insert raw_traces for " << file_path;
             } else {
               LOG(VERBOSE) << "Inserted into db: " << *raw_trace;
-
-              ScopedFormatTrace atrace_delete_older_files(
-                  ATRACE_TAG_ACTIVITY_MANAGER,
-                  "Delete older trace files for package");
-
-              // Ensure we don't have too many files per-app.
-              db::PerfettoTraceFileModel::DeleteOlderFiles(db, versioned_component_name);
             }
           }
         },
@@ -622,8 +607,8 @@
     // FIXME: how do we clear this vector?
   }
 
-  void RecordDbLaunchHistory() {
-    std::optional<db::AppLaunchHistoryModel> history = InsertDbLaunchHistory();
+  void RecordDbLaunchHistory(int32_t pid) {
+    std::optional<db::AppLaunchHistoryModel> history = InsertDbLaunchHistory(pid);
 
     // RecordDbLaunchHistory happens-after kIntentStarted
     if (!history_id_subscriber_.has_value()) {
@@ -648,7 +633,7 @@
     history_id_subscriber_ = std::nullopt;
   }
 
-  std::optional<db::AppLaunchHistoryModel> InsertDbLaunchHistory() {
+  std::optional<db::AppLaunchHistoryModel> InsertDbLaunchHistory(int32_t pid) {
     // TODO: deferred queue into a different lower priority thread.
     if (!component_name_ || !temperature_) {
       LOG(VERBOSE) << "Skip RecordDbLaunchHistory, no component name available.";
@@ -690,7 +675,8 @@
                                       intent_started_ns_,
                                       total_time_ns_,
                                       // ReportFullyDrawn event normally occurs after this. Need update later.
-                                      /* report_fully_drawn_ns= */ std::nullopt);
+                                      /* report_fully_drawn_ns= */ std::nullopt,
+                                      pid);
     //Repo
     if (!alh) {
       LOG(WARNING) << "Failed to insert app_launch_histories row";
@@ -744,7 +730,7 @@
       case Type::kActivityLaunchCancelled:
       case Type::kReportFullyDrawn: {  // From a terminal state, only go to kIntentStarted
         if (event.type != Type::kIntentStarted) {
-          LOG(WARNING) << "Rejecting transition from " << last_event_type_ << " to " << event.type;
+          LOG(DEBUG) << "Rejecting transition from " << last_event_type_ << " to " << event.type;
           last_event_type_ = Type::kUninitialized;
           return Result::kReject;
         } else {
@@ -760,7 +746,7 @@
           last_event_type_ = event.type;
           return Result::kAccept;
         } else {
-          LOG(WARNING) << "Overwriting transition from kIntentStarted to "
+          LOG(DEBUG) << "Overwriting transition from kIntentStarted to "
                        << event.type << " into kIntentFailed";
           last_event_type_ = Type::kIntentFailed;
 
@@ -776,7 +762,7 @@
           last_event_type_ = event.type;
           return Result::kAccept;
         } else {
-          LOG(WARNING) << "Overwriting transition from kActivityLaunched to "
+          LOG(DEBUG) << "Overwriting transition from kActivityLaunched to "
                        << event.type << " into kActivityLaunchCancelled";
           last_event_type_ = Type::kActivityLaunchCancelled;
 
@@ -792,7 +778,7 @@
           last_event_type_ = event.type;
           return Result::kAccept;
         } else {
-          LOG(WARNING) << "Rejecting transition from " << last_event_type_ << " to " << event.type;
+          LOG(DEBUG) << "Rejecting transition from " << last_event_type_ << " to " << event.type;
           last_event_type_ = Type::kUninitialized;
           return Result::kReject;
         }
@@ -1098,28 +1084,32 @@
   }
 
   // Runs the maintenance code to compile perfetto traces to compiled
-  // trace.
+  // trace for a package.
   void StartMaintenance(bool output_text,
                         std::optional<std::string> inode_textcache,
                         bool verbose,
                         bool recompile,
-                        uint64_t min_traces) {
+                        uint64_t min_traces,
+                        std::string package_name,
+                        bool should_update_versions) {
     ScopedFormatTrace atrace_bg_scope(ATRACE_TAG_PACKAGE_MANAGER,
                                       "Background Job Scope");
 
-    {
-      ScopedFormatTrace atrace_update_versions(ATRACE_TAG_PACKAGE_MANAGER,
-                                               "Update package versions map cache");
-      // Update the version map.
-      version_map_->UpdateAll();
-    }
-
     db::DbHandle db{db::SchemaModel::GetSingleton()};
-    {
-      ScopedFormatTrace atrace_cleanup_db(ATRACE_TAG_PACKAGE_MANAGER,
-                                          "Clean up obsolete data in database");
-      // Cleanup the obsolete data in the database.
-      maintenance::CleanUpDatabase(db, version_map_);
+    if (should_update_versions) {
+      {
+        ScopedFormatTrace atrace_update_versions(ATRACE_TAG_PACKAGE_MANAGER,
+                                                 "Update package versions map cache");
+        // Update the version map.
+        version_map_->UpdateAll();
+      }
+
+      {
+        ScopedFormatTrace atrace_cleanup_db(ATRACE_TAG_PACKAGE_MANAGER,
+                                            "Clean up obsolete data in database");
+        // Cleanup the obsolete data in the database.
+        maintenance::CleanUpDatabase(db, version_map_);
+      }
     }
 
     {
@@ -1136,7 +1126,7 @@
         common::ExcludeDexFiles(kExcludeDexFilesDefault)};
 
       LOG(DEBUG) << "StartMaintenance: min_traces=" << min_traces;
-      maintenance::CompileAppsOnDevice(db, params);
+      maintenance::CompileSingleAppOnDevice(db, params, package_name);
     }
   }
 
@@ -1158,11 +1148,14 @@
         LOG(VERBOSE) << "EventManager#JobScheduledEvent#tap(1) - job begins";
         this->NotifyProgress(e.first, TaskResult{TaskResult::State::kBegan});
 
+        LOG(VERBOSE) << "Compile " << std::get<1>(e).package_name;
         StartMaintenance(/*output_text=*/false,
                          /*inode_textcache=*/std::nullopt,
                          /*verbose=*/false,
                          /*recompile=*/false,
-                         s_min_traces);
+                         s_min_traces,
+                         std::get<1>(e).package_name,
+                         std::get<1>(e).should_update_versions);
 
         // TODO: probably this shouldn't be emitted until most of the usual DCHECKs
         // (for example, validate a job isn't already started, the request is not reused, etc).
diff --git a/src/prefetcher/read_ahead.cc b/src/prefetcher/read_ahead.cc
index 164f2ff..8759f32 100644
--- a/src/prefetcher/read_ahead.cc
+++ b/src/prefetcher/read_ahead.cc
@@ -65,6 +65,8 @@
 }
 
 static constexpr PrefetchStrategy kPrefetchStrategy = PrefetchStrategy::kFadvise;
+static uint64_t kMaxPrefetchBytes = ::android::base::GetUintProperty<uint64_t>(
+    "iorapd.max_prefetch_bytes", /*default*/100 * 1024 * 1024); // 100MB by default
 
 static PrefetchStrategy GetPrefetchStrategy() {
   PrefetchStrategy strat = PrefetchStrategy::kFadvise;
@@ -356,6 +358,7 @@
   LOG(DEBUG) << "ReadAhead: Opened file&headers in " << open_duration_ms.count() << "ms";
 
   size_t length_sum = 0;
+  size_t prefetch_bytes = 0;
   size_t entry_offset = 0;
   {
     ScopedFormatTrace atrace_perform_read_ahead(ATRACE_TAG_ACTIVITY_MANAGER,
@@ -378,6 +381,15 @@
       if (!PerformReadAhead(session, file_entry.index_id(), kind, file_entry.file_length(), file_entry.file_offset())) {
         // TODO: Do we need below at all? The always-on Dump already prints a % of failed entries.
         // LOG(WARNING) << "Failed readahead, bad file length/offset in entry @ " << (entry_offset - 1);
+      } else {
+        prefetch_bytes += static_cast<size_t>(file_entry.file_length());
+        if (prefetch_bytes >= kMaxPrefetchBytes) {
+          LOG(WARNING) << "The prefetching size is "
+                       << prefetch_bytes
+                       << " and it exceeds the threshold "
+                       << kMaxPrefetchBytes;
+          break;
+        }
       }
 
       length_sum += static_cast<size_t>(file_entry.file_length());
diff --git a/src/prefetcher/session.cc b/src/prefetcher/session.cc
index e998580..8a24b24 100644
--- a/src/prefetcher/session.cc
+++ b/src/prefetcher/session.cc
@@ -225,7 +225,7 @@
 
   switch (kind) {
     case ReadAheadKind::kFadvise:
-      if (posix_fadvise(entry_fd, offset, length, POSIX_FADV_WILLNEED) < 0) {
+      if (posix_fadvise(entry_fd, offset, length, POSIX_FADV_WILLNEED) != 0) {
         PLOG(ERROR) << "SessionDirect: Failed to fadvise entry " << file_name
                     << ", offset=" << offset << ", length=" << length;
         success = false;