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