binder: Add package change observer to iorap. am: 3a8d95e073
Change-Id: I5936e95ba4464f7b4cd570e7464c647c1094ebdc
diff --git a/Android.bp b/Android.bp
index e8ef332..138ba4b 100644
--- a/Android.bp
+++ b/Android.bp
@@ -108,6 +108,7 @@
srcs: [
":iorap-aidl",
"src/binder/iiorap_impl.cc",
+ "src/binder/package_change_observer.cc",
"src/binder/package_manager_remote.cc",
"src/binder/package_version_map.cc",
],
diff --git a/src/binder/iiorap_impl.cc b/src/binder/iiorap_impl.cc
index 935ac31..088631d 100644
--- a/src/binder/iiorap_impl.cc
+++ b/src/binder/iiorap_impl.cc
@@ -102,6 +102,10 @@
};
public:
+ ~Impl() {
+ package_manager_->UnregisterPackageChangeObserver(package_change_observer_);
+ }
+
void SetTaskListener(const ::android::sp<ITaskListener>& listener) {
::android::sp<ITaskListener> old_listener = listener_;
if (old_listener != nullptr && listener != nullptr) {
@@ -201,10 +205,31 @@
service_params_.event_manager_->SetTaskResultCallbacks(
std::static_pointer_cast<manager::TaskResultCallbacks>(event_manager_callbacks_));
+
+ // Init the package change observer.
+ package_manager_ = PackageManagerRemote::Create();
+
+ if (package_manager_ == nullptr) {
+ LOG(FATAL) << "Failed to get package manager service in IIorapImpl::Impl";
+ return;
+ }
+
+ package_change_observer_ =
+ new PackageChangeObserver(service_params_.event_manager_);
+ package_manager_death_recipient_ =
+ new PackageManagerDeathRecipient(package_manager_, package_change_observer_);
+
+ package_manager_->RegisterPackageChangeObserver(package_change_observer_);
+ package_manager_->
+ RegisterPackageManagerDeathRecipient(package_manager_death_recipient_);
+
}
ServiceParams service_params_;
std::shared_ptr<EventManagerTaskCallbacks> event_manager_callbacks_;
+ android::sp<PackageChangeObserver> package_change_observer_;
+ android::sp<PackageManagerDeathRecipient> package_manager_death_recipient_;
+ std::shared_ptr<PackageManagerRemote> package_manager_;
};
using Impl = IIorapImpl::Impl;
diff --git a/src/binder/iiorap_impl.h b/src/binder/iiorap_impl.h
index 565a0c3..ae1422f 100644
--- a/src/binder/iiorap_impl.h
+++ b/src/binder/iiorap_impl.h
@@ -18,6 +18,8 @@
#define IORAP_BINDER_IIORAP_IMPL_H
#include "binder/iiorap_def.h"
+#include "binder/package_change_observer.h"
+#include "binder/package_manager_remote.h"
#include "common/macros.h"
#include "com/google/android/startop/iorap/BnIorap.h"
@@ -68,7 +70,6 @@
std::unique_ptr<Impl> impl_;
};
-
}
}
diff --git a/src/binder/package_change_observer.cc b/src/binder/package_change_observer.cc
new file mode 100644
index 0000000..1907af8
--- /dev/null
+++ b/src/binder/package_change_observer.cc
@@ -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.
+
+#include "package_change_observer.h"
+#include "package_manager_remote.h"
+#include "manager/event_manager.h"
+
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+
+namespace iorap::binder {
+
+PackageChangeObserver::PackageChangeObserver(
+ std::shared_ptr<iorap::manager::EventManager> event_manager) :
+ event_manager_(event_manager){}
+
+android::binder::Status PackageChangeObserver::onPackageChanged(
+ const android::content::pm::PackageChangeEvent& event) {
+ LOG(DEBUG) << "Received PackageChangeObserver::onPackageChanged";
+ if (event_manager_->OnPackageChanged(event)) {
+ return android::binder::Status::ok();
+ } else {
+ return android::binder::Status::fromStatusT(android::BAD_VALUE);
+ }
+}
+} // namespace iorap::binder
diff --git a/src/binder/package_change_observer.h b/src/binder/package_change_observer.h
new file mode 100644
index 0000000..ac488ac
--- /dev/null
+++ b/src/binder/package_change_observer.h
@@ -0,0 +1,42 @@
+// 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_CHANGE_OBSERVER_H_
+#define IORAP_SRC_PACKAGE_CHANGE_OBSERVER_H_
+
+#include "binder/iiorap_def.h"
+
+#include <android/content/pm/BnPackageChangeObserver.h>
+#include <android/content/pm/PackageChangeEvent.h>
+#include <android/content/pm/IPackageManagerNative.h>
+
+namespace iorap::manager {
+ class EventManager;
+};
+
+namespace iorap::binder {
+
+class PackageChangeObserver : public android::content::pm::BnPackageChangeObserver {
+ public:
+ PackageChangeObserver(std::shared_ptr<iorap::manager::EventManager> event_manager);
+
+ // Callback when the package is changed.
+ android::binder::Status onPackageChanged(
+ const ::android::content::pm::PackageChangeEvent& event) override;
+ private:
+ std::shared_ptr<iorap::manager::EventManager> event_manager_;
+};
+} // namespace iorap::binder
+
+#endif // IORAP_SRC_PACKAGE_CHANGE_OBSERVER_H_
diff --git a/src/binder/package_manager_remote.cc b/src/binder/package_manager_remote.cc
index e166e09..7cca2cf 100644
--- a/src/binder/package_manager_remote.cc
+++ b/src/binder/package_manager_remote.cc
@@ -135,4 +135,54 @@
return lambda();
}
+
+void PackageManagerRemote::RegisterPackageChangeObserver(
+ android::sp<PackageChangeObserver> observer) {
+ LOG(DEBUG) << "Register package change observer.";
+ android::binder::Status status = InvokeRemote(
+ [this, &observer]() {
+ return package_service_->registerPackageChangeObserver(observer);
+ });
+
+ if (!status.isOk()) {
+ LOG(FATAL) << "Cannot register package change observer.";
+ }
+}
+
+void PackageManagerRemote::UnregisterPackageChangeObserver(
+ android::sp<PackageChangeObserver> observer) {
+ LOG(DEBUG) << "Unregister package change observer.";
+ android::binder::Status status = InvokeRemote(
+ [this, &observer]() {
+ return package_service_->unregisterPackageChangeObserver(observer);
+ });
+
+ if (!status.isOk()) {
+ LOG(WARNING) << "Cannot unregister package change observer.";
+ }
+}
+
+void PackageManagerRemote::RegisterPackageManagerDeathRecipient(
+ android::sp<PackageManagerDeathRecipient> death_recipient) {
+ LOG(DEBUG) << "Register package manager death recipient.";
+ android::status_t status =
+ android::IInterface::asBinder(package_service_.get())->linkToDeath(death_recipient);
+
+ if (status == android::OK) {
+ return;
+ }
+
+ if (!ReconnectWithTimeout(kTimeoutMs) ||
+ android::OK != android::IInterface::asBinder(
+ package_service_.get())->linkToDeath(death_recipient)) {
+ LOG(FATAL) << "Failed to register package manager death recipient.";
+ }
+}
+
+void PackageManagerDeathRecipient::binderDied(const android::wp<android::IBinder>& /* who */) {
+ LOG(DEBUG) << "PackageManagerDeathRecipient::binderDied try to re-register";
+ package_manager_->RegisterPackageChangeObserver(observer_);
+ package_manager_->
+ RegisterPackageManagerDeathRecipient(this);
+}
} // namespace iorap::package_manager
diff --git a/src/binder/package_manager_remote.h b/src/binder/package_manager_remote.h
index 9c4e2fc..bcb333c 100644
--- a/src/binder/package_manager_remote.h
+++ b/src/binder/package_manager_remote.h
@@ -15,6 +15,8 @@
#ifndef IORAP_SRC_PACKAGE_MANAGER_REMOTE_H_
#define IORAP_SRC_PACKAGE_MANAGER_REMOTE_H_
+#include "binder/package_change_observer.h"
+
#include <android/content/pm/IPackageManagerNative.h>
#include <binder/IServiceManager.h>
@@ -27,6 +29,22 @@
// A map between package name and its version.
using VersionMap = std::unordered_map<std::string, int64_t>;
+class PackageManagerRemote;
+
+class PackageManagerDeathRecipient : public android::IBinder::DeathRecipient {
+public:
+ PackageManagerDeathRecipient(std::shared_ptr<PackageManagerRemote> package_manager,
+ android::sp<PackageChangeObserver> observer) :
+ package_manager_(package_manager), observer_(observer) {}
+ // android::IBinder::DeathRecipient override:
+ void binderDied(const android::wp<android::IBinder>& /* who */) override;
+
+private:
+ std::shared_ptr<PackageManagerRemote> package_manager_;
+
+ android::sp<PackageChangeObserver> observer_;
+};
+
class PackageManagerRemote {
public:
static std::shared_ptr<PackageManagerRemote> Create();
@@ -37,6 +55,13 @@
// Gets a map of package name and its version.
VersionMap GetPackageVersionMap();
+ void RegisterPackageChangeObserver(android::sp<PackageChangeObserver> observer);
+
+ void UnregisterPackageChangeObserver(android::sp<PackageChangeObserver> observer);
+
+ void RegisterPackageManagerDeathRecipient(
+ android::sp<PackageManagerDeathRecipient> death_recipient);
+
private:
template <typename T>
android::binder::Status InvokeRemote(T&& lambda);
diff --git a/src/binder/package_version_map.cc b/src/binder/package_version_map.cc
index 6f64d7b..5a3c446 100644
--- a/src/binder/package_version_map.cc
+++ b/src/binder/package_version_map.cc
@@ -31,7 +31,7 @@
return std::make_shared<PackageVersionMap>(package_manager, map);
}
-void PackageVersionMap::Update() {
+void PackageVersionMap::UpdateAll() {
std::lock_guard<std::mutex> lock(mutex_);
size_t old_size = version_map_.size();
version_map_ = package_manager_->GetPackageVersionMap();
@@ -39,6 +39,35 @@
<< " to " << version_map_.size();
}
+bool PackageVersionMap::Update(std::string package_name, int64_t version) {
+ std::lock_guard<std::mutex> lock(mutex_);
+
+ VersionMap::iterator it = version_map_.find(package_name);
+ if (it == version_map_.end()) {
+ LOG(DEBUG) << "New installed package "
+ << package_name
+ << " with version "
+ << version;
+ version_map_[package_name] = version;
+ return true;
+ }
+
+ if (it->second != version) {
+ LOG(DEBUG) << "New version package "
+ << package_name
+ << " with version "
+ << version;
+ version_map_[package_name] = version;
+ return true;
+ }
+
+ LOG(DEBUG) << "Same version package "
+ << package_name
+ << " with version "
+ << version;
+ return false;
+}
+
size_t PackageVersionMap::Size() { return version_map_.size(); }
int64_t PackageVersionMap::GetOrQueryPackageVersion(const std::string& package_name) {
diff --git a/src/binder/package_version_map.h b/src/binder/package_version_map.h
index 1c756a8..d90e94c 100644
--- a/src/binder/package_version_map.h
+++ b/src/binder/package_version_map.h
@@ -34,7 +34,16 @@
: package_manager_(package_manager),
version_map_(version_map) {}
- void Update();
+ // Updates the version specified by 'package_name' to 'version'.
+ //
+ // Post-condition: Find(package_name) == version.
+ // * if the package is newly installed, insert and return true.
+ // * if the package version is changed, update the version to the
+ // given one and return true.
+ // * otherwise, return false.
+ bool Update(std::string package_name, int64_t version);
+
+ void UpdateAll();
// Finds the version of the package in the hash table.
// -1 means the app is installed by unversioned.
diff --git a/src/db/clean_up.cc b/src/db/clean_up.cc
index 49f1657..de1412d 100644
--- a/src/db/clean_up.cc
+++ b/src/db/clean_up.cc
@@ -70,6 +70,20 @@
}
}
+void CleanUpFilesForPackage(const db::DbHandle& db,
+ const std::string& package_name,
+ int64_t version) {
+ std::optional<PackageModel> package =
+ PackageModel::SelectByNameAndVersion(db, package_name.c_str(), version);
+
+ if (!package) {
+ LOG(DEBUG) << "No package to clean up " << package_name << " with version " << version;
+ return;
+ }
+
+ CleanUpFilesForPackage(db, package->id, package_name, version);
+}
+
void CleanUpFilesForDb(const db::DbHandle& db) {
std::vector<db::PackageModel> packages = db::PackageModel::SelectAll(db);
for (db::PackageModel package : packages) {
diff --git a/src/db/clean_up.h b/src/db/clean_up.h
index 93ef9c4..08b7bde 100644
--- a/src/db/clean_up.h
+++ b/src/db/clean_up.h
@@ -25,9 +25,12 @@
namespace iorap::db {
-// Clean up perfetto traces and compiled traces stored in the db.
+// Clean up perfetto traces and compiled traces in disk and rows
+// in raw_traces and prefetch_files in the db.
void CleanUpFilesForDb(const db::DbHandle& db);
+// Clean up perfetto traces and compiled traces in disk and rows
+// in raw_traces and prefetch_files in the db for a package id.
void CleanUpFilesForPackage(const db::DbHandle& db,
int package_id,
const std::string& package_name,
@@ -40,6 +43,12 @@
// Clean up all package rows (and files) associated with a package by name.
void CleanUpFilesForPackage(const db::DbHandle& db,
const std::string& package_name);
+// Clean up perfetto traces and compiled traces in disk and rows
+// in raw_traces and prefetch_files in the db for a package name
+// and version.
+void CleanUpFilesForPackage(const db::DbHandle& db,
+ const std::string& package_name,
+ int64_t version);
} // namespace iorap::db
#endif // IORAP_SRC_DB_CLEANER_H_
diff --git a/src/manager/event_manager.cc b/src/manager/event_manager.cc
index 749caa6..1f0ea13 100644
--- a/src/manager/event_manager.cc
+++ b/src/manager/event_manager.cc
@@ -897,6 +897,15 @@
std::optional<rxcpp::subscriber<std::pair<RequestId, JobScheduledEvent>>> subscriber_;
};
+std::ostream& operator<<(std::ostream& os, const android::content::pm::PackageChangeEvent& event) {
+ os << "PackageChangeEvent{";
+ os << "packageName=" << event.packageName << ",";
+ os << "version=" << event.version << ",";
+ os << "lastUpdateTimeMillis=" << event.lastUpdateTimeMillis;
+ os << "}";
+ return os;
+}
+
class EventManager::Impl {
public:
Impl(/*borrow*/perfetto::RxProducerFactory& perfetto_factory)
@@ -996,6 +1005,25 @@
return true; // No errors.
}
+ bool OnPackageChanged(const android::content::pm::PackageChangeEvent& event) {
+ LOG(DEBUG) << "Received " << event;
+ if (event.isDeleted) {
+ // Do nothing if the package is deleted rignt now.
+ // The package will be removed from db during maintenance.
+ return true;
+ }
+ // Update the version map.
+ if (version_map_->Update(event.packageName, event.version)) {
+ return true;
+ }
+
+ // Sometimes a package is updated without any version change.
+ // Clean it up in this case.
+ db::DbHandle db{db::SchemaModel::GetSingleton()};
+ db::CleanUpFilesForPackage(db, event.packageName, event.version);
+ return true;
+ }
+
void Dump(/*borrow*/::android::Printer& printer) {
::iorap::prefetcher::ReadAhead::Dump(printer);
::iorap::perfetto::PerfettoConsumerImpl::Dump(/*borrow*/printer);
@@ -1056,7 +1084,7 @@
ScopedFormatTrace atrace_update_versions(ATRACE_TAG_PACKAGE_MANAGER,
"Update package versions map cache");
// Update the version map.
- version_map_->Update();
+ version_map_->UpdateAll();
}
db::DbHandle db{db::SchemaModel::GetSingleton()};
@@ -1250,6 +1278,10 @@
return impl_->OnJobScheduledEvent(request_id, event);
}
+bool EventManager::OnPackageChanged(const android::content::pm::PackageChangeEvent& event) {
+ return impl_->OnPackageChanged(event);
+}
+
void EventManager::Dump(/*borrow*/::android::Printer& printer) {
return impl_->Dump(printer);
}
diff --git a/src/manager/event_manager.h b/src/manager/event_manager.h
index 328d4d9..2a40191 100644
--- a/src/manager/event_manager.h
+++ b/src/manager/event_manager.h
@@ -22,6 +22,8 @@
#include "binder/request_id.h"
#include "binder/task_result.h"
+#include <android/content/pm/PackageChangeEvent.h>
+
#include <memory>
namespace android {
@@ -78,6 +80,11 @@
bool OnJobScheduledEvent(binder::RequestId request_id,
const binder::JobScheduledEvent& event);
+ // Handles a PackageChangeEvent:
+ //
+ // * The package manager service send this event for package install
+ // update or delete.
+ bool OnPackageChanged(const android::content::pm::PackageChangeEvent& event);
// Print to adb shell dumpsys (for bugreport info).
void Dump(/*borrow*/::android::Printer& printer);