• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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