// 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 #include #include #include namespace iorap::binder { const constexpr int64_t kTimeoutMs = 60 * 1000; // 1 min const constexpr int64_t kIntervalMs = 1000; // 1 sec std::shared_ptr PackageManagerRemote::Create() { std::shared_ptr package_manager = std::make_shared(); if (package_manager->ReconnectWithTimeout(kTimeoutMs)) { return package_manager; } return nullptr; } android::sp PackageManagerRemote::GetPackageService() { android::sp binder = android::defaultServiceManager()->getService( android::String16{"package_native"}); if (binder == nullptr) { LOG(ERROR) << "Cannot get package manager service!"; return nullptr; } return android::interface_cast(binder); } std::optional 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 PackageManagerRemote::GetPackageVersionMap() { VersionMap package_version_map; std::optional> 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 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> PackageManagerRemote::GetAllPackages() { std::vector 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 android::binder::Status PackageManagerRemote::InvokeRemote(T&& lambda) { android::binder::Status status = static_cast(lambda()); if (status.isOk()) { return status; } if (!ReconnectWithTimeout(kTimeoutMs)) { return status; } return lambda(); } void PackageManagerRemote::RegisterPackageChangeObserver( android::sp 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 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 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& /* who */) { LOG(DEBUG) << "PackageManagerDeathRecipient::binderDied try to re-register"; package_manager_->RegisterPackageChangeObserver(observer_); package_manager_-> RegisterPackageManagerDeathRecipient(this); } } // namespace iorap::package_manager