xref: /aosp_15_r20/hardware/libhardware_legacy/power.cpp (revision 79330504eb3d14022296e3b041867f86289dd52c)
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