/** * 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. */ #define LOG_TAG "carwatchdogd" #include "WatchdogServiceHelper.h" #include "ServiceManager.h" #include namespace android { namespace automotive { namespace watchdog { namespace aawi = ::android::automotive::watchdog::internal; using aawi::BnCarWatchdogServiceForSystem; using aawi::ICarWatchdogServiceForSystem; using aawi::PackageInfo; using aawi::PackageIoOveruseStats; using aawi::UserPackageIoUsageStats; using ::android::IBinder; using ::android::sp; using ::android::wp; using ::android::base::Error; using ::android::base::Result; using ::android::binder::Status; namespace { Status fromExceptionCode(int32_t exceptionCode, std::string message) { ALOGW("%s.", message.c_str()); return Status::fromExceptionCode(exceptionCode, message.c_str()); } } // namespace Result WatchdogServiceHelper::init(const sp& watchdogProcessService) { if (watchdogProcessService == nullptr) { return Error() << "Must provide a non-null watchdog process service instance"; } mWatchdogProcessService = watchdogProcessService; return mWatchdogProcessService->registerWatchdogServiceHelper(this); } WatchdogServiceHelper::~WatchdogServiceHelper() { terminate(); } Status WatchdogServiceHelper::registerService( const android::sp& service) { std::unique_lock writeLock(mRWMutex); if (mWatchdogProcessService == nullptr) { return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "Must initialize watchdog service helper before " "registering car watchdog service"); } sp curBinder = BnCarWatchdogServiceForSystem::asBinder(mService); sp newBinder = BnCarWatchdogServiceForSystem::asBinder(service); if (mService != nullptr && curBinder == newBinder) { return Status::ok(); } if (status_t ret = newBinder->linkToDeath(this); ret != OK) { return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "Failed to register car watchdog service as it is dead"); } unregisterServiceLocked(); if (Status status = mWatchdogProcessService->registerCarWatchdogService(newBinder); !status.isOk()) { newBinder->unlinkToDeath(this); return status; } mService = service; return Status::ok(); } Status WatchdogServiceHelper::unregisterService(const sp& service) { std::unique_lock writeLock(mRWMutex); if (sp binder = BnCarWatchdogServiceForSystem::asBinder(service); binder != BnCarWatchdogServiceForSystem::asBinder(mService)) { return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "Failed to unregister car watchdog service as it is not " "registered"); } unregisterServiceLocked(); return Status::ok(); } void WatchdogServiceHelper::binderDied(const wp& who) { std::unique_lock writeLock(mRWMutex); sp curBinder = BnCarWatchdogServiceForSystem::asBinder(mService); if (IBinder* diedBinder = who.unsafe_get(); curBinder == nullptr || diedBinder != curBinder) { return; } ALOGW("Car watchdog service had died."); mService.clear(); mWatchdogProcessService->unregisterCarWatchdogService(curBinder); } void WatchdogServiceHelper::terminate() { std::unique_lock writeLock(mRWMutex); unregisterServiceLocked(); mWatchdogProcessService.clear(); } Status WatchdogServiceHelper::checkIfAlive(const wp& who, int32_t sessionId, TimeoutLength timeout) const { sp service; if (std::shared_lock readLock(mRWMutex); mService == nullptr || who.unsafe_get() != BnCarWatchdogServiceForSystem::asBinder(mService)) { return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "Dropping checkIfAlive request as the given car watchdog " "service " "binder isn't registered"); } else { service = mService; } return service->checkIfAlive(sessionId, static_cast(timeout)); } Status WatchdogServiceHelper::prepareProcessTermination(const wp& who) { sp service; if (std::shared_lock readLock(mRWMutex); mService == nullptr || who.unsafe_get() != BnCarWatchdogServiceForSystem::asBinder(mService)) { return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "Dropping prepareProcessTermination request as the given " "car watchdog service binder isn't registered"); } else { service = mService; } Status status = service->prepareProcessTermination(); if (status.isOk()) { std::unique_lock writeLock(mRWMutex); /* * prepareTermination callback is called when CarWatchdogService isn't responding, which * indicates the CarWatchdogService is stuck, terminating, or restarting. * * When CarWatchdogService is terminating, it will issue an unregisterService call. * If the unregisterService is executed after the previous |readLock| is released and the * before current |writeLock| is acquired, the |mService| will be updated to null. Then it * won't match |service|. * * When CarWatchdogService is restarting, it will issue an registerService call. When the * registerService is executed between after the previous |readLock| is released and before * the current |writeLock| is acquired, the |mService| will be overwritten. This will lead * to unregistering the new CarWatchdogService. * * To avoid this race condition, check mService before proceeding with unregistering the * CarWatchdogService. */ if (mService == service) { unregisterServiceLocked(); } } return status; } void WatchdogServiceHelper::unregisterServiceLocked() { if (mService == nullptr) return; sp binder = BnCarWatchdogServiceForSystem::asBinder(mService); binder->unlinkToDeath(this); mService.clear(); mWatchdogProcessService->unregisterCarWatchdogService(binder); } Status WatchdogServiceHelper::getPackageInfosForUids( const std::vector& uids, const std::vector& vendorPackagePrefixes, std::vector* packageInfos) { sp service; if (std::shared_lock readLock(mRWMutex); mService == nullptr) { return fromExceptionCode(Status::EX_ILLEGAL_STATE, "Watchdog service is not initialized"); } else { service = mService; } /* * The expected number of vendor package prefixes is in the order of 10s. Thus the overhead of * forwarding these in each get call is very low. */ return service->getPackageInfosForUids(uids, vendorPackagePrefixes, packageInfos); } Status WatchdogServiceHelper::latestIoOveruseStats( const std::vector& packageIoOveruseStats) { sp service; if (std::shared_lock readLock(mRWMutex); mService == nullptr) { return fromExceptionCode(Status::EX_ILLEGAL_STATE, "Watchdog service is not initialized"); } else { service = mService; } return service->latestIoOveruseStats(packageIoOveruseStats); } Status WatchdogServiceHelper::resetResourceOveruseStats( const std::vector& packageNames) { sp service; if (std::shared_lock readLock(mRWMutex); mService == nullptr) { return fromExceptionCode(Status::EX_ILLEGAL_STATE, "Watchdog service is not initialized"); } else { service = mService; } return service->resetResourceOveruseStats(packageNames); } Status WatchdogServiceHelper::getTodayIoUsageStats( std::vector* userPackageIoUsageStats) { sp service; if (std::shared_lock readLock(mRWMutex); mService == nullptr) { return fromExceptionCode(Status::EX_ILLEGAL_STATE, "Watchdog service is not initialized"); } else { service = mService; } return service->getTodayIoUsageStats(userPackageIoUsageStats); } } // namespace watchdog } // namespace automotive } // namespace android