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