iorap: Add version support to iorap.

To avoid package query IPC overhead, when iorapd is starting, all
package version are cached (~80ms) in RAM for faster queries. If the app
in newly installed and the version is not cached, one IPC call is
made with a cost ~0.6ms and the result is cached.

The RAM versions is updated during maintenance.

Details:
common: Add version support to iorap.
manager: Add version support for perfetto trace insertion.
maintenance: Update the package versions during maintenance.
maintenance: Delete older version packages and relevant data and files.
maintenance: Add version to compilation in maintenance.
db: Add delete cascade.

Bug: 137785555
Test: Run on the device and the vesrion is shown in database after
insertion.
Change-Id: If9a2f68888d81fa7be34ef6e31a0a972f7548f3b
diff --git a/src/db/models.h b/src/db/models.h
index 90acfc1..bfe8cfc 100644
--- a/src/db/models.h
+++ b/src/db/models.h
@@ -15,8 +15,14 @@
 #ifndef IORAP_SRC_DB_MODELS_H_
 #define IORAP_SRC_DB_MODELS_H_
 
-#include <android-base/logging.h>
+#include "clean_up.h"
+#include "file_models.h"
 
+#include <android-base/logging.h>
+#include <utils/String8.h>
+
+#include <filesystem>
+#include <iostream>
 #include <optional>
 #include <ostream>
 #include <string>
@@ -28,6 +34,8 @@
 
 namespace iorap::db {
 
+const constexpr int kDbVersion = 2;
+
 struct SqliteDbDeleter {
   void operator()(sqlite3* db) {
     if (db != nullptr) {
@@ -368,16 +376,34 @@
     }
 
     sqlite3* db = nullptr;
+    bool is_deprecated = false;
     if (location != ":memory:") {
       // Try to open DB if it already exists.
       rc = sqlite3_open_v2(location.c_str(), /*out*/&db, SQLITE_OPEN_READWRITE, /*vfs*/nullptr);
 
       if (rc == SQLITE_OK) {
         LOG(INFO) << "Opened existing database at '" << location << "'";
-        return SchemaModel{DbHandle{db}, location};
+        SchemaModel schema{DbHandle{db}, location};
+        if (schema.Version() == kDbVersion) {
+          return schema;
+        } else {
+          LOG(DEBUG) << "The version is old, reinit the db."
+                     << " old version is "
+                     << schema.Version()
+                     << " and new version is "
+                     << kDbVersion;
+          CleanUpFilesForDb(schema.db());
+          is_deprecated = true;
+       }
       }
     }
 
+    if (is_deprecated) {
+      // Remove the db and recreate it.
+      // TODO: migrate to a newer version without deleting the old one.
+      std::filesystem::remove(location.c_str());
+    }
+
     // Create a new DB if one didn't exist already.
     rc = sqlite3_open(location.c_str(), /*out*/&db);
 
@@ -452,12 +478,11 @@
         CREATE TABLE schema_versions(
             version INTEGER NOT NULL
         );
-        INSERT INTO schema_versions VALUES(1);
 
         CREATE TABLE packages(
             id INTEGER NOT NULL,
             name TEXT NOT NULL,
-            version INTEGER,
+            version INTEGER NOT NULL,
 
             PRIMARY KEY(id)
         );
@@ -468,7 +493,7 @@
             package_id INTEGER NOT NULL,
 
             PRIMARY KEY(id),
-            FOREIGN KEY (package_id) REFERENCES packages (id)
+            FOREIGN KEY (package_id) REFERENCES packages (id) ON DELETE CASCADE
         );
 
         CREATE TABLE app_launch_histories(
@@ -485,7 +510,7 @@
             -- absolute timestamp since epoch
             report_fully_drawn_ns INTEGER CHECK(report_fully_drawn_ns IS NULL or report_fully_drawn_ns >= 0),
 
-            FOREIGN KEY (activity_id) REFERENCES activities (id)
+            FOREIGN KEY (activity_id) REFERENCES activities (id) ON DELETE CASCADE
         );
 
         CREATE TABLE raw_traces(
@@ -493,7 +518,7 @@
             history_id INTEGER NOT NULL,
             file_path TEXT NOT NULL,
 
-            FOREIGN KEY (history_id) REFERENCES app_launch_histories (id)
+            FOREIGN KEY (history_id) REFERENCES app_launch_histories (id) ON DELETE CASCADE
         );
 
         CREATE TABLE prefetch_files(
@@ -501,7 +526,7 @@
           activity_id INTEGER NOT NULL,
           file_path TEXT NOT NULL,
 
-          FOREIGN KEY (activity_id) REFERENCES activities (id)
+          FOREIGN KEY (activity_id) REFERENCES activities (id) ON DELETE CASCADE
         );
 )SQLC0D3";
 
@@ -515,6 +540,21 @@
     if (rc != SQLITE_OK) {
       LOG(FATAL) << "Failed to create tables: " << err_msg ? err_msg : "nullptr";
     }
+
+    const char* sql_to_insert_schema_version = R"SQLC0D3(
+      INSERT INTO schema_versions VALUES(%d)
+      )SQLC0D3";
+    rc = sqlite3_exec(db().get(),
+                      android::String8::format(sql_to_insert_schema_version,
+                                               kDbVersion),
+                      /*callback*/nullptr,
+                      /*arg*/0,
+                      /*out*/&err_msg);
+
+    if (rc != SQLITE_OK) {
+      LOG(FATAL) << "Failed to insert the schema version: "
+                 << err_msg ? err_msg : "nullptr";
+    }
   }
 
   static void ErrorLogCallback(void *pArg, int iErrCode, const char *zMsg) {
@@ -559,6 +599,23 @@
     return p;
   }
 
+  static std::optional<PackageModel> SelectByNameAndVersion(DbHandle db,
+                                                            const char* name,
+                                                            int version) {
+    ScopedLockDb lock{db};
+
+    std::string query =
+        "SELECT * FROM packages WHERE name = ?1 AND version = ?2 LIMIT 1;";
+    DbStatement stmt = DbStatement::Prepare(db, query, name, version);
+
+    PackageModel p{db};
+    if (!DbQueryBuilder::SelectOnce(stmt, p.id, p.name, p.version)) {
+      return std::nullopt;
+    }
+
+    return p;
+  }
+
   static std::vector<PackageModel> SelectAll(DbHandle db) {
     ScopedLockDb lock{db};
 
@@ -576,7 +633,7 @@
 
   static std::optional<PackageModel> Insert(DbHandle db,
                                             std::string name,
-                                            std::optional<int> version) {
+                                            int version) {
     const char* sql = "INSERT INTO packages (name, version) VALUES (?1, ?2);";
 
     std::optional<int> inserted_row_id =
@@ -593,19 +650,21 @@
     return p;
   }
 
+  bool Delete() {
+    const char* sql = "DELETE FROM packages WHERE id = ?";
+
+    return DbQueryBuilder::Delete(db(), sql, id);
+  }
+
   int id;
   std::string name;
-  std::optional<int> version;
+  int version;
 };
 
 inline std::ostream& operator<<(std::ostream& os, const PackageModel& p) {
   os << "PackageModel{id=" << p.id << ",name=" << p.name << ",";
   os << "version=";
-  if (p.version) {
-    os << *p.version;
-  } else {
-    os << "(nullopt)";
-  }
+  os << p.version;
   os << "}";
   return os;
 }
@@ -687,9 +746,11 @@
   static std::optional<ActivityModel> SelectOrInsert(
       DbHandle db,
       std::string package_name,
-      std::optional<int> package_version,
+      int package_version,
       std::string activity_name) {
-    std::optional<PackageModel> package = PackageModel::SelectByName(db, package_name.c_str());
+    std::optional<PackageModel> package = PackageModel::SelectByNameAndVersion(db,
+                                                                               package_name.c_str(),
+                                                                               package_version);
     if (!package) {
       package = PackageModel::Insert(db, package_name, package_version);
       DCHECK(package.has_value());
@@ -892,9 +953,8 @@
  public:
 
   // Return raw_traces, sorted ascending by the id.
-  static std::vector<RawTraceModel> SelectByPackageNameActivityName(DbHandle db,
-                                                                    std::string package_name,
-                                                                    std::string activity_name) {
+  static std::vector<RawTraceModel> SelectByVersionedComponentName(DbHandle db,
+                                                                   VersionedComponentName vcn) {
     ScopedLockDb lock{db};
 
     const char* sql =
@@ -903,10 +963,14 @@
       "INNER JOIN app_launch_histories ON raw_traces.history_id = app_launch_histories.id "
       "INNER JOIN activities ON activities.id = app_launch_histories.activity_id "
       "INNER JOIN packages ON packages.id = activities.package_id "
-      "WHERE packages.name = ? AND activities.name = ? "
+      "WHERE packages.name = ? AND activities.name = ? AND packages.version = ?"
       "ORDER BY raw_traces.id ASC";
 
-    DbStatement stmt = DbStatement::Prepare(db, sql, package_name, activity_name);
+    DbStatement stmt = DbStatement::Prepare(db,
+                                            sql,
+                                            vcn.GetPackage(),
+                                            vcn.GetActivity(),
+                                            vcn.GetVersion());
 
     std::vector<RawTraceModel> results;
 
@@ -979,8 +1043,9 @@
   }
 
  public:
-  static std::optional<PrefetchFileModel> SelectByPackageNameActivityName(
-      DbHandle db, const std::string& package_name, const std::string& activity_name) {
+  static std::optional<PrefetchFileModel> SelectByVersionedComponentName(
+      DbHandle db,
+      VersionedComponentName vcn) {
     ScopedLockDb lock{db};
 
     const char* sql =
@@ -988,9 +1053,13 @@
       "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 = ? ";
+      "WHERE packages.name = ? AND activities.name = ? AND packages.version = ?";
 
-    DbStatement stmt = DbStatement::Prepare(db, sql, package_name, activity_name);
+    DbStatement stmt = DbStatement::Prepare(db,
+                                            sql,
+                                            vcn.GetPackage(),
+                                            vcn.GetActivity(),
+                                            vcn.GetVersion());
 
     PrefetchFileModel p{db};