/*
* 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 <android-base/logging.h>
namespace android {
namespace system {
namespace suspend {
namespace V1_0 {
template <typename T>
binder::Status retOk(const T& value, T* ret_val) {
*ret_val = value;
return binder::Status::ok();
}
void SuspendControlService::setSuspendService(const wp<SystemSuspend>& 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<ISuspendCallback>& callback,
bool* _aidl_return) {
if (!callback) {
return retOk(false, _aidl_return);
}
auto l = std::lock_guard(mCallbackLock);
sp<IBinder> 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<IBinder>& 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