Revert "Revert "iorap: Add version support to iorap.""
This reverts commit 57fabf3f1eb6700613c97cb292ec86477a44e1f2.
Reason for revert: Add Fix on ag/10373965
Test: None
Change-Id: I6e216429e94bb17c2658063675b84949681c44e6
diff --git a/src/binder/package_manager_remote.cc b/src/binder/package_manager_remote.cc
new file mode 100644
index 0000000..da56a17
--- /dev/null
+++ b/src/binder/package_manager_remote.cc
@@ -0,0 +1,84 @@
+// Copyright (C) 2020 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 "package_manager_remote.h"
+
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+
+namespace iorap::binder {
+
+std::shared_ptr<PackageManagerRemote> PackageManagerRemote::Create() {
+ android::sp<IPackageManager> package_service = GetPackageService();
+ if (package_service == nullptr) {
+ return nullptr;
+ }
+ return std::make_shared<PackageManagerRemote>(package_service);
+}
+
+android::sp<IPackageManager> PackageManagerRemote::GetPackageService() {
+ auto binder = android::defaultServiceManager()->getService(
+ android::String16{"package_native"});
+ if (binder == nullptr) {
+ LOG(ERROR) << "Cannot get package manager service!";
+ return nullptr;
+ }
+
+ return android::interface_cast<IPackageManager>(binder);
+}
+
+std::optional<int64_t> PackageManagerRemote::GetPackageVersion(
+ const std::string& package_name) {
+ int64_t version_code;
+ auto status = package_service_->getVersionCodeForPackage(
+ android::String16(package_name.c_str()), &version_code);
+ if (!status.isOk()) {
+ LOG(WARNING) << "Failed to get version: " << status.toString8().c_str()
+ << " for " << package_name;
+ return std::nullopt;
+ }
+
+ return std::optional<int64_t>{version_code};
+}
+
+VersionMap PackageManagerRemote::GetPackageVersionMap() {
+ VersionMap package_version_map;
+
+ std::vector<std::string> packages = GetAllPackages();
+ LOG(DEBUG) << "PackageManagerRemote::GetPackageVersionMap: "
+ << packages.size()
+ << " packages are found.";
+
+ for (std::string package : packages) {
+ std::optional<int64_t> version = GetPackageVersion(package);
+ if (!version) {
+ LOG(DEBUG) << "Cannot get version for " << package;
+ continue;
+ }
+ package_version_map[package] = *version;
+ }
+
+ return package_version_map;
+}
+
+std::vector<std::string> PackageManagerRemote::GetAllPackages() {
+ CHECK(package_service_ != nullptr);
+ std::vector<std::string> packages;
+ auto status = package_service_->getAllPackages(/*out*/&packages);
+ if (!status.isOk()) {
+ LOG(ERROR) << "Failed to get all packages: " << status.toString8().c_str();
+ }
+ return packages;
+}
+} // namespace iorap::package_manager
diff --git a/src/binder/package_manager_remote.h b/src/binder/package_manager_remote.h
new file mode 100644
index 0000000..e0dd212
--- /dev/null
+++ b/src/binder/package_manager_remote.h
@@ -0,0 +1,54 @@
+// Copyright (C) 2020 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.
+
+#ifndef IORAP_SRC_PACKAGE_MANAGER_REMOTE_H_
+#define IORAP_SRC_PACKAGE_MANAGER_REMOTE_H_
+
+#include <android/content/pm/IPackageManagerNative.h>
+#include <binder/IServiceManager.h>
+
+#include <optional>
+#include <unordered_map>
+
+namespace iorap::binder {
+
+using IPackageManager = android::content::pm::IPackageManagerNative;
+// A map between package name and its version.
+using VersionMap = std::unordered_map<std::string, int64_t>;
+
+class PackageManagerRemote {
+ public:
+ static std::shared_ptr<PackageManagerRemote> Create();
+
+ PackageManagerRemote(android::sp<IPackageManager> package_service)
+ : package_service_(package_service) {}
+
+ // Gets the package version based on the package name.
+ std::optional<int64_t> GetPackageVersion(const std::string& package_name);
+
+ // Gets a map of package name and its version.
+ VersionMap GetPackageVersionMap();
+
+ private:
+ // Gets the package manager service.
+ static android::sp<IPackageManager> GetPackageService();
+
+ // Gets all package names.
+ std::vector<std::string> GetAllPackages();
+
+ android::sp<IPackageManager> package_service_;
+};
+} // namespace iorap::package_manager
+
+#endif // IORAP_SRC_PACKAGE_MANAGER_REMOTE_H_
diff --git a/src/binder/package_version_map.cc b/src/binder/package_version_map.cc
new file mode 100644
index 0000000..6f64d7b
--- /dev/null
+++ b/src/binder/package_version_map.cc
@@ -0,0 +1,66 @@
+// Copyright (C) 2020 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 "package_version_map.h"
+
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+
+namespace iorap::binder {
+
+std::shared_ptr<PackageVersionMap> PackageVersionMap::Create() {
+ std::shared_ptr<PackageManagerRemote> package_manager =
+ PackageManagerRemote::Create();
+ if (!package_manager) {
+ return nullptr;
+ }
+
+ VersionMap map = package_manager->GetPackageVersionMap();
+
+ return std::make_shared<PackageVersionMap>(package_manager, map);
+}
+
+void PackageVersionMap::Update() {
+ std::lock_guard<std::mutex> lock(mutex_);
+ size_t old_size = version_map_.size();
+ version_map_ = package_manager_->GetPackageVersionMap();
+ LOG(DEBUG) << "Update for version is done. The size is from " << old_size
+ << " to " << version_map_.size();
+}
+
+size_t PackageVersionMap::Size() { return version_map_.size(); }
+
+int64_t PackageVersionMap::GetOrQueryPackageVersion(const std::string& package_name) {
+ std::lock_guard<std::mutex> lock(mutex_);
+ VersionMap::iterator it = version_map_.find(package_name);
+
+ if (it == version_map_.end()) {
+ LOG(WARNING) << "Cannot find version for: " << package_name
+ << " in the hash table";
+ std::optional<int64_t> version =
+ package_manager_->GetPackageVersion(package_name);
+ if (version) {
+ LOG(VERBOSE) << "Find version for: " << package_name << " on the fly.";
+ version_map_[package_name] = *version;
+ return *version;
+ } else {
+ LOG(ERROR) << "Cannot find version for: " << package_name
+ << " on the fly.";
+ return -1;
+ }
+ }
+
+ return it->second;
+}
+} // namespace iorap::binder
diff --git a/src/binder/package_version_map.h b/src/binder/package_version_map.h
new file mode 100644
index 0000000..1c756a8
--- /dev/null
+++ b/src/binder/package_version_map.h
@@ -0,0 +1,70 @@
+// Copyright (C) 2020 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.
+
+#ifndef IORAP_SRC_PACKAGE_VERSION_MAP_H_
+#define IORAP_SRC_PACKAGE_VERSION_MAP_H_
+
+#include <android/content/pm/IPackageManagerNative.h>
+#include <binder/IServiceManager.h>
+
+#include <optional>
+#include <unordered_map>
+
+#include "package_manager_remote.h"
+
+namespace iorap::binder {
+
+class PackageVersionMap {
+ public:
+ static std::shared_ptr<PackageVersionMap> Create();
+
+ PackageVersionMap(std::shared_ptr<PackageManagerRemote> package_manager,
+ const VersionMap& version_map)
+ : package_manager_(package_manager),
+ version_map_(version_map) {}
+
+ void Update();
+
+ // Finds the version of the package in the hash table.
+ // -1 means the app is installed by unversioned.
+ // Empty means the app is not inside the RAM version map, maybe due to
+ // the app is newly installed.
+ std::optional<int64_t> Find(const std::string& package_name) {
+ VersionMap::iterator it = version_map_.find(package_name);
+ if (it == version_map_.end()) {
+ return std::nullopt;
+ }
+ return it->second;
+ }
+
+ size_t Size();
+
+ // Gets or queries the version for the package.
+ //
+ // The method firstly access the hash map in the RAM, which is built when
+ // iorapd starts. If the version is not in the map, it tries the query
+ // the package manager via IPC, with a cost of ~0.6ms.
+ //
+ // If no version can be found for some reason, return -1,
+ // because when an app has no version the package manager returns -1.
+ int64_t GetOrQueryPackageVersion(const std::string& package_name);
+
+ private:
+ std::shared_ptr<PackageManagerRemote> package_manager_;
+ VersionMap version_map_;
+ std::mutex mutex_;
+};
+} // namespace iorap::binder
+
+#endif // IORAP_SRC_PACKAGE_MANAGER_REMOTE_H_
diff --git a/src/db/clean_up.cc b/src/db/clean_up.cc
new file mode 100644
index 0000000..b3eba46
--- /dev/null
+++ b/src/db/clean_up.cc
@@ -0,0 +1,78 @@
+// Copyright (C) 2020 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 "db/clean_up.h"
+
+#include <android-base/file.h>
+
+#include <cstdio>
+#include <filesystem>
+#include <fstream>
+#include <iostream>
+#include <limits>
+#include <optional>
+#include <string>
+#include <vector>
+
+#include "db/file_models.h"
+#include "db/models.h"
+
+namespace iorap::db {
+
+void CleanUpFilesForActivity(const db::DbHandle& db,
+ const db::VersionedComponentName& vcn) {
+ LOG(DEBUG) << "Clean up files for activity " << vcn.GetActivity();
+ // Remove perfetto traces.
+ std::vector<db::RawTraceModel> raw_traces =
+ db::RawTraceModel::SelectByVersionedComponentName(db, vcn);
+ for (db::RawTraceModel raw_trace : raw_traces) {
+ std::string file_path = raw_trace.file_path;
+ LOG(DEBUG) << "Remove file: " << file_path;
+ std::filesystem::remove(file_path.c_str());
+ }
+
+ // Remove compiled traces.
+ std::optional<db::PrefetchFileModel> prefetch_file =
+ db::PrefetchFileModel::SelectByVersionedComponentName(db, vcn);
+
+ if (prefetch_file) {
+ std::string file_path = prefetch_file->file_path;
+ LOG(DEBUG) << "Remove file: " << file_path;
+ std::filesystem::remove(file_path.c_str());
+ }
+}
+
+void CleanUpFilesForPackage(const db::DbHandle& db,
+ int package_id,
+ const std::string& package_name,
+ int64_t version) {
+ LOG(DEBUG) << "Clean up files for package " << package_name << " with version "
+ << version;
+ std::vector<db::ActivityModel> activities =
+ db::ActivityModel::SelectByPackageId(db, package_id);
+
+ for (db::ActivityModel activity : activities) {
+ db::VersionedComponentName vcn{package_name, activity.name, version};
+ CleanUpFilesForActivity(db, vcn);
+ }
+}
+
+void CleanUpFilesForDb(const db::DbHandle& db) {
+ std::vector<db::PackageModel> packages = db::PackageModel::SelectAll(db);
+ for (db::PackageModel package : packages) {
+ CleanUpFilesForPackage(db, package.id, package.name, package.version);
+ }
+}
+
+} // namespace iorap::db
diff --git a/src/db/clean_up.h b/src/db/clean_up.h
new file mode 100644
index 0000000..82a26fd
--- /dev/null
+++ b/src/db/clean_up.h
@@ -0,0 +1,37 @@
+// Copyright (C) 2020 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.
+
+#ifndef IORAP_SRC_DB_CLEANER_H_
+#define IORAP_SRC_DB_CLEANER_H_
+
+#include <android/content/pm/IPackageManagerNative.h>
+
+#include <string>
+#include <vector>
+
+#include "binder/package_version_map.h"
+#include "db/file_models.h"
+
+namespace iorap::db {
+
+// Clean up perfetto traces and compiled traces stored in the db.
+void CleanUpFilesForDb(const db::DbHandle& db);
+
+void CleanUpFilesForPackage(const db::DbHandle& db,
+ int package_id,
+ const std::string& package_name,
+ int64_t version);
+} // namespace iorap::db
+
+#endif // IORAP_SRC_DB_CLEANER_H_
diff --git a/src/db/file_models.cc b/src/db/file_models.cc
index f47c68b..9a0c360 100644
--- a/src/db/file_models.cc
+++ b/src/db/file_models.cc
@@ -87,11 +87,7 @@
std::stringstream ss;
ss << root_path_ << "/" << vcn_.GetPackage() << "/";
- if (vcn_.GetVersion()) {
- ss << *vcn_.GetVersion();
- } else {
- ss << "none";
- }
+ ss << vcn_.GetVersion();
ss << "/";
ss << vcn_.GetActivity() << "/";
ss << SubDir();
@@ -131,9 +127,7 @@
void PerfettoTraceFileModel::DeleteOlderFiles(DbHandle& db, VersionedComponentName vcn) {
std::vector<RawTraceModel> raw_traces =
- RawTraceModel::SelectByPackageNameActivityName(db,
- vcn.GetPackage(),
- vcn.GetActivity()); // TODO: version
+ RawTraceModel::SelectByVersionedComponentName(db, vcn);
if (WOULD_LOG(VERBOSE)) {
size_t raw_traces_size = raw_traces.size();
diff --git a/src/db/file_models.h b/src/db/file_models.h
index 0a2c24f..135c98a 100644
--- a/src/db/file_models.h
+++ b/src/db/file_models.h
@@ -24,7 +24,7 @@
struct VersionedComponentName {
VersionedComponentName(std::string package,
std::string activity,
- std::optional<int> version)
+ int64_t version)
: package_{std::move(package)},
activity_{std::move(activity)},
version_{version} {
@@ -38,23 +38,18 @@
return activity_;
}
- std::optional<int> GetVersion() const {
+ int GetVersion() const {
return version_;
}
private:
std::string package_;
std::string activity_;
- std::optional<int> version_;
+ int64_t version_;
};
inline std::ostream& operator<<(std::ostream& os, const VersionedComponentName& vcn) {
- os << vcn.GetPackage() << "/" << vcn.GetActivity() << "@";
- if (vcn.GetVersion()) {
- os << "none";
- } else {
- os << *vcn.GetVersion();
- }
+ os << vcn.GetPackage() << "/" << vcn.GetActivity() << "@" << vcn.GetVersion();
return os;
}
diff --git a/src/db/main.cc b/src/db/main.cc
index 7b64756..2edd961 100644
--- a/src/db/main.cc
+++ b/src/db/main.cc
@@ -54,6 +54,8 @@
LOG(ERROR) << "SQLite error (" << iErrCode << "): " << zMsg;
}
+const constexpr int64_t kNoVersion = -1;
+
int Main(int argc, char** argv) {
// Go to system logcat + stderr when running from command line.
android::base::InitLogging(argv, iorap::common::StderrAndLogdLogger{android::base::SYSTEM});
@@ -186,7 +188,7 @@
std::optional<ActivityModel> activity =
ActivityModel::SelectOrInsert(db,
component_name.package,
- /*version*/std::nullopt,
+ kNoVersion,
component_name.activity_name);
DCHECK(activity.has_value());
LOG(DEBUG) << "Component selected/inserted: " << *activity;
@@ -204,7 +206,7 @@
std::optional<ActivityModel> activity =
ActivityModel::SelectOrInsert(db,
component_name.package,
- /*version*/std::nullopt,
+ kNoVersion,
component_name.activity_name);
DCHECK(activity.has_value());
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};
diff --git a/src/maintenance/controller.cc b/src/maintenance/controller.cc
index 818fb13..6c91ed1 100644
--- a/src/maintenance/controller.cc
+++ b/src/maintenance/controller.cc
@@ -39,7 +39,7 @@
db::CompiledTraceFileModel CalculateNewestFilePath(
const std::string& package_name,
const std::string& activity_name,
- const std::optional<int> version) {
+ int version) {
db::VersionedComponentName versioned_component_name{
package_name, activity_name, version};
@@ -195,9 +195,10 @@
int package_id,
const std::string& package_name,
const std::string& activity_name,
+ int version,
const ControllerParameters& params) {
db::CompiledTraceFileModel output_file =
- CalculateNewestFilePath(package_name, activity_name, /* version= */std::nullopt);
+ CalculateNewestFilePath(package_name, activity_name, version);
std::string file_path = output_file.FilePath();
@@ -233,6 +234,7 @@
LOG(DEBUG) << "Try to compiled package_id: " << package_id
<< " package_name: " << package_name
<< " activity_name: " << activity_name
+ << " version: " << version
<< " file_path: " << file_path
<< " verbose: " << params.verbose
<< " perfetto_traces: "
@@ -268,12 +270,16 @@
// Compiled the perfetto traces for activities in an package.
bool CompilePackage(const db::DbHandle& db,
const std::string& package_name,
+ int version,
const ControllerParameters& params) {
std::optional<db::PackageModel> package =
- db::PackageModel::SelectByName(db, package_name.c_str());
+ db::PackageModel::SelectByNameAndVersion(db, package_name.c_str(), version);
if (!package) {
- LOG(ERROR) << "Cannot find package for package_name: " << package_name;
+ LOG(ERROR) << "Cannot find package for package_name: "
+ << package_name
+ << " and version "
+ << version;
return false;
}
@@ -282,7 +288,7 @@
bool ret = true;
for (db::ActivityModel activity : activities) {
- if (!CompileActivity(db, package->id, package->name, activity.name, params)) {
+ if (!CompileActivity(db, package->id, package->name, activity.name, version, params)) {
ret = false;
}
}
@@ -294,7 +300,7 @@
std::vector<db::PackageModel> packages = db::PackageModel::SelectAll(db);
bool ret = true;
for (db::PackageModel package : packages) {
- if (!CompilePackage(db, package.name, params)) {
+ if (!CompilePackage(db, package.name, package.version, params)) {
ret = false;
}
}
@@ -310,26 +316,32 @@
bool Compile(const std::string& db_path,
const std::string& package_name,
+ int version,
const ControllerParameters& params) {
iorap::db::SchemaModel db_schema = db::SchemaModel::GetOrCreate(db_path);
db::DbHandle db{db_schema.db()};
- return CompilePackage(db, package_name, params);
+ return CompilePackage(db, package_name, version, params);
}
bool Compile(const std::string& db_path,
const std::string& package_name,
const std::string& activity_name,
+ int version,
const ControllerParameters& params) {
iorap::db::SchemaModel db_schema = db::SchemaModel::GetOrCreate(db_path);
db::DbHandle db{db_schema.db()};
std::optional<db::PackageModel> package =
- db::PackageModel::SelectByName(db, package_name.c_str());
+ db::PackageModel::SelectByNameAndVersion(db, package_name.c_str(), version);
+
if (!package) {
- LOG(ERROR) << "Cannot find package with name " << package_name;
+ LOG(ERROR) << "Cannot find package with name "
+ << package_name
+ << " and version "
+ << version;
return false;
}
- return CompileActivity(db, package->id, package_name, activity_name, params);
+ return CompileActivity(db, package->id, package_name, activity_name, version, params);
}
} // namespace iorap::maintenance
diff --git a/src/maintenance/controller.h b/src/maintenance/controller.h
index c676a52..27e40bb 100644
--- a/src/maintenance/controller.h
+++ b/src/maintenance/controller.h
@@ -82,14 +82,18 @@
bool Compile(const std::string& db_path, const ControllerParameters& params);
// Compile all activities in the package.
+// If the version is not given, an arbitrary package that has the same name is used.
bool Compile(const std::string& db_path,
const std::string& package_name,
+ int version,
const ControllerParameters& params);
// Compile trace for the activity.
+// If the version is not given, an arbitrary package has the same name is used.
bool Compile(const std::string& db_path,
const std::string& package_name,
const std::string& activity_name,
+ int version,
const ControllerParameters& params);
// Visible for testing.
bool CompileAppsOnDevice(const db::DbHandle& db, const ControllerParameters& params);
diff --git a/src/maintenance/db_cleaner.cc b/src/maintenance/db_cleaner.cc
new file mode 100644
index 0000000..8099dde
--- /dev/null
+++ b/src/maintenance/db_cleaner.cc
@@ -0,0 +1,61 @@
+// Copyright (C) 2020 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 "maintenance/db_cleaner.h"
+
+#include <android-base/file.h>
+
+#include <cstdio>
+#include <filesystem>
+#include <fstream>
+#include <iostream>
+#include <limits>
+#include <optional>
+#include <string>
+#include <vector>
+
+#include "db/clean_up.h"
+#include "db/file_models.h"
+#include "db/models.h"
+
+namespace iorap::maintenance {
+
+// Enable foreign key restriction.
+const constexpr char* kForeignKeyOnSql = "PRAGMA foreign_keys = ON;";
+
+void CleanUpDatabase(const db::DbHandle& db,
+ std::shared_ptr<binder::PackageVersionMap> version_map) {
+ std::vector<db::PackageModel> packages = db::PackageModel::SelectAll(db);
+ // Enable cascade deletion.
+ if (!db::DbQueryBuilder::ExecuteOnce(db, kForeignKeyOnSql)) {
+ LOG(ERROR) << "Fail to turn on foreign key restraint!";
+ }
+
+ for (db::PackageModel package : packages) {
+ // Package is cleanup if it
+ // * has a null version, because each package should have version now
+ // * is not in the version map, it may be uninstalled
+ // * has an different version with the latest one
+ std::optional<int64_t> version = version_map->Find(package.name);
+ if (!version || *version != package.version) {
+ db::CleanUpFilesForPackage(db, package.id, package.name, package.version);
+ if (!package.Delete()) {
+ LOG(ERROR) << "Fail to delete package " << package.name
+ << " with version " << package.version;
+ }
+ }
+ }
+}
+
+} // namespace iorap::maintenance
diff --git a/src/maintenance/db_cleaner.h b/src/maintenance/db_cleaner.h
new file mode 100644
index 0000000..1168bd5
--- /dev/null
+++ b/src/maintenance/db_cleaner.h
@@ -0,0 +1,34 @@
+// Copyright (C) 2020 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.
+
+#ifndef IORAP_SRC_MAINTENANCE_VERSION_UPDATE_H_
+#define IORAP_SRC_MAINTENANCE_VERSION_UPDATE_H_
+
+#include <android/content/pm/IPackageManagerNative.h>
+
+#include <string>
+#include <vector>
+
+#include "binder/package_version_map.h"
+#include "db/file_models.h"
+
+namespace iorap::maintenance {
+
+// Clean up the database.
+// Remove all relevant data for old-version packages.
+void CleanUpDatabase(const db::DbHandle& db,
+ std::shared_ptr<binder::PackageVersionMap> version_map);
+} // namespace iorap::maintenance
+
+#endif // IORAP_SRC_MAINTENANCE_VERSION_UPDATE_H_
diff --git a/src/maintenance/main.cc b/src/maintenance/main.cc
index a932886..18a0f1e 100644
--- a/src/maintenance/main.cc
+++ b/src/maintenance/main.cc
@@ -35,6 +35,7 @@
std::cerr << "" << std::endl;
std::cerr << " Optional flags:" << std::endl;
std::cerr << " --package $,-p $ Package name." << std::endl;
+ std::cerr << " --version $,-ve $ Package version." << std::endl;
std::cerr << " --activity $,-a $ Activity name." << std::endl;
std::cerr << " --inode-textcache $,-it $ Resolve inode->filename from textcache." << std::endl;
std::cerr << " --help,-h Print this Usage." << std::endl;
@@ -59,6 +60,7 @@
std::vector<std::string> arg_input_filenames;
std::optional<std::string> arg_package;
+ int arg_version = -1;
std::optional<std::string> arg_activity;
std::optional<std::string> arg_inode_textcache;
bool recompile = false;
@@ -80,6 +82,18 @@
}
arg_package = arg_next;
++arg;
+ } else if (argstr == "--version" || argstr == "-ve") {
+ if (!has_arg_next) {
+ std::cerr << "Missing --version <value>" << std::endl;
+ return 1;
+ }
+ int version;
+ if (!android::base::ParseInt<int>(arg_next, &version)) {
+ std::cerr << "Invalid --version " << arg_next << std::endl;
+ return 1;
+ }
+ arg_version = version;
+ ++arg;
} else if (argstr == "--activity" || argstr == "-a") {
if (!has_arg_next) {
std::cerr << "Missing --activity <value>" << std::endl;
@@ -144,9 +158,10 @@
ret_code = !Compile(std::move(db),
std::move(*arg_package),
std::move(*arg_activity),
+ arg_version,
params);
} else if (arg_package) {
- ret_code = !Compile(std::move(db), std::move(*arg_package), params);
+ ret_code = !Compile(std::move(db), std::move(*arg_package), arg_version, params);
} else {
ret_code = !Compile(std::move(db), params);
}
diff --git a/src/manager/event_manager.cc b/src/manager/event_manager.cc
index b3655a5..e166a30 100644
--- a/src/manager/event_manager.cc
+++ b/src/manager/event_manager.cc
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include "binder/package_version_map.h"
#include "common/debug.h"
#include "common/expected.h"
#include "common/rx_async.h"
@@ -21,6 +22,7 @@
#include "db/file_models.h"
#include "db/models.h"
#include "maintenance/controller.h"
+#include "maintenance/db_cleaner.h"
#include "manager/event_manager.h"
#include "perfetto/rx_producer.h"
#include "prefetcher/read_ahead.h"
@@ -35,6 +37,8 @@
#include <atomic>
#include <filesystem>
#include <functional>
+#include <type_traits>
+#include <unordered_map>
#include <utils/Trace.h>
using rxcpp::observe_on_one_worker;
@@ -89,6 +93,8 @@
std::vector<std::string> packages_;
};
+using PackageVersionMap = std::unordered_map<std::string, int64_t>;
+
// Main logic of the #OnAppLaunchEvent scan method.
//
// All functions are called from the same thread as the event manager
@@ -135,13 +141,16 @@
borrowed<observe_on_one_worker*> io_thread_; // not null
borrowed<AsyncPool*> async_pool_; // not null
+ std::shared_ptr<binder::PackageVersionMap> version_map_;
+
explicit AppLaunchEventState(borrowed<perfetto::RxProducerFactory*> perfetto_factory,
bool allowed_readahead,
bool allowed_tracing,
PackageBlacklister package_blacklister,
borrowed<observe_on_one_worker*> thread,
borrowed<observe_on_one_worker*> io_thread,
- borrowed<AsyncPool*> async_pool)
+ borrowed<AsyncPool*> async_pool,
+ std::shared_ptr<binder::PackageVersionMap> version_map)
: read_ahead_{std::make_shared<prefetcher::ReadAhead>()}
{
perfetto_factory_ = perfetto_factory;
@@ -160,6 +169,9 @@
async_pool_ = async_pool;
DCHECK(async_pool_ != nullptr);
+
+ version_map_ = version_map;
+ DCHECK(version_map_ != nullptr);
}
// Updates the values in this struct only as a side effect.
@@ -359,10 +371,12 @@
// Firstly, try to find the compiled trace from sqlite.
android::base::Timer timer{};
db::DbHandle db{db::SchemaModel::GetSingleton()};
+ int version = version_map_->GetOrQueryPackageVersion(component_name.package);
+ db::VersionedComponentName vcn{component_name.package,
+ component_name.activity_name,
+ version};
std::optional<db::PrefetchFileModel> compiled_trace =
- db::PrefetchFileModel::SelectByPackageNameActivityName(db,
- component_name.package,
- component_name.activity_name);
+ db::PrefetchFileModel::SelectByVersionedComponentName(db, vcn);
std::chrono::milliseconds duration_ms = timer.duration();
LOG(DEBUG) << "EventManager: Looking up compiled trace done in "
@@ -471,9 +485,10 @@
LOG(VERBOSE) << "StartTracing -- PerfettoTraceProto received (2)";
});
+ int version = version_map_->GetOrQueryPackageVersion(component_name_->package);
db::VersionedComponentName versioned_component_name{component_name.package,
component_name.activity_name,
- /*version*/std::nullopt}; // TODO: version
+ version};
lifetime = RxAsync::SubscribeAsync(*async_pool_,
std::move(stream_via_threads),
/*on_next*/[versioned_component_name]
@@ -604,10 +619,11 @@
using namespace iorap::db;
+ int version = version_map_->GetOrQueryPackageVersion(component_name_->package);
std::optional<ActivityModel> activity =
ActivityModel::SelectOrInsert(db,
component_name_->package,
- /*version*/std::nullopt,
+ version,
component_name_->activity_name);
if (!activity) {
@@ -795,6 +811,14 @@
worker_thread2_(rxcpp::observe_on_new_thread()),
io_thread_(perfetto::ObserveOnNewIoThread()) {
+ android::base::Timer timer{};
+ version_map_ = binder::PackageVersionMap::Create();
+ std::chrono::milliseconds duration_ms = timer.duration();
+ LOG(ERROR) << " Got versions for "
+ << version_map_->Size()
+ <<" packages in "
+ << duration_ms.count() << "ms";
+
// TODO: read all properties from one config class.
// PH properties do not work if they contain ".". "_" was instead used here.
const char* ph_namespace = "runtime_native_boot";
@@ -877,7 +901,8 @@
package_blacklister_,
&worker_thread2_,
&io_thread_,
- &async_pool_};
+ &async_pool_,
+ version_map_};
app_launch_events_
.subscribe_on(worker_thread_)
.scan(std::move(initial_state),
@@ -900,7 +925,12 @@
bool verbose,
bool recompile,
uint64_t min_traces) {
+ // Update the version map.
+ version_map_->Update();
+ // Cleanup the obsolete data in the database.
db::DbHandle db{db::SchemaModel::GetSingleton()};
+ maintenance::CleanUpDatabase(db, version_map_);
+ // Compilation
maintenance::ControllerParameters params{
output_text,
inode_textcache,
@@ -1028,6 +1058,9 @@
rxcpp::composite_subscription rx_lifetime_; // app launch events
rxcpp::composite_subscription rx_lifetime_jobs_; // job scheduled events
+ // package version map
+ std::shared_ptr<binder::PackageVersionMap> version_map_;
+
//INTENTIONAL_COMPILER_ERROR_HERE:
// FIXME:
// ok so we want to expose a 'BlockingSubscribe' or a 'Subscribe' or some kind of function