event_manager: Change compiled trace search strategy and
disable trace when isReadAhead.

(1) Get compiled trace file path from sqlite.
(2) If not exists, try the prebuilt path.

Measured the overhead of looking up compiled trace path in db.
It's less than 1 ms.

Bug: 140429498
Test: Make
Test: Run an app with a compiled trace and path stored in db.
Prefetching is preformed and tracing is not.
Test: atest --host -v iorapd-host-tests
Change-Id: I965bc34ba7ed578031c696967e4386495e3ef21a
diff --git a/Android.bp b/Android.bp
index 6c26045..eb8af46 100644
--- a/Android.bp
+++ b/Android.bp
@@ -61,6 +61,7 @@
     */
 
     clang: true,
+    static_libs: ["libc++fs"],
     shared_libs: ["libbase"],
 
     // build all ioraps for host.
@@ -247,6 +248,7 @@
     ],
     srcs: [
         "tests/src/compiler/*.cc",
+        "tests/src/db/*.cc",
     ],
     data: [
         "tests/src/compiler/testdata/*",
@@ -655,7 +657,6 @@
     include_dirs: [],
 
     static_libs: [
-        "libc++fs",
         "libiorap-compiler",
         "libiorap-db",
     ],
diff --git a/src/db/app_component_name.h b/src/db/app_component_name.h
index 19ab4b2..e364163 100644
--- a/src/db/app_component_name.h
+++ b/src/db/app_component_name.h
@@ -21,6 +21,16 @@
   std::string package;
   std::string activity_name;
 
+  // Turns the activity name to the fully qualified name.
+  // For example, if the activity name is ".MainActivity" and the package is
+  // foo.bar. Then the fully qualified name is foo.bar.MainActivity.
+  AppComponentName Canonicalize() const {
+    if (!activity_name.empty() && activity_name[0] == '.') {
+      return {package, package + activity_name};
+    }
+    return {package, activity_name};
+  }
+
   static bool HasAppComponentName(const std::string& s) {
     return s.find('/') != std::string::npos;
   }
diff --git a/src/db/models.h b/src/db/models.h
index 94f82da..90acfc1 100644
--- a/src/db/models.h
+++ b/src/db/models.h
@@ -766,8 +766,8 @@
     std::string query = "SELECT * FROM app_launch_histories "
                         "WHERE activity_id = ?1 AND"
                         "  temperature = 1 AND"
-                        "  trace_enabled = TRUE"
-                        "  intent_started_ns != NULL;";
+                        "  trace_enabled = TRUE AND"
+                        "  intent_started_ns IS NOT NULL;";
     DbStatement stmt = DbStatement::Prepare(db, query, activity_id);
     std::vector<AppLaunchHistoryModel> result;
 
@@ -778,6 +778,7 @@
                                       p.temperature,
                                       p.trace_enabled,
                                       p.readahead_enabled,
+                                      p.intent_started_ns,
                                       p.total_time_ns,
                                       p.report_fully_drawn_ns)) {
       result.push_back(p);
@@ -978,6 +979,28 @@
   }
 
  public:
+  static std::optional<PrefetchFileModel> SelectByPackageNameActivityName(
+      DbHandle db, const std::string& package_name, const std::string& activity_name) {
+    ScopedLockDb lock{db};
+
+    const char* sql =
+      "SELECT prefetch_files.id, prefetch_files.activity_id, prefetch_files.file_path "
+      "FROM prefetch_files "
+      "INNER JOIN activities ON activities.id = prefetch_files.activity_id "
+      "INNER JOIN packages ON packages.id = activities.package_id "
+      "WHERE packages.name = ? AND activities.name = ? ";
+
+    DbStatement stmt = DbStatement::Prepare(db, sql, package_name, activity_name);
+
+    PrefetchFileModel p{db};
+
+    if (!DbQueryBuilder::SelectOnce(stmt, p.id, p.activity_id, p.file_path)) {
+      return std::nullopt;
+    }
+
+    return p;
+  }
+
   static std::optional<PrefetchFileModel> Insert(DbHandle db,
                                                  int activity_id,
                                                  std::string file_path) {
diff --git a/src/manager/event_manager.cc b/src/manager/event_manager.cc
index f6655a6..4f700e5 100644
--- a/src/manager/event_manager.cc
+++ b/src/manager/event_manager.cc
@@ -25,10 +25,12 @@
 #include "prefetcher/read_ahead.h"
 #include "prefetcher/task_id.h"
 
+#include <android-base/chrono_utils.h>
 #include <android-base/properties.h>
 #include <rxcpp/rx.hpp>
 
 #include <atomic>
+#include <filesystem>
 #include <functional>
 #include <utils/Trace.h>
 
@@ -159,13 +161,12 @@
         const std::string& package_name = event.intent_proto->component().package_name();
         const std::string& class_name = event.intent_proto->component().class_name();
         AppComponentName component_name{package_name, class_name};
-
-        component_name_ = component_name;
+        component_name_ = component_name.Canonicalize();
 
         if (allowed_readahead_) {
           StartReadAhead(sequence_id_, component_name);
         }
-        if (allowed_tracing_) {
+        if (allowed_tracing_ && !IsReadAhead()) {
           rx_lifetime_ = StartTracing(std::move(component_name));
         }
 
@@ -212,13 +213,12 @@
           }
 
           AppComponentName component_name = AppComponentName::FromString(title);
-
-          component_name_ = component_name;
+          component_name_ = component_name.Canonicalize();
 
           if (allowed_readahead_ && !IsReadAhead()) {
             StartReadAhead(sequence_id_, component_name);
           }
-          if (allowed_tracing_ && !IsTracing()) {
+          if (allowed_tracing_ && !IsTracing() && !IsReadAhead()) {
             rx_lifetime_ = StartTracing(std::move(component_name));
           }
         } else {
@@ -271,17 +271,63 @@
     return read_ahead_task_.has_value();
   }
 
-  void StartReadAhead(size_t id, const AppComponentName& component_name) {
-    DCHECK(allowed_readahead_);
-    DCHECK(!IsReadAhead());
+  // Gets the compiled trace.
+  // If a compiled trace exists in sqlite, use that one. Otherwise, try
+  // to find a prebuilt one.
+  std::optional<std::string> GetCompiledTrace(const AppComponentName& component_name) {
+    // Firstly, try to find the compiled trace from sqlite.
+    android::base::Timer timer{};
+    db::DbHandle db{db::SchemaModel::GetSingleton()};
+    std::optional<db::PrefetchFileModel> compiled_trace =
+        db::PrefetchFileModel::SelectByPackageNameActivityName(db,
+                                                               component_name.package,
+                                                               component_name.activity_name);
 
-    // This is changed from "/data/misc/iorapd/" for testing purpose.
-    // TODO: b/139831359.
+    std::chrono::milliseconds duration_ms = timer.duration();
+    LOG(DEBUG) << "EventManager: Looking up compiled trace done in "
+               << duration_ms.count() // the count of ticks.
+               << "ms.";
+
+    if (compiled_trace) {
+      if (std::filesystem::exists(compiled_trace->file_path)) {
+        return compiled_trace->file_path;
+      } else {
+        LOG(ERROR) << "Compiled trace in sqlite doesn't exists. file_path: "
+                   << compiled_trace->file_path;
+      }
+    }
+
+    LOG(DEBUG) << "Cannot find compiled trace in sqlite for package_name: "
+               << component_name.package
+               << " activity_name: "
+               << component_name.activity_name;
+
+    // If sqlite doesn't have the compiled trace, try the prebuilt path.
     std::string file_path = "/product/iorap-trace/";
     file_path += component_name.ToMakeFileSafeEncodedPkgString();
     file_path += ".compiled_trace.pb";
 
-    prefetcher::TaskId task{id, std::move(file_path)};
+    if (std::filesystem::exists(file_path)) {
+      return file_path;
+    }
+
+    LOG(ERROR) << "Prebuilt compiled trace doesn't exists. file_path: "
+               << file_path;
+
+    return std::nullopt;
+  }
+
+  void StartReadAhead(size_t id, const AppComponentName& component_name) {
+    DCHECK(allowed_readahead_);
+    DCHECK(!IsReadAhead());
+
+    std::optional<std::string> file_path = GetCompiledTrace(component_name);
+    if (!file_path) {
+      LOG(VERBOSE) << "Cannot find a compiled trace.";
+      return;
+    }
+
+    prefetcher::TaskId task{id, *file_path};
     read_ahead_->BeginTask(task);
     // TODO: non-void return signature?
 
diff --git a/tests/src/db/app_component_name_test.cc b/tests/src/db/app_component_name_test.cc
new file mode 100644
index 0000000..2d2fa59
--- /dev/null
+++ b/tests/src/db/app_component_name_test.cc
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common/debug.h"
+#include "db/app_component_name.h"
+
+#include <gtest/gtest.h>
+
+namespace iorap::compiler {
+
+TEST(AppComponentNameTest, FullyQualifiedActivityName) {
+  db::AppComponentName component_name{"foo.bar", "foo.bar.MainActivity"};
+
+  db::AppComponentName result = component_name.Canonicalize();
+
+  EXPECT_EQ(result.package, "foo.bar");
+  EXPECT_EQ(result.activity_name, "foo.bar.MainActivity");
+}
+
+TEST(AppComponentNameTest, NotFullyQualifiedActivityName) {
+  db::AppComponentName component_name{"foo.bar", ".MainActivity"};
+
+  db::AppComponentName result = component_name.Canonicalize();
+
+  EXPECT_EQ(result.package, "foo.bar");
+  EXPECT_EQ(result.activity_name, "foo.bar.MainActivity");
+}
+}  // namespace iorap::compiler