1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "power_interface_impl.h"
17
18 #include <atomic>
19 #include <hdf_base.h>
20 #include <file_ex.h>
21 #include <iremote_object.h>
22 #include <iproxy_broker.h>
23 #include <sys/eventfd.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <unistd.h>
27 #include <chrono>
28 #include <condition_variable>
29 #include <mutex>
30 #include <cstdlib>
31 #include <thread>
32 #include "errors.h"
33 #include "hdf_sbuf.h"
34 #include "pubdef.h"
35 #include "securec.h"
36 #include "utils/hdf_log.h"
37 #include "hdf_device_desc.h"
38 #include "hdf_remote_service.h"
39 #include "unique_fd.h"
40
41 namespace OHOS {
42 namespace HDI {
43 namespace Power {
44 namespace V1_0 {
45 static constexpr const int32_t MAX_FILE_LENGTH = 32 * 1024 * 1024;
46 static constexpr const char * const SUSPEND_STATE = "mem";
47 static constexpr const char * const SUSPEND_STATE_PATH = "/sys/power/state";
48 static constexpr const char * const LOCK_PATH = "/sys/power/wake_lock";
49 static constexpr const char * const UNLOCK_PATH = "/sys/power/wake_unlock";
50 static constexpr const char * const WAKEUP_COUNT_PATH = "/sys/power/wakeup_count";
51 static std::chrono::milliseconds waitTime_(100); // {100ms};
52 static std::mutex g_mutex;
53 static std::mutex g_suspendMutex;
54 static std::condition_variable g_suspendCv;
55 static std::unique_ptr<std::thread> g_daemon;
56 static std::atomic_bool g_suspending;
57 static std::atomic_bool g_suspendRetry;
58 static sptr<IPowerHdiCallback> g_callback;
59 static UniqueFd wakeupCountFd;
60 static void AutoSuspendLoop();
61 static int32_t DoSuspend();
62 static void LoadStringFd(int32_t fd, std::string& content);
63 static std::string ReadWakeCount();
64 static bool WriteWakeCount(const std::string& count);
65 static void NotifyCallback(int code);
66 namespace {
67 sptr<PowerInterfaceImpl::PowerDeathRecipient> g_deathRecipient = nullptr;
68 bool g_isHdiStart = false;
69 }
70
PowerInterfaceImplGetInstance(void)71 extern "C" IPowerInterface *PowerInterfaceImplGetInstance(void)
72 {
73 return new (std::nothrow) PowerInterfaceImpl();
74 }
75
RegisterCallback(const sptr<IPowerHdiCallback> & ipowerHdiCallback)76 int32_t PowerInterfaceImpl::RegisterCallback(const sptr<IPowerHdiCallback>& ipowerHdiCallback)
77 {
78 std::lock_guard<std::mutex> lock(g_mutex);
79 if (!g_isHdiStart) {
80 g_callback = ipowerHdiCallback;
81 if (g_callback == nullptr) {
82 UnRegister();
83 return HDF_SUCCESS;
84 }
85 g_deathRecipient = new PowerDeathRecipient(this);
86 if (g_deathRecipient == nullptr) {
87 return HDF_FAILURE;
88 }
89 AddPowerDeathRecipient(g_callback);
90 g_isHdiStart = true;
91 }
92 return HDF_SUCCESS;
93 }
94
UnRegister()95 int32_t PowerInterfaceImpl::UnRegister()
96 {
97 HDF_LOGI("UnRegister");
98 RemovePowerDeathRecipient(g_callback);
99 g_callback = nullptr;
100 return HDF_SUCCESS;
101 }
102
StartSuspend()103 int32_t PowerInterfaceImpl::StartSuspend()
104 {
105 std::lock_guard<std::mutex> lock(g_mutex);
106 g_suspendRetry = true;
107 if (g_suspending) {
108 g_suspendCv.notify_one();
109 return HDF_SUCCESS;
110 }
111 g_suspending = true;
112 g_daemon = std::make_unique<std::thread>(&AutoSuspendLoop);
113 g_daemon->detach();
114 return HDF_SUCCESS;
115 }
116
AutoSuspendLoop()117 void AutoSuspendLoop()
118 {
119 auto suspendLock = std::unique_lock(g_suspendMutex);
120 while (true) {
121 std::this_thread::sleep_for(waitTime_);
122
123 const std::string wakeupCount = ReadWakeCount();
124 if (wakeupCount.empty()) {
125 continue;
126 }
127 if (!g_suspendRetry) {
128 g_suspendCv.wait(suspendLock);
129 }
130 if (!WriteWakeCount(wakeupCount)) {
131 continue;
132 }
133
134 NotifyCallback(CMD_ON_SUSPEND);
135 DoSuspend();
136 NotifyCallback(CMD_ON_WAKEUP);
137 }
138 g_suspending = false;
139 g_suspendRetry = false;
140 }
141
DoSuspend()142 int32_t DoSuspend()
143 {
144 std::lock_guard<std::mutex> lock(g_mutex);
145 UniqueFd suspendStateFd(TEMP_FAILURE_RETRY(open(SUSPEND_STATE_PATH, O_RDWR | O_CLOEXEC)));
146 if (suspendStateFd < 0) {
147 return HDF_FAILURE;
148 }
149 bool ret = false;
150 do {
151 ret = SaveStringToFd(suspendStateFd, SUSPEND_STATE);
152 } while (!ret && (errno == EINTR || errno == EBUSY));
153
154 if (!ret) {
155 return HDF_FAILURE;
156 }
157 return HDF_SUCCESS;
158 }
159
NotifyCallback(int code)160 void NotifyCallback(int code)
161 {
162 if (g_callback == nullptr) {
163 return;
164 }
165 switch (code) {
166 case CMD_ON_SUSPEND:
167 g_callback->OnSuspend();
168 break;
169 case CMD_ON_WAKEUP:
170 g_callback->OnWakeup();
171 break;
172 }
173 }
174
StopSuspend()175 int32_t PowerInterfaceImpl::StopSuspend()
176 {
177 g_suspendRetry = false;
178
179 return HDF_SUCCESS;
180 }
181
ForceSuspend()182 int32_t PowerInterfaceImpl::ForceSuspend()
183 {
184 g_suspendRetry = false;
185
186 NotifyCallback(CMD_ON_SUSPEND);
187 DoSuspend();
188 NotifyCallback(CMD_ON_WAKEUP);
189 return HDF_SUCCESS;
190 }
191
SuspendBlock(const std::string & name)192 int32_t PowerInterfaceImpl::SuspendBlock(const std::string& name)
193 {
194 std::lock_guard<std::mutex> lock(g_mutex);
195 if (name.empty()) {
196 return HDF_ERR_INVALID_PARAM;
197 }
198 UniqueFd fd(TEMP_FAILURE_RETRY(open(LOCK_PATH, O_RDWR | O_CLOEXEC)));
199 bool ret = SaveStringToFd(fd, name);
200 if (!ret) {
201 return HDF_FAILURE;
202 }
203 return HDF_SUCCESS;
204 }
205
SuspendUnblock(const std::string & name)206 int32_t PowerInterfaceImpl::SuspendUnblock(const std::string& name)
207 {
208 std::lock_guard<std::mutex> lock(g_mutex);
209 if (name.empty()) {
210 return HDF_ERR_INVALID_PARAM;
211 }
212 UniqueFd fd(TEMP_FAILURE_RETRY(open(UNLOCK_PATH, O_RDWR | O_CLOEXEC)));
213 bool ret = SaveStringToFd(fd, name);
214 if (!ret) {
215 return HDF_FAILURE;
216 }
217 return HDF_SUCCESS;
218 }
219
AddPowerDeathRecipient(const sptr<IPowerHdiCallback> & callback)220 int32_t PowerInterfaceImpl::AddPowerDeathRecipient(const sptr<IPowerHdiCallback> &callback)
221 {
222 HDF_LOGI("AddPowerDeathRecipient");
223 const sptr<IRemoteObject> &remote = OHOS::HDI::hdi_objcast<IPowerHdiCallback>(callback);
224 bool result = remote->AddDeathRecipient(g_deathRecipient);
225 if (!result) {
226 HDF_LOGI("AddPowerDeathRecipient fail");
227 return HDF_FAILURE;
228 }
229 return HDF_SUCCESS;
230 }
231
RemovePowerDeathRecipient(const sptr<IPowerHdiCallback> & callback)232 int32_t PowerInterfaceImpl::RemovePowerDeathRecipient(const sptr<IPowerHdiCallback> &callback)
233 {
234 HDF_LOGI("RemovePowerDeathRecipient");
235 const sptr<IRemoteObject> &remote = OHOS::HDI::hdi_objcast<IPowerHdiCallback>(callback);
236 bool result = remote->RemoveDeathRecipient(g_deathRecipient);
237 if (!result) {
238 HDF_LOGI("RemovePowerDeathRecipient fail");
239 return HDF_FAILURE;
240 }
241 return HDF_SUCCESS;
242 }
243
OnRemoteDied(const wptr<IRemoteObject> & object)244 void PowerInterfaceImpl::PowerDeathRecipient::OnRemoteDied(const wptr<IRemoteObject> &object)
245 {
246 powerInterfaceImpl_->UnRegister();
247 }
248
LoadStringFd(int32_t fd,std::string & content)249 void LoadStringFd(int32_t fd, std::string& content)
250 {
251 if (fd <= 0) {
252 HDF_LOGW("invalid fd: %{public}d", fd);
253 return;
254 }
255
256 const int32_t fileLength = lseek(fd, 0, SEEK_END);
257 if (fileLength > MAX_FILE_LENGTH || fileLength <= 0) {
258 HDF_LOGW("invalid file length(%{public}d)!", fileLength);
259 return;
260 }
261 int32_t loc = lseek(fd, 0, SEEK_SET);
262 if (loc == -1) {
263 HDF_LOGE("lseek file to begin failed!");
264 return;
265 }
266 content.resize(fileLength);
267 const int32_t len = static_cast<int32_t>(read(fd, content.data(), fileLength));
268 if (len <= 0) {
269 HDF_LOGW("the length read from file is failed, len: %{public}d, fileLen: %{public}d",
270 len, fileLength);
271 content.clear();
272 }
273 }
274
ReadWakeCount()275 std::string ReadWakeCount()
276 {
277 if (wakeupCountFd < 0) {
278 wakeupCountFd = UniqueFd(TEMP_FAILURE_RETRY(open(WAKEUP_COUNT_PATH, O_RDWR | O_CLOEXEC)));
279 }
280 std::string wakeupCount;
281 LoadStringFd(wakeupCountFd, wakeupCount);
282
283 return wakeupCount;
284 }
285
WriteWakeCount(const std::string & count)286 bool WriteWakeCount(const std::string& count)
287 {
288 if (wakeupCountFd < 0) {
289 wakeupCountFd = UniqueFd(TEMP_FAILURE_RETRY(open(WAKEUP_COUNT_PATH, O_RDWR | O_CLOEXEC)));
290 }
291 bool ret = SaveStringToFd(wakeupCountFd, count.c_str());
292 return ret;
293 }
294
LoadSystemInfo(const std::string & path,std::string & info)295 static void LoadSystemInfo(const std::string& path, std::string& info)
296 {
297 UniqueFd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDWR | O_CLOEXEC)));
298 std::string str;
299 if (fd >= 0) {
300 bool ret = LoadStringFromFd(fd, str);
301 if (!ret) {
302 str = "# Failed to read";
303 }
304 } else {
305 str = "# Failed to open";
306 }
307 info.append(path);
308 info.append(": " + str + "\n");
309 }
310
PowerDump(std::string & info)311 int32_t PowerInterfaceImpl::PowerDump(std::string& info)
312 {
313 std::string dumpInfo("");
314 LoadSystemInfo(SUSPEND_STATE_PATH, dumpInfo);
315 LoadSystemInfo(WAKEUP_COUNT_PATH, dumpInfo);
316 LoadSystemInfo(LOCK_PATH, dumpInfo);
317 LoadSystemInfo(UNLOCK_PATH, dumpInfo);
318 info = dumpInfo;
319
320 return HDF_SUCCESS;
321 }
322 } // V1_0
323 } // Power
324 } // HDI
325 } // OHOS
326