• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2018 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 "SystemSuspend.h"
18 
19 #include <android-base/file.h>
20 #include <android-base/logging.h>
21 #include <android-base/strings.h>
22 #include <google/protobuf/text_format.h>
23 #include <hidl/Status.h>
24 #include <hwbinder/IPCThreadState.h>
25 
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 
29 #include <fcntl.h>
30 #include <ctime>
31 #include <string>
32 #include <thread>
33 
34 using ::android::base::ReadFdToString;
35 using ::android::base::WriteStringToFd;
36 using ::android::hardware::Void;
37 using ::std::string;
38 
39 namespace android {
40 namespace system {
41 namespace suspend {
42 namespace V1_0 {
43 
44 static const char kSleepState[] = "mem";
45 // TODO(b/128923994): we only need /sys/power/wake_[un]lock to export debugging info via
46 // /sys/kernel/debug/wakeup_sources.
47 static constexpr char kSysPowerWakeLock[] = "/sys/power/wake_lock";
48 static constexpr char kSysPowerWakeUnlock[] = "/sys/power/wake_unlock";
49 
50 // This function assumes that data in fd is small enough that it can be read in one go.
51 // We use this function instead of the ones available in libbase because it doesn't block
52 // indefinitely when reading from socket streams which are used for testing.
readFd(int fd)53 string readFd(int fd) {
54     char buf[BUFSIZ];
55     ssize_t n = TEMP_FAILURE_RETRY(read(fd, &buf[0], sizeof(buf)));
56     if (n < 0) return "";
57     return string{buf, static_cast<size_t>(n)};
58 }
59 
getCallingPid()60 static inline int getCallingPid() {
61     return ::android::hardware::IPCThreadState::self()->getCallingPid();
62 }
63 
getWakeLockId(int pid,const string & name)64 static inline WakeLockIdType getWakeLockId(int pid, const string& name) {
65     // Doesn't guarantee unique ids, but for debuging purposes this is adequate.
66     return std::to_string(pid) + "/" + name;
67 }
68 
getEpochTimeNow()69 TimestampType getEpochTimeNow() {
70     auto timeSinceEpoch = std::chrono::system_clock::now().time_since_epoch();
71     return std::chrono::duration_cast<std::chrono::microseconds>(timeSinceEpoch).count();
72 }
73 
WakeLock(SystemSuspend * systemSuspend,const WakeLockIdType & id,const string & name)74 WakeLock::WakeLock(SystemSuspend* systemSuspend, const WakeLockIdType& id, const string& name)
75     : mReleased(), mSystemSuspend(systemSuspend), mId(id), mName(name) {
76     mSystemSuspend->incSuspendCounter(mName);
77 }
78 
~WakeLock()79 WakeLock::~WakeLock() {
80     releaseOnce();
81 }
82 
release()83 Return<void> WakeLock::release() {
84     releaseOnce();
85     return Void();
86 }
87 
releaseOnce()88 void WakeLock::releaseOnce() {
89     std::call_once(mReleased, [this]() {
90         mSystemSuspend->decSuspendCounter(mName);
91         mSystemSuspend->deleteWakeLockStatsEntry(mId);
92     });
93 }
94 
SystemSuspend(unique_fd wakeupCountFd,unique_fd stateFd,size_t maxStatsEntries,std::chrono::milliseconds baseSleepTime,const sp<SuspendControlService> & controlService,bool useSuspendCounter)95 SystemSuspend::SystemSuspend(unique_fd wakeupCountFd, unique_fd stateFd, size_t maxStatsEntries,
96                              std::chrono::milliseconds baseSleepTime,
97                              const sp<SuspendControlService>& controlService,
98                              bool useSuspendCounter)
99     : mSuspendCounter(0),
100       mWakeupCountFd(std::move(wakeupCountFd)),
101       mStateFd(std::move(stateFd)),
102       mMaxStatsEntries(maxStatsEntries),
103       mBaseSleepTime(baseSleepTime),
104       mSleepTime(baseSleepTime),
105       mControlService(controlService),
106       mUseSuspendCounter(useSuspendCounter),
107       mWakeLockFd(-1),
108       mWakeUnlockFd(-1) {
109     mControlService->setSuspendService(this);
110 
111     if (!mUseSuspendCounter) {
112         mWakeLockFd.reset(TEMP_FAILURE_RETRY(open(kSysPowerWakeLock, O_CLOEXEC | O_RDWR)));
113         if (mWakeLockFd < 0) {
114             PLOG(ERROR) << "error opening " << kSysPowerWakeLock;
115         }
116         mWakeUnlockFd.reset(TEMP_FAILURE_RETRY(open(kSysPowerWakeUnlock, O_CLOEXEC | O_RDWR)));
117         if (mWakeUnlockFd < 0) {
118             PLOG(ERROR) << "error opening " << kSysPowerWakeUnlock;
119         }
120     }
121 }
122 
enableAutosuspend()123 bool SystemSuspend::enableAutosuspend() {
124     static bool initialized = false;
125     if (initialized) {
126         LOG(ERROR) << "Autosuspend already started.";
127         return false;
128     }
129 
130     initAutosuspend();
131     initialized = true;
132     return true;
133 }
134 
forceSuspend()135 bool SystemSuspend::forceSuspend() {
136     //  We are forcing the system to suspend. This particular call ignores all
137     //  existing wakelocks (full or partial). It does not cancel the wakelocks
138     //  or reset mSuspendCounter, it just ignores them.  When the system
139     //  returns from suspend, the wakelocks and SuspendCounter will not have
140     //  changed.
141     auto counterLock = std::unique_lock(mCounterLock);
142     bool success = WriteStringToFd(kSleepState, mStateFd);
143     counterLock.unlock();
144 
145     if (!success) {
146         PLOG(VERBOSE) << "error writing to /sys/power/state for forceSuspend";
147     }
148     return success;
149 }
150 
acquireWakeLock(WakeLockType,const hidl_string & name)151 Return<sp<IWakeLock>> SystemSuspend::acquireWakeLock(WakeLockType /* type */,
152                                                      const hidl_string& name) {
153     auto pid = getCallingPid();
154     auto wlId = getWakeLockId(pid, name);
155     IWakeLock* wl = new WakeLock{this, wlId, name};
156     {
157         auto l = std::lock_guard(mStatsLock);
158 
159         auto& wlStatsEntry = (*mStats.mutable_wl_stats())[wlId];
160         auto lastUpdated = wlStatsEntry.last_updated();
161         auto timeNow = getEpochTimeNow();
162         mLruWakeLockId.erase(lastUpdated);
163         mLruWakeLockId[timeNow] = wlId;
164 
165         wlStatsEntry.set_name(name);
166         wlStatsEntry.set_pid(pid);
167         wlStatsEntry.set_active(true);
168         wlStatsEntry.set_last_updated(timeNow);
169 
170         if (mStats.wl_stats().size() > mMaxStatsEntries) {
171             auto lruWakeLockId = mLruWakeLockId.begin()->second;
172             mLruWakeLockId.erase(mLruWakeLockId.begin());
173             mStats.mutable_wl_stats()->erase(lruWakeLockId);
174         }
175     }
176     return wl;
177 }
178 
debug(const hidl_handle & handle,const hidl_vec<hidl_string> &)179 Return<void> SystemSuspend::debug(const hidl_handle& handle,
180                                   const hidl_vec<hidl_string>& /* options */) {
181     if (handle == nullptr || handle->numFds < 1 || handle->data[0] < 0) {
182         LOG(ERROR) << "no valid fd";
183         return Void();
184     }
185     int fd = handle->data[0];
186     string debugStr;
187     {
188         auto l = std::lock_guard(mStatsLock);
189         google::protobuf::TextFormat::PrintToString(mStats, &debugStr);
190     }
191     WriteStringToFd(debugStr, fd);
192     fsync(fd);
193     return Void();
194 }
195 
incSuspendCounter(const string & name)196 void SystemSuspend::incSuspendCounter(const string& name) {
197     auto l = std::lock_guard(mCounterLock);
198     if (mUseSuspendCounter) {
199         mSuspendCounter++;
200     } else {
201         if (!WriteStringToFd(name, mWakeLockFd)) {
202             PLOG(ERROR) << "error writing " << name << " to " << kSysPowerWakeLock;
203         }
204     }
205 }
206 
decSuspendCounter(const string & name)207 void SystemSuspend::decSuspendCounter(const string& name) {
208     auto l = std::lock_guard(mCounterLock);
209     if (mUseSuspendCounter) {
210         if (--mSuspendCounter == 0) {
211             mCounterCondVar.notify_one();
212         }
213     } else {
214         if (!WriteStringToFd(name, mWakeUnlockFd)) {
215             PLOG(ERROR) << "error writing " << name << " to " << kSysPowerWakeUnlock;
216         }
217     }
218 }
219 
deleteWakeLockStatsEntry(WakeLockIdType id)220 void SystemSuspend::deleteWakeLockStatsEntry(WakeLockIdType id) {
221     auto l = std::lock_guard(mStatsLock);
222     auto* wlStats = mStats.mutable_wl_stats();
223     if (wlStats->find(id) != wlStats->end()) {
224         auto& wlStatsEntry = (*wlStats)[id];
225         auto timeNow = getEpochTimeNow();
226         auto lastUpdated = wlStatsEntry.last_updated();
227         wlStatsEntry.set_active(false);
228         wlStatsEntry.set_last_updated(timeNow);
229         mLruWakeLockId.erase(lastUpdated);
230         mLruWakeLockId[timeNow] = id;
231     }
232 }
233 
initAutosuspend()234 void SystemSuspend::initAutosuspend() {
235     std::thread autosuspendThread([this] {
236         while (true) {
237             std::this_thread::sleep_for(mSleepTime);
238             lseek(mWakeupCountFd, 0, SEEK_SET);
239             const string wakeupCount = readFd(mWakeupCountFd);
240             if (wakeupCount.empty()) {
241                 PLOG(ERROR) << "error reading from /sys/power/wakeup_count";
242                 continue;
243             }
244 
245             auto counterLock = std::unique_lock(mCounterLock);
246             mCounterCondVar.wait(counterLock, [this] { return mSuspendCounter == 0; });
247             // The mutex is locked and *MUST* remain locked until we write to /sys/power/state.
248             // Otherwise, a WakeLock might be acquired after we check mSuspendCounter and before we
249             // write to /sys/power/state.
250 
251             if (!WriteStringToFd(wakeupCount, mWakeupCountFd)) {
252                 PLOG(VERBOSE) << "error writing from /sys/power/wakeup_count";
253                 continue;
254             }
255             bool success = WriteStringToFd(kSleepState, mStateFd);
256             counterLock.unlock();
257 
258             if (!success) {
259                 PLOG(VERBOSE) << "error writing to /sys/power/state";
260             }
261 
262             mControlService->notifyWakeup(success);
263 
264             updateSleepTime(success);
265         }
266     });
267     autosuspendThread.detach();
268     LOG(INFO) << "automatic system suspend enabled";
269 }
270 
updateSleepTime(bool success)271 void SystemSuspend::updateSleepTime(bool success) {
272     static constexpr std::chrono::milliseconds kMaxSleepTime = 1min;
273     if (success) {
274         mSleepTime = mBaseSleepTime;
275         return;
276     }
277     // Double sleep time after each failure up to one minute.
278     mSleepTime = std::min(mSleepTime * 2, kMaxSleepTime);
279 }
280 
281 }  // namespace V1_0
282 }  // namespace suspend
283 }  // namespace system
284 }  // namespace android
285