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