1 /*
2 * Copyright 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "SuspendControlService.h"
18
19 #include <android-base/logging.h>
20 #include <android-base/stringprintf.h>
21 #include <signal.h>
22
23 #include "SystemSuspend.h"
24
25 using ::android::base::Result;
26 using ::android::base::StringPrintf;
27
28 namespace android {
29 namespace system {
30 namespace suspend {
31 namespace V1_0 {
32
register_sig_handler()33 static void register_sig_handler() {
34 signal(SIGPIPE, SIG_IGN);
35 }
36
37 template <typename T>
retOk(const T & value,T * ret_val)38 binder::Status retOk(const T& value, T* ret_val) {
39 *ret_val = value;
40 return binder::Status::ok();
41 }
42
registerCallback(const sp<ISuspendCallback> & callback,bool * _aidl_return)43 binder::Status SuspendControlService::registerCallback(const sp<ISuspendCallback>& callback,
44 bool* _aidl_return) {
45 if (!callback) {
46 return retOk(false, _aidl_return);
47 }
48
49 auto l = std::lock_guard(mCallbackLock);
50 sp<IBinder> cb = IInterface::asBinder(callback);
51 // Only remote binders can be linked to death
52 if (cb->remoteBinder() != nullptr) {
53 if (findCb(cb) == mCallbacks.end()) {
54 auto status = cb->linkToDeath(this);
55 if (status != NO_ERROR) {
56 LOG(ERROR) << __func__ << " Cannot link to death: " << status;
57 return retOk(false, _aidl_return);
58 }
59 }
60 }
61 mCallbacks.push_back(callback);
62 return retOk(true, _aidl_return);
63 }
64
registerWakelockCallback(const sp<IWakelockCallback> & callback,const std::string & name,bool * _aidl_return)65 binder::Status SuspendControlService::registerWakelockCallback(
66 const sp<IWakelockCallback>& callback, const std::string& name, bool* _aidl_return) {
67 if (!callback || name.empty()) {
68 return retOk(false, _aidl_return);
69 }
70
71 auto l = std::lock_guard(mWakelockCallbackLock);
72 if (std::find_if(mWakelockCallbacks[name].begin(), mWakelockCallbacks[name].end(),
73 [&callback](const sp<IWakelockCallback>& i) {
74 return IInterface::asBinder(callback) == IInterface::asBinder(i);
75 }) != mWakelockCallbacks[name].end()) {
76 LOG(ERROR) << __func__ << " Same wakelock callback has already been registered";
77 return retOk(false, _aidl_return);
78 }
79
80 if (IInterface::asBinder(callback)->remoteBinder() &&
81 IInterface::asBinder(callback)->linkToDeath(this) != NO_ERROR) {
82 LOG(WARNING) << __func__ << " Cannot link to death";
83 return retOk(false, _aidl_return);
84 }
85 mWakelockCallbacks[name].push_back(callback);
86
87 return retOk(true, _aidl_return);
88 }
89
binderDied(const wp<IBinder> & who)90 void SuspendControlService::binderDied(const wp<IBinder>& who) {
91 auto l = std::lock_guard(mCallbackLock);
92 mCallbacks.erase(std::remove_if(mCallbacks.begin(), mCallbacks.end(),
93 [&who](const sp<ISuspendCallback>& i) {
94 return who == IInterface::asBinder(i);
95 }),
96 mCallbacks.end());
97
98 auto lWakelock = std::lock_guard(mWakelockCallbackLock);
99 // Iterate through all wakelock names as same callback can be registered with different
100 // wakelocks.
101 for (auto wakelockIt = mWakelockCallbacks.begin(); wakelockIt != mWakelockCallbacks.end();) {
102 wakelockIt->second.erase(
103 std::remove_if(
104 wakelockIt->second.begin(), wakelockIt->second.end(),
105 [&who](const sp<IWakelockCallback>& i) { return who == IInterface::asBinder(i); }),
106 wakelockIt->second.end());
107 if (wakelockIt->second.empty()) {
108 wakelockIt = mWakelockCallbacks.erase(wakelockIt);
109 } else {
110 ++wakelockIt;
111 }
112 }
113 }
114
notifyWakelock(const std::string & name,bool isAcquired)115 void SuspendControlService::notifyWakelock(const std::string& name, bool isAcquired) {
116 // A callback could potentially modify mWakelockCallbacks (e.g., via registerCallback). That
117 // must not result in a deadlock. To that end, we make a copy of the callback is an entry can be
118 // found for the particular wakelock and release mCallbackLock before calling the copied
119 // callbacks.
120 auto callbackLock = std::unique_lock(mWakelockCallbackLock);
121 auto it = mWakelockCallbacks.find(name);
122 if (it == mWakelockCallbacks.end()) {
123 return;
124 }
125 auto callbacksCopy = it->second;
126 callbackLock.unlock();
127
128 for (const auto& callback : callbacksCopy) {
129 if (isAcquired) {
130 callback->notifyAcquired().isOk(); // ignore errors
131 } else {
132 callback->notifyReleased().isOk(); // ignore errors
133 }
134 }
135 }
136
notifyWakeup(bool success,std::vector<std::string> & wakeupReasons)137 void SuspendControlService::notifyWakeup(bool success, std::vector<std::string>& wakeupReasons) {
138 // A callback could potentially modify mCallbacks (e.g., via registerCallback). That must not
139 // result in a deadlock. To that end, we make a copy of mCallbacks and release mCallbackLock
140 // before calling the copied callbacks.
141 auto callbackLock = std::unique_lock(mCallbackLock);
142 auto callbacksCopy = mCallbacks;
143 callbackLock.unlock();
144
145 for (const auto& callback : callbacksCopy) {
146 callback->notifyWakeup(success, wakeupReasons).isOk(); // ignore errors
147 }
148 }
149
setSuspendService(const wp<SystemSuspend> & suspend)150 void SuspendControlServiceInternal::setSuspendService(const wp<SystemSuspend>& suspend) {
151 mSuspend = suspend;
152 }
153
enableAutosuspend(const sp<IBinder> & token,bool * _aidl_return)154 binder::Status SuspendControlServiceInternal::enableAutosuspend(const sp<IBinder>& token,
155 bool* _aidl_return) {
156 const auto suspendService = mSuspend.promote();
157 return retOk(suspendService != nullptr && suspendService->enableAutosuspend(token),
158 _aidl_return);
159 }
160
forceSuspend(bool * _aidl_return)161 binder::Status SuspendControlServiceInternal::forceSuspend(bool* _aidl_return) {
162 const auto suspendService = mSuspend.promote();
163 return retOk(suspendService != nullptr && suspendService->forceSuspend(), _aidl_return);
164 }
165
getSuspendStats(SuspendInfo * _aidl_return)166 binder::Status SuspendControlServiceInternal::getSuspendStats(SuspendInfo* _aidl_return) {
167 const auto suspendService = mSuspend.promote();
168 if (!suspendService) {
169 return binder::Status::fromExceptionCode(binder::Status::Exception::EX_NULL_POINTER,
170 String8("Null reference to suspendService"));
171 }
172
173 suspendService->getSuspendInfo(_aidl_return);
174 return binder::Status::ok();
175 }
176
getWakeLockStats(std::vector<WakeLockInfo> * _aidl_return)177 binder::Status SuspendControlServiceInternal::getWakeLockStats(
178 std::vector<WakeLockInfo>* _aidl_return) {
179 const auto suspendService = mSuspend.promote();
180 if (!suspendService) {
181 return binder::Status::fromExceptionCode(binder::Status::Exception::EX_NULL_POINTER,
182 String8("Null reference to suspendService"));
183 }
184
185 suspendService->updateStatsNow();
186 suspendService->getStatsList().getWakeLockStats(
187 BnSuspendControlServiceInternal::WAKE_LOCK_INFO_ALL_FIELDS, _aidl_return);
188
189 return binder::Status::ok();
190 }
191
getWakeLockStatsFiltered(int wakeLockInfoFieldBitMask,std::vector<WakeLockInfo> * _aidl_return)192 binder::Status SuspendControlServiceInternal::getWakeLockStatsFiltered(
193 int wakeLockInfoFieldBitMask, std::vector<WakeLockInfo>* _aidl_return) {
194 const auto suspendService = mSuspend.promote();
195 if (!suspendService) {
196 return binder::Status::fromExceptionCode(binder::Status::Exception::EX_NULL_POINTER,
197 String8("Null reference to suspendService"));
198 }
199
200 suspendService->updateStatsNow();
201 suspendService->getStatsList().getWakeLockStats(wakeLockInfoFieldBitMask, _aidl_return);
202
203 return binder::Status::ok();
204 }
205
getWakeupStats(std::vector<WakeupInfo> * _aidl_return)206 binder::Status SuspendControlServiceInternal::getWakeupStats(
207 std::vector<WakeupInfo>* _aidl_return) {
208 const auto suspendService = mSuspend.promote();
209 if (!suspendService) {
210 return binder::Status::fromExceptionCode(binder::Status::Exception::EX_NULL_POINTER,
211 String8("Null reference to suspendService"));
212 }
213
214 suspendService->getWakeupList().getWakeupStats(_aidl_return);
215 return binder::Status::ok();
216 }
217
dumpUsage()218 static std::string dumpUsage() {
219 return "\nUsage: adb shell dumpsys suspend_control_internal [option]\n\n"
220 " Options:\n"
221 " --wakelocks : returns wakelock stats.\n"
222 " --wakeups : returns wakeup stats.\n"
223 " --kernel_suspends : returns suspend success/error stats from the kernel\n"
224 " --suspend_controls : returns suspend control stats\n"
225 " --all or -a : returns all stats.\n"
226 " --help or -h : prints this message.\n\n"
227 " Note: All stats are returned if no or (an\n"
228 " invalid) option is specified.\n\n";
229 }
230
dump(int fd,const Vector<String16> & args)231 status_t SuspendControlServiceInternal::dump(int fd, const Vector<String16>& args) {
232 register_sig_handler();
233
234 const auto suspendService = mSuspend.promote();
235 if (!suspendService) {
236 return DEAD_OBJECT;
237 }
238
239 enum : int32_t {
240 OPT_WAKELOCKS = 1 << 0,
241 OPT_WAKEUPS = 1 << 1,
242 OPT_KERNEL_SUSPENDS = 1 << 2,
243 OPT_SUSPEND_CONTROLS = 1 << 3,
244 OPT_ALL = ~0,
245 };
246 int opts = 0;
247
248 if (args.empty()) {
249 opts = OPT_ALL;
250 } else {
251 for (const auto& arg : args) {
252 if (arg == String16("--wakelocks")) {
253 opts |= OPT_WAKELOCKS;
254 } else if (arg == String16("--wakeups")) {
255 opts |= OPT_WAKEUPS;
256 } else if (arg == String16("--kernel_suspends")) {
257 opts |= OPT_KERNEL_SUSPENDS;
258 } else if (arg == String16("--suspend_controls")) {
259 opts |= OPT_SUSPEND_CONTROLS;
260 } else if (arg == String16("-a") || arg == String16("--all")) {
261 opts = OPT_ALL;
262 } else if (arg == String16("-h") || arg == String16("--help")) {
263 std::string usage = dumpUsage();
264 dprintf(fd, "%s\n", usage.c_str());
265 return OK;
266 }
267 }
268 }
269
270 if (opts & OPT_WAKELOCKS) {
271 suspendService->updateStatsNow();
272 std::stringstream wlStats;
273 wlStats << suspendService->getStatsList();
274 dprintf(fd, "\n%s\n", wlStats.str().c_str());
275 }
276
277 if (opts & OPT_WAKEUPS) {
278 std::ostringstream wakeupStats;
279 std::vector<WakeupInfo> wakeups;
280 suspendService->getWakeupList().getWakeupStats(&wakeups);
281 for (const auto& w : wakeups) {
282 wakeupStats << w.toString() << std::endl;
283 }
284 dprintf(fd, "Wakeups:\n%s\n", wakeupStats.str().c_str());
285 }
286
287 if (opts & OPT_KERNEL_SUSPENDS) {
288 Result<SuspendStats> res = suspendService->getSuspendStats();
289 if (!res.ok()) {
290 LOG(ERROR) << "SuspendControlService: " << res.error().message();
291 return OK;
292 }
293
294 SuspendStats stats = res.value();
295 // clang-format off
296 std::string suspendStats = StringPrintf(
297 "----- Suspend Stats -----\n"
298 "%s: %d\n%s: %d\n%s: %d\n%s: %d\n%s: %d\n"
299 "%s: %d\n%s: %d\n%s: %d\n%s: %d\n%s: %d\n"
300 "%s: %" PRIu64 "\n%s: %" PRIu64 "\n%s: %" PRIu64 "\n"
301 "\nLast Failures:\n"
302 " %s: %s\n"
303 " %s: %d\n"
304 " %s: %s\n"
305 "----------\n\n",
306
307 "success", stats.success,
308 "fail", stats.fail,
309 "failed_freeze", stats.failedFreeze,
310 "failed_prepare", stats.failedPrepare,
311 "failed_suspend", stats.failedSuspend,
312 "failed_suspend_late", stats.failedSuspendLate,
313 "failed_suspend_noirq", stats.failedSuspendNoirq,
314 "failed_resume", stats.failedResume,
315 "failed_resume_early", stats.failedResumeEarly,
316 "failed_resume_noirq", stats.failedResumeNoirq,
317 "last_hw_sleep", stats.lastHwSleep,
318 "total_hw_sleep", stats.totalHwSleep,
319 "max_hw_sleep", stats.maxHwSleep,
320 "last_failed_dev", stats.lastFailedDev.c_str(),
321 "last_failed_errno", stats.lastFailedErrno,
322 "last_failed_step", stats.lastFailedStep.c_str());
323 // clang-format on
324 dprintf(fd, "\n%s\n", suspendStats.c_str());
325 }
326
327 if (opts & OPT_SUSPEND_CONTROLS) {
328 std::ostringstream suspendInfo;
329 SuspendInfo info;
330 suspendService->getSuspendInfo(&info);
331 suspendInfo << "suspend attempts: " << info.suspendAttemptCount << std::endl;
332 suspendInfo << "failed suspends: " << info.failedSuspendCount << std::endl;
333 suspendInfo << "short suspends: " << info.shortSuspendCount << std::endl;
334 suspendInfo << "total suspend time: " << info.suspendTimeMillis << " ms" << std::endl;
335 suspendInfo << "short suspend time: " << info.shortSuspendTimeMillis << " ms" << std::endl;
336 suspendInfo << "suspend overhead: " << info.suspendOverheadTimeMillis << " ms" << std::endl;
337 suspendInfo << "failed suspend overhead: " << info.failedSuspendOverheadTimeMillis << " ms"
338 << std::endl;
339 suspendInfo << "new backoffs: " << info.newBackoffCount << std::endl;
340 suspendInfo << "backoff continuations: " << info.backoffContinueCount << std::endl;
341 suspendInfo << "total sleep time between suspends: " << info.sleepTimeMillis << " ms"
342 << std::endl;
343 dprintf(fd, "Suspend Info:\n%s\n", suspendInfo.str().c_str());
344 }
345
346 return OK;
347 }
348
349 } // namespace V1_0
350 } // namespace suspend
351 } // namespace system
352 } // namespace android
353