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};