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 
setSuspendService(const wp<SystemSuspend> & suspend)43 void SuspendControlService::setSuspendService(const wp<SystemSuspend>& suspend) {
44     mSuspend = suspend;
45 }
46 
enableAutosuspend(bool * _aidl_return)47 binder::Status SuspendControlService::enableAutosuspend(bool* _aidl_return) {
48     const auto suspendService = mSuspend.promote();
49     return retOk(suspendService != nullptr && suspendService->enableAutosuspend(), _aidl_return);
50 }
51 
registerCallback(const sp<ISuspendCallback> & callback,bool * _aidl_return)52 binder::Status SuspendControlService::registerCallback(const sp<ISuspendCallback>& callback,
53                                                        bool* _aidl_return) {
54     if (!callback) {
55         return retOk(false, _aidl_return);
56     }
57 
58     auto l = std::lock_guard(mCallbackLock);
59     sp<IBinder> cb = IInterface::asBinder(callback);
60     // Only remote binders can be linked to death
61     if (cb->remoteBinder() != nullptr) {
62         if (findCb(cb) == mCallbacks.end()) {
63             auto status = cb->linkToDeath(this);
64             if (status != NO_ERROR) {
65                 LOG(ERROR) << __func__ << " Cannot link to death: " << status;
66                 return retOk(false, _aidl_return);
67             }
68         }
69     }
70     mCallbacks.push_back(callback);
71     return retOk(true, _aidl_return);
72 }
73 
forceSuspend(bool * _aidl_return)74 binder::Status SuspendControlService::forceSuspend(bool* _aidl_return) {
75     const auto suspendService = mSuspend.promote();
76     return retOk(suspendService != nullptr && suspendService->forceSuspend(), _aidl_return);
77 }
78 
binderDied(const wp<IBinder> & who)79 void SuspendControlService::binderDied(const wp<IBinder>& who) {
80     auto l = std::lock_guard(mCallbackLock);
81     mCallbacks.erase(findCb(who));
82 }
83 
notifyWakeup(bool success)84 void SuspendControlService::notifyWakeup(bool success) {
85     // A callback could potentially modify mCallbacks (e.g., via registerCallback). That must not
86     // result in a deadlock. To that end, we make a copy of mCallbacks and release mCallbackLock
87     // before calling the copied callbacks.
88     auto callbackLock = std::unique_lock(mCallbackLock);
89     auto callbacksCopy = mCallbacks;
90     callbackLock.unlock();
91 
92     for (const auto& callback : callbacksCopy) {
93         callback->notifyWakeup(success).isOk();  // ignore errors
94     }
95 }
96 
getWakeLockStats(std::vector<WakeLockInfo> * _aidl_return)97 binder::Status SuspendControlService::getWakeLockStats(std::vector<WakeLockInfo>* _aidl_return) {
98     const auto suspendService = mSuspend.promote();
99     if (!suspendService) {
100         return binder::Status::fromExceptionCode(binder::Status::Exception::EX_NULL_POINTER,
101                                                  String8("Null reference to suspendService"));
102     }
103 
104     suspendService->updateStatsNow();
105     suspendService->getStatsList().getWakeLockStats(_aidl_return);
106 
107     return binder::Status::ok();
108 }
109 
dumpUsage()110 static std::string dumpUsage() {
111     return "\nUsage: adb shell dumpsys suspend_control [option]\n\n"
112            "   Options:\n"
113            "       --wakelocks      : returns wakelock stats.\n"
114            "       --suspend_stats  : returns suspend stats.\n"
115            "       --help or -h     : prints this message.\n\n"
116            "   Note: All stats are returned  if no or (an\n"
117            "         invalid) option is specified.\n\n";
118 }
119 
dump(int fd,const Vector<String16> & args)120 status_t SuspendControlService::dump(int fd, const Vector<String16>& args) {
121     register_sig_handler();
122 
123     const auto suspendService = mSuspend.promote();
124     if (!suspendService) {
125         return DEAD_OBJECT;
126     }
127 
128     bool wakelocks = true;
129     bool suspend_stats = true;
130 
131     if (args.size() > 0) {
132         std::string arg(String8(args[0]).string());
133         if (arg == "--wakelocks") {
134             suspend_stats = false;
135         } else if (arg == "--suspend_stats") {
136             wakelocks = false;
137         } else if (arg == "-h" || arg == "--help") {
138             std::string usage = dumpUsage();
139             dprintf(fd, "%s\n", usage.c_str());
140             return OK;
141         }
142     }
143 
144     if (wakelocks) {
145         suspendService->updateStatsNow();
146         std::stringstream wlStats;
147         wlStats << suspendService->getStatsList();
148         dprintf(fd, "\n%s\n", wlStats.str().c_str());
149     }
150     if (suspend_stats) {
151         Result<SuspendStats> res = suspendService->getSuspendStats();
152         if (!res.ok()) {
153             LOG(ERROR) << "SuspendControlService: " << res.error().message();
154             return OK;
155         }
156 
157         SuspendStats stats = res.value();
158         // clang-format off
159         std::string suspendStats = StringPrintf(
160             "----- Suspend Stats -----\n"
161             "%s: %d\n%s: %d\n%s: %d\n%s: %d\n%s: %d\n"
162             "%s: %d\n%s: %d\n%s: %d\n%s: %d\n%s: %d\n"
163             "\nLast Failures:\n"
164             "    %s: %s\n"
165             "    %s: %d\n"
166             "    %s: %s\n"
167             "----------\n\n",
168 
169             "success", stats.success,
170             "fail", stats.fail,
171             "failed_freeze", stats.failedFreeze,
172             "failed_prepare", stats.failedPrepare,
173             "failed_suspend", stats.failedSuspend,
174             "failed_suspend_late", stats.failedSuspendLate,
175             "failed_suspend_noirq", stats.failedSuspendNoirq,
176             "failed_resume", stats.failedResume,
177             "failed_resume_early", stats.failedResumeEarly,
178             "failed_resume_noirq", stats.failedResumeNoirq,
179             "last_failed_dev", stats.lastFailedDev.c_str(),
180             "last_failed_errno", stats.lastFailedErrno,
181             "last_failed_step", stats.lastFailedStep.c_str());
182         // clang-format on
183         dprintf(fd, "\n%s\n", suspendStats.c_str());
184     }
185 
186     return OK;
187 }
188 
189 }  // namespace V1_0
190 }  // namespace suspend
191 }  // namespace system
192 }  // namespace android
193