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(bool * _aidl_return)154 binder::Status SuspendControlServiceInternal::enableAutosuspend(bool* _aidl_return) {
155 const auto suspendService = mSuspend.promote();
156 return retOk(suspendService != nullptr && suspendService->enableAutosuspend(), _aidl_return);
157 }
158
forceSuspend(bool * _aidl_return)159 binder::Status SuspendControlServiceInternal::forceSuspend(bool* _aidl_return) {
160 const auto suspendService = mSuspend.promote();
161 return retOk(suspendService != nullptr && suspendService->forceSuspend(), _aidl_return);
162 }
163
getSuspendStats(SuspendInfo * _aidl_return)164 binder::Status SuspendControlServiceInternal::getSuspendStats(SuspendInfo* _aidl_return) {
165 const auto suspendService = mSuspend.promote();
166 if (!suspendService) {
167 return binder::Status::fromExceptionCode(binder::Status::Exception::EX_NULL_POINTER,
168 String8("Null reference to suspendService"));
169 }
170
171 suspendService->getSuspendInfo(_aidl_return);
172 return binder::Status::ok();
173 }
174
getWakeLockStats(std::vector<WakeLockInfo> * _aidl_return)175 binder::Status SuspendControlServiceInternal::getWakeLockStats(
176 std::vector<WakeLockInfo>* _aidl_return) {
177 const auto suspendService = mSuspend.promote();
178 if (!suspendService) {
179 return binder::Status::fromExceptionCode(binder::Status::Exception::EX_NULL_POINTER,
180 String8("Null reference to suspendService"));
181 }
182
183 suspendService->updateStatsNow();
184 suspendService->getStatsList().getWakeLockStats(_aidl_return);
185
186 return binder::Status::ok();
187 }
188
getWakeupStats(std::vector<WakeupInfo> * _aidl_return)189 binder::Status SuspendControlServiceInternal::getWakeupStats(
190 std::vector<WakeupInfo>* _aidl_return) {
191 const auto suspendService = mSuspend.promote();
192 if (!suspendService) {
193 return binder::Status::fromExceptionCode(binder::Status::Exception::EX_NULL_POINTER,
194 String8("Null reference to suspendService"));
195 }
196
197 suspendService->getWakeupList().getWakeupStats(_aidl_return);
198 return binder::Status::ok();
199 }
200
dumpUsage()201 static std::string dumpUsage() {
202 return "\nUsage: adb shell dumpsys suspend_control_internal [option]\n\n"
203 " Options:\n"
204 " --wakelocks : returns wakelock stats.\n"
205 " --wakeups : returns wakeup stats.\n"
206 " --kernel_suspends : returns suspend success/error stats from the kernel\n"
207 " --suspend_controls : returns suspend control stats\n"
208 " --all or -a : returns all stats.\n"
209 " --help or -h : prints this message.\n\n"
210 " Note: All stats are returned if no or (an\n"
211 " invalid) option is specified.\n\n";
212 }
213
dump(int fd,const Vector<String16> & args)214 status_t SuspendControlServiceInternal::dump(int fd, const Vector<String16>& args) {
215 register_sig_handler();
216
217 const auto suspendService = mSuspend.promote();
218 if (!suspendService) {
219 return DEAD_OBJECT;
220 }
221
222 enum : int32_t {
223 OPT_WAKELOCKS = 1 << 0,
224 OPT_WAKEUPS = 1 << 1,
225 OPT_KERNEL_SUSPENDS = 1 << 2,
226 OPT_SUSPEND_CONTROLS = 1 << 3,
227 OPT_ALL = ~0,
228 };
229 int opts = 0;
230
231 if (args.empty()) {
232 opts = OPT_ALL;
233 } else {
234 for (const auto& arg : args) {
235 if (arg == String16("--wakelocks")) {
236 opts |= OPT_WAKELOCKS;
237 } else if (arg == String16("--wakeups")) {
238 opts |= OPT_WAKEUPS;
239 } else if (arg == String16("--kernel_suspends")) {
240 opts |= OPT_KERNEL_SUSPENDS;
241 } else if (arg == String16("--suspend_controls")) {
242 opts |= OPT_SUSPEND_CONTROLS;
243 } else if (arg == String16("-a") || arg == String16("--all")) {
244 opts = OPT_ALL;
245 } else if (arg == String16("-h") || arg == String16("--help")) {
246 std::string usage = dumpUsage();
247 dprintf(fd, "%s\n", usage.c_str());
248 return OK;
249 }
250 }
251 }
252
253 if (opts & OPT_WAKELOCKS) {
254 suspendService->updateStatsNow();
255 std::stringstream wlStats;
256 wlStats << suspendService->getStatsList();
257 dprintf(fd, "\n%s\n", wlStats.str().c_str());
258 }
259
260 if (opts & OPT_WAKEUPS) {
261 std::ostringstream wakeupStats;
262 std::vector<WakeupInfo> wakeups;
263 suspendService->getWakeupList().getWakeupStats(&wakeups);
264 for (const auto& w : wakeups) {
265 wakeupStats << w.toString() << std::endl;
266 }
267 dprintf(fd, "Wakeups:\n%s\n", wakeupStats.str().c_str());
268 }
269
270 if (opts & OPT_KERNEL_SUSPENDS) {
271 Result<SuspendStats> res = suspendService->getSuspendStats();
272 if (!res.ok()) {
273 LOG(ERROR) << "SuspendControlService: " << res.error().message();
274 return OK;
275 }
276
277 SuspendStats stats = res.value();
278 // clang-format off
279 std::string suspendStats = StringPrintf(
280 "----- Suspend Stats -----\n"
281 "%s: %d\n%s: %d\n%s: %d\n%s: %d\n%s: %d\n"
282 "%s: %d\n%s: %d\n%s: %d\n%s: %d\n%s: %d\n"
283 "\nLast Failures:\n"
284 " %s: %s\n"
285 " %s: %d\n"
286 " %s: %s\n"
287 "----------\n\n",
288
289 "success", stats.success,
290 "fail", stats.fail,
291 "failed_freeze", stats.failedFreeze,
292 "failed_prepare", stats.failedPrepare,
293 "failed_suspend", stats.failedSuspend,
294 "failed_suspend_late", stats.failedSuspendLate,
295 "failed_suspend_noirq", stats.failedSuspendNoirq,
296 "failed_resume", stats.failedResume,
297 "failed_resume_early", stats.failedResumeEarly,
298 "failed_resume_noirq", stats.failedResumeNoirq,
299 "last_failed_dev", stats.lastFailedDev.c_str(),
300 "last_failed_errno", stats.lastFailedErrno,
301 "last_failed_step", stats.lastFailedStep.c_str());
302 // clang-format on
303 dprintf(fd, "\n%s\n", suspendStats.c_str());
304 }
305
306 if (opts & OPT_SUSPEND_CONTROLS) {
307 std::ostringstream suspendInfo;
308 SuspendInfo info;
309 suspendService->getSuspendInfo(&info);
310 suspendInfo << "suspend attempts: " << info.suspendAttemptCount << std::endl;
311 suspendInfo << "failed suspends: " << info.failedSuspendCount << std::endl;
312 suspendInfo << "short suspends: " << info.shortSuspendCount << std::endl;
313 suspendInfo << "total suspend time: " << info.suspendTimeMillis << " ms" << std::endl;
314 suspendInfo << "short suspend time: " << info.shortSuspendTimeMillis << " ms" << std::endl;
315 suspendInfo << "suspend overhead: " << info.suspendOverheadTimeMillis << " ms" << std::endl;
316 suspendInfo << "failed suspend overhead: " << info.failedSuspendOverheadTimeMillis << " ms"
317 << std::endl;
318 suspendInfo << "new backoffs: " << info.newBackoffCount << std::endl;
319 suspendInfo << "backoff continuations: " << info.backoffContinueCount << std::endl;
320 suspendInfo << "total sleep time between suspends: " << info.sleepTimeMillis << " ms"
321 << std::endl;
322 dprintf(fd, "Suspend Info:\n%s\n", suspendInfo.str().c_str());
323 }
324
325 return OK;
326 }
327
328 } // namespace V1_0
329 } // namespace suspend
330 } // namespace system
331 } // namespace android
332