/* * Copyright 2019 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 "SuspendControlService.h" #include "SystemSuspend.h" #include namespace android { namespace system { namespace suspend { namespace V1_0 { template binder::Status retOk(const T& value, T* ret_val) { *ret_val = value; return binder::Status::ok(); } void SuspendControlService::setSuspendService(const wp& suspend) { mSuspend = suspend; } binder::Status SuspendControlService::enableAutosuspend(bool* _aidl_return) { const auto suspendService = mSuspend.promote(); return retOk(suspendService != nullptr && suspendService->enableAutosuspend(), _aidl_return); } binder::Status SuspendControlService::registerCallback(const sp& callback, bool* _aidl_return) { if (!callback) { return retOk(false, _aidl_return); } auto l = std::lock_guard(mCallbackLock); sp cb = IInterface::asBinder(callback); // Only remote binders can be linked to death if (cb->remoteBinder() != nullptr) { if (findCb(cb) == mCallbacks.end()) { auto status = cb->linkToDeath(this); if (status != NO_ERROR) { LOG(ERROR) << __func__ << " Cannot link to death: " << status; return retOk(false, _aidl_return); } } } mCallbacks.push_back(callback); return retOk(true, _aidl_return); } binder::Status SuspendControlService::forceSuspend(bool* _aidl_return) { const auto suspendService = mSuspend.promote(); return retOk(suspendService != nullptr && suspendService->forceSuspend(), _aidl_return); } void SuspendControlService::binderDied(const wp& who) { auto l = std::lock_guard(mCallbackLock); mCallbacks.erase(findCb(who)); } void SuspendControlService::notifyWakeup(bool success) { // A callback could potentially modify mCallbacks (e.g., via registerCallback). That must not // result in a deadlock. To that end, we make a copy of mCallbacks and release mCallbackLock // before calling the copied callbacks. auto callbackLock = std::unique_lock(mCallbackLock); auto callbacksCopy = mCallbacks; callbackLock.unlock(); for (const auto& callback : callbacksCopy) { callback->notifyWakeup(success).isOk(); // ignore errors } } } // namespace V1_0 } // namespace suspend } // namespace system } // namespace android