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