1*79330504STreehugger Robot /*
2*79330504STreehugger Robot * Copyright (C) 2018 The Android Open Source Project
3*79330504STreehugger Robot *
4*79330504STreehugger Robot * Licensed under the Apache License, Version 2.0 (the "License");
5*79330504STreehugger Robot * you may not use this file except in compliance with the License.
6*79330504STreehugger Robot * You may obtain a copy of the License at
7*79330504STreehugger Robot *
8*79330504STreehugger Robot * http://www.apache.org/licenses/LICENSE-2.0
9*79330504STreehugger Robot *
10*79330504STreehugger Robot * Unless required by applicable law or agreed to in writing, software
11*79330504STreehugger Robot * distributed under the License is distributed on an "AS IS" BASIS,
12*79330504STreehugger Robot * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*79330504STreehugger Robot * See the License for the specific language governing permissions and
14*79330504STreehugger Robot * limitations under the License.
15*79330504STreehugger Robot */
16*79330504STreehugger Robot
17*79330504STreehugger Robot #define LOG_TAG "power"
18*79330504STreehugger Robot #define ATRACE_TAG ATRACE_TAG_POWER
19*79330504STreehugger Robot
20*79330504STreehugger Robot #include <hardware_legacy/power.h>
21*79330504STreehugger Robot #include <wakelock/wakelock.h>
22*79330504STreehugger Robot
23*79330504STreehugger Robot #include <aidl/android/system/suspend/ISystemSuspend.h>
24*79330504STreehugger Robot #include <aidl/android/system/suspend/IWakeLock.h>
25*79330504STreehugger Robot #include <android/binder_manager.h>
26*79330504STreehugger Robot #include <android-base/logging.h>
27*79330504STreehugger Robot #include <utils/Trace.h>
28*79330504STreehugger Robot
29*79330504STreehugger Robot #include <mutex>
30*79330504STreehugger Robot #include <string>
31*79330504STreehugger Robot #include <thread>
32*79330504STreehugger Robot #include <unordered_map>
33*79330504STreehugger Robot
34*79330504STreehugger Robot using aidl::android::system::suspend::ISystemSuspend;
35*79330504STreehugger Robot using aidl::android::system::suspend::IWakeLock;
36*79330504STreehugger Robot using aidl::android::system::suspend::WakeLockType;
37*79330504STreehugger Robot
38*79330504STreehugger Robot static std::mutex gLock;
39*79330504STreehugger Robot static std::unordered_map<std::string, std::shared_ptr<IWakeLock>> gWakeLockMap;
40*79330504STreehugger Robot
getSystemSuspendServiceOnce()41*79330504STreehugger Robot static const std::shared_ptr<ISystemSuspend> getSystemSuspendServiceOnce() {
42*79330504STreehugger Robot static std::shared_ptr<ISystemSuspend> suspendService =
43*79330504STreehugger Robot []() -> std::shared_ptr<ISystemSuspend> {
44*79330504STreehugger Robot std::string suspendServiceName =
45*79330504STreehugger Robot ISystemSuspend::descriptor + std::string("/default");
46*79330504STreehugger Robot if (!AServiceManager_isDeclared(suspendServiceName.c_str())) {
47*79330504STreehugger Robot return nullptr;
48*79330504STreehugger Robot }
49*79330504STreehugger Robot return ISystemSuspend::fromBinder(ndk::SpAIBinder(
50*79330504STreehugger Robot AServiceManager_waitForService(suspendServiceName.c_str())));
51*79330504STreehugger Robot }();
52*79330504STreehugger Robot return suspendService;
53*79330504STreehugger Robot }
54*79330504STreehugger Robot
acquire_wake_lock(int,const char * id)55*79330504STreehugger Robot int acquire_wake_lock(int, const char* id) {
56*79330504STreehugger Robot ATRACE_CALL();
57*79330504STreehugger Robot const auto suspendService = getSystemSuspendServiceOnce();
58*79330504STreehugger Robot if (!suspendService) {
59*79330504STreehugger Robot LOG(ERROR) << "Failed to get SystemSuspend service";
60*79330504STreehugger Robot return -1;
61*79330504STreehugger Robot }
62*79330504STreehugger Robot
63*79330504STreehugger Robot #ifdef ENABLE_NO_LOCK_BINDER_TXN
64*79330504STreehugger Robot bool hasLock;
65*79330504STreehugger Robot {
66*79330504STreehugger Robot std::lock_guard<std::mutex> l{gLock};
67*79330504STreehugger Robot hasLock = !!gWakeLockMap[id];
68*79330504STreehugger Robot }
69*79330504STreehugger Robot if (hasLock)
70*79330504STreehugger Robot return 0;
71*79330504STreehugger Robot
72*79330504STreehugger Robot std::shared_ptr<IWakeLock> wl = nullptr;
73*79330504STreehugger Robot auto status =
74*79330504STreehugger Robot suspendService->acquireWakeLock(WakeLockType::PARTIAL, id, &wl);
75*79330504STreehugger Robot // It's possible that during device shutdown SystemSuspend service has
76*79330504STreehugger Robot // already exited. Check that the wakelock object is not null.
77*79330504STreehugger Robot if (!wl) {
78*79330504STreehugger Robot LOG(ERROR) << "ISuspendService::acquireWakeLock() call failed: "
79*79330504STreehugger Robot << status.getDescription();
80*79330504STreehugger Robot return -1;
81*79330504STreehugger Robot }
82*79330504STreehugger Robot {
83*79330504STreehugger Robot std::lock_guard<std::mutex> l{gLock};
84*79330504STreehugger Robot // Check if another thread has already set it.
85*79330504STreehugger Robot if (!gWakeLockMap[id]) gWakeLockMap[id] = wl;
86*79330504STreehugger Robot }
87*79330504STreehugger Robot #else
88*79330504STreehugger Robot std::lock_guard<std::mutex> l{gLock};
89*79330504STreehugger Robot if (!gWakeLockMap[id]) {
90*79330504STreehugger Robot std::shared_ptr<IWakeLock> wl = nullptr;
91*79330504STreehugger Robot auto status = suspendService->acquireWakeLock(WakeLockType::PARTIAL, id, &wl);
92*79330504STreehugger Robot // It's possible that during device shutdown SystemSuspend service has already exited.
93*79330504STreehugger Robot // Check that the wakelock object is not null.
94*79330504STreehugger Robot if (!wl) {
95*79330504STreehugger Robot LOG(ERROR) << "ISuspendService::acquireWakeLock() call failed: "
96*79330504STreehugger Robot << status.getDescription();
97*79330504STreehugger Robot return -1;
98*79330504STreehugger Robot }
99*79330504STreehugger Robot gWakeLockMap[id] = wl;
100*79330504STreehugger Robot }
101*79330504STreehugger Robot #endif
102*79330504STreehugger Robot return 0;
103*79330504STreehugger Robot }
104*79330504STreehugger Robot
release_wake_lock(const char * id)105*79330504STreehugger Robot int release_wake_lock(const char* id) {
106*79330504STreehugger Robot ATRACE_CALL();
107*79330504STreehugger Robot std::lock_guard<std::mutex> l{gLock};
108*79330504STreehugger Robot if (gWakeLockMap[id]) {
109*79330504STreehugger Robot // Ignore errors on release() call since hwbinder driver will clean up the underlying object
110*79330504STreehugger Robot // once we clear the corresponding shared_ptr.
111*79330504STreehugger Robot auto status = gWakeLockMap[id]->release();
112*79330504STreehugger Robot if (!status.isOk()) {
113*79330504STreehugger Robot LOG(ERROR) << "IWakeLock::release() call failed: " << status.getDescription();
114*79330504STreehugger Robot }
115*79330504STreehugger Robot gWakeLockMap[id] = nullptr;
116*79330504STreehugger Robot return 0;
117*79330504STreehugger Robot }
118*79330504STreehugger Robot return -1;
119*79330504STreehugger Robot }
120*79330504STreehugger Robot
121*79330504STreehugger Robot namespace android {
122*79330504STreehugger Robot namespace wakelock {
123*79330504STreehugger Robot
124*79330504STreehugger Robot class WakeLock::WakeLockImpl {
125*79330504STreehugger Robot public:
126*79330504STreehugger Robot WakeLockImpl(const std::string& name);
127*79330504STreehugger Robot ~WakeLockImpl();
128*79330504STreehugger Robot bool acquireOk();
129*79330504STreehugger Robot
130*79330504STreehugger Robot private:
131*79330504STreehugger Robot std::shared_ptr<IWakeLock> mWakeLock;
132*79330504STreehugger Robot };
133*79330504STreehugger Robot
tryGet(const std::string & name)134*79330504STreehugger Robot std::optional<WakeLock> WakeLock::tryGet(const std::string& name) {
135*79330504STreehugger Robot std::unique_ptr<WakeLockImpl> wlImpl = std::make_unique<WakeLockImpl>(name);
136*79330504STreehugger Robot if (wlImpl->acquireOk()) {
137*79330504STreehugger Robot return { std::move(wlImpl) };
138*79330504STreehugger Robot } else {
139*79330504STreehugger Robot LOG(ERROR) << "Failed to acquire wakelock: " << name;
140*79330504STreehugger Robot return {};
141*79330504STreehugger Robot }
142*79330504STreehugger Robot }
143*79330504STreehugger Robot
WakeLock(std::unique_ptr<WakeLockImpl> wlImpl)144*79330504STreehugger Robot WakeLock::WakeLock(std::unique_ptr<WakeLockImpl> wlImpl) : mImpl(std::move(wlImpl)) {}
145*79330504STreehugger Robot
146*79330504STreehugger Robot WakeLock::~WakeLock() = default;
147*79330504STreehugger Robot
WakeLockImpl(const std::string & name)148*79330504STreehugger Robot WakeLock::WakeLockImpl::WakeLockImpl(const std::string& name) : mWakeLock(nullptr) {
149*79330504STreehugger Robot const auto suspendService = getSystemSuspendServiceOnce();
150*79330504STreehugger Robot if (!suspendService) {
151*79330504STreehugger Robot LOG(ERROR) << "Failed to get SystemSuspend service";
152*79330504STreehugger Robot return;
153*79330504STreehugger Robot }
154*79330504STreehugger Robot
155*79330504STreehugger Robot std::shared_ptr<IWakeLock> wl = nullptr;
156*79330504STreehugger Robot auto status = suspendService->acquireWakeLock(WakeLockType::PARTIAL, name, &wl);
157*79330504STreehugger Robot // It's possible that during device shutdown SystemSuspend service has already exited.
158*79330504STreehugger Robot // Check that the wakelock object is not null.
159*79330504STreehugger Robot if (!wl) {
160*79330504STreehugger Robot LOG(ERROR) << "ISuspendService::acquireWakeLock() call failed: " << status.getDescription();
161*79330504STreehugger Robot } else {
162*79330504STreehugger Robot mWakeLock = wl;
163*79330504STreehugger Robot }
164*79330504STreehugger Robot }
165*79330504STreehugger Robot
~WakeLockImpl()166*79330504STreehugger Robot WakeLock::WakeLockImpl::~WakeLockImpl() {
167*79330504STreehugger Robot if (!acquireOk()) {
168*79330504STreehugger Robot return;
169*79330504STreehugger Robot }
170*79330504STreehugger Robot auto status = mWakeLock->release();
171*79330504STreehugger Robot if (!status.isOk()) {
172*79330504STreehugger Robot LOG(ERROR) << "IWakeLock::release() call failed: " << status.getDescription();
173*79330504STreehugger Robot }
174*79330504STreehugger Robot }
175*79330504STreehugger Robot
acquireOk()176*79330504STreehugger Robot bool WakeLock::WakeLockImpl::acquireOk() {
177*79330504STreehugger Robot return mWakeLock != nullptr;
178*79330504STreehugger Robot }
179*79330504STreehugger Robot
180*79330504STreehugger Robot } // namespace wakelock
181*79330504STreehugger Robot } // namespace android
182