binder: Add package change observer to iorap. am: 3a8d95e073 am: e8d7a79cfb

Change-Id: I1a0ff281baa4ae98004d6ac75d9ad89ab7839564
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);