| // 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> |
| |
| #include <chrono> |
| #include <thread> |
| |
| namespace iorap::binder { |
| |
| const constexpr int64_t kTimeoutMs = 60 * 1000; // 1 min |
| const constexpr int64_t kIntervalMs = 1000; // 1 sec |
| |
| std::shared_ptr<PackageManagerRemote> PackageManagerRemote::Create() { |
| std::shared_ptr<PackageManagerRemote> package_manager = |
| std::make_shared<PackageManagerRemote>(); |
| if (package_manager->ReconnectWithTimeout(kTimeoutMs)) { |
| return package_manager; |
| } |
| return nullptr; |
| } |
| |
| android::sp<IPackageManager> PackageManagerRemote::GetPackageService() { |
| android::sp<android::IBinder> 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; |
| android::binder::Status status = InvokeRemote( |
| [this, &version_code, &package_name]() { |
| return package_service_->getVersionCodeForPackage( |
| android::String16(package_name.c_str()), /*out*/&version_code); |
| }); |
| if (status.isOk()) { |
| return version_code; |
| } else { |
| LOG(WARNING) << "Failed to get version: " |
| << status.toString8().c_str() |
| << " for " << package_name |
| << ". Retry to connect package manager service."; |
| return std::nullopt; |
| } |
| } |
| |
| std::optional<VersionMap> PackageManagerRemote::GetPackageVersionMap() { |
| VersionMap package_version_map; |
| std::optional<std::vector<std::string>> packages = GetAllPackages(); |
| if (!packages) { |
| LOG(DEBUG) << "Failed to get all packages. The package manager may be down."; |
| return std::nullopt; |
| } |
| LOG(DEBUG) << "PackageManagerRemote::GetPackageVersionMap: " |
| << packages->size() |
| << " packages are found."; |
| |
| for (const std::string& package : *packages) { |
| std::optional<int64_t> version = GetPackageVersion(package); |
| if (!version) { |
| LOG(DEBUG) << "Cannot get version for " << package |
| << "Package manager may be down"; |
| return std::nullopt; |
| } |
| package_version_map[package] = *version; |
| } |
| |
| return package_version_map; |
| } |
| |
| std::optional<std::vector<std::string>> PackageManagerRemote::GetAllPackages() { |
| std::vector<std::string> packages; |
| android::binder::Status status = InvokeRemote( |
| [this, &packages]() { |
| return package_service_->getAllPackages(/*out*/&packages); |
| }); |
| |
| if (status.isOk()) { |
| return packages; |
| } |
| |
| LOG(ERROR) << "Failed to get all packages: " << status.toString8().c_str(); |
| return std::nullopt; |
| |
| } |
| |
| bool PackageManagerRemote::ReconnectWithTimeout(int64_t timeout_ms) { |
| int64_t count = 0; |
| package_service_ = nullptr; |
| std::chrono::duration interval = std::chrono::milliseconds(1000); |
| std::chrono::duration timeout = std::chrono::milliseconds(timeout_ms); |
| |
| while (package_service_ == nullptr) { |
| LOG(WARNING) << "Reconnect to package manager service: " << ++count << " times"; |
| package_service_ = GetPackageService(); |
| std::this_thread::sleep_for(interval); |
| if (count * interval >= timeout) { |
| LOG(ERROR) << "Fail to create version map in " |
| << timeout.count() |
| << " milliseconds." |
| << " Reason: Failed to connect to package manager service." |
| << " Is system_server down?"; |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| template <typename T> |
| android::binder::Status PackageManagerRemote::InvokeRemote(T&& lambda) { |
| android::binder::Status status = |
| static_cast<android::binder::Status>(lambda()); |
| if (status.isOk()) { |
| return status; |
| } |
| |
| if (!ReconnectWithTimeout(kTimeoutMs)) { |
| return status; |
| } |
| |
| 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(ERROR) << "Cannot register package change observer. Is system_server down?"; |
| exit(1); |
| } |
| } |
| |
| 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(ERROR) << "Failed to register package manager death recipient. Is system_server down?"; |
| exit(1); |
| } |
| } |
| |
| 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 |