1 /*
2 * Copyright (c) 2022-2023 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 "errors.h"
19 #include "hdf_device_desc.h"
20 #include "hdf_remote_service.h"
21 #include "hdf_sbuf.h"
22 #include "pubdef.h"
23 #include "running_lock_impl.h"
24 #include "securec.h"
25 #include "unique_fd.h"
26 #include "power_hdf_log.h"
27 #include "v1_1/power_types.h"
28 #include <atomic>
29 #include <chrono>
30 #include <condition_variable>
31 #include <cstdlib>
32 #include <file_ex.h>
33 #include <hdf_base.h>
34 #include <iproxy_broker.h>
35 #include <iremote_object.h>
36 #include <mutex>
37 #include <sys/eventfd.h>
38 #include <sys/stat.h>
39 #include <sys/types.h>
40 #include <thread>
41 #include <unistd.h>
42
43 #ifdef DRIVER_PERIPHERAL_POWER_WAKEUP_CAUSE_PATH
44 #include "power_config.h"
45 #endif
46
47 namespace OHOS {
48 namespace HDI {
49 namespace Power {
50 namespace V1_1 {
51 static constexpr const int32_t MAX_FILE_LENGTH = 32 * 1024 * 1024;
52 static constexpr const char * const SUSPEND_STATE = "mem";
53 static constexpr const char * const SUSPEND_STATE_PATH = "/sys/power/state";
54 static constexpr const char * const LOCK_PATH = "/sys/power/wake_lock";
55 static constexpr const char * const UNLOCK_PATH = "/sys/power/wake_unlock";
56 static constexpr const char * const WAKEUP_COUNT_PATH = "/sys/power/wakeup_count";
57 static std::chrono::milliseconds waitTime_(1000); // {1000ms};
58 static std::mutex g_mutex;
59 static std::mutex g_suspendMutex;
60 static std::mutex g_forceMutex;
61 static std::condition_variable g_suspendCv;
62 static std::unique_ptr<std::thread> g_daemon;
63 static std::atomic_bool g_suspending;
64 static std::atomic_bool g_suspendRetry;
65 static std::atomic_bool g_forceSuspendStart;
66 static sptr<IPowerHdiCallback> g_callback;
67 static UniqueFd wakeupCountFd;
68 static PowerHdfState g_powerState {PowerHdfState::AWAKE};
69 static void AutoSuspendLoop();
70 static int32_t DoSuspend();
71 static void LoadStringFd(int32_t fd, std::string &content);
72 static std::string ReadWakeCount();
73 static bool WriteWakeCount(const std::string &count);
74 static void NotifyCallback(int code);
75 namespace {
76 sptr<PowerInterfaceImpl::PowerDeathRecipient> g_deathRecipient = nullptr;
77 bool g_isHdiStart = false;
78 } // namespace
79
PowerInterfaceImplGetInstance(void)80 extern "C" IPowerInterface *PowerInterfaceImplGetInstance(void)
81 {
82 using OHOS::HDI::Power::V1_1::PowerInterfaceImpl;
83 PowerInterfaceImpl *service = new (std::nothrow) PowerInterfaceImpl();
84 if (service == nullptr) {
85 return nullptr;
86 }
87
88 if (service->Init() != HDF_SUCCESS) {
89 delete service;
90 return nullptr;
91 }
92 return service;
93 }
94
Init()95 int32_t PowerInterfaceImpl::Init()
96 {
97 #ifdef DRIVER_PERIPHERAL_POWER_WAKEUP_CAUSE_PATH
98 auto& powerConfig = PowerConfig::GetInstance();
99 powerConfig.ParseConfig();
100 #endif
101 return HDF_SUCCESS;
102 }
103
RegisterCallback(const sptr<IPowerHdiCallback> & ipowerHdiCallback)104 int32_t PowerInterfaceImpl::RegisterCallback(const sptr<IPowerHdiCallback> &ipowerHdiCallback)
105 {
106 std::lock_guard<std::mutex> lock(g_mutex);
107 if (!g_isHdiStart) {
108 g_callback = ipowerHdiCallback;
109 if (g_callback == nullptr) {
110 UnRegister();
111 return HDF_SUCCESS;
112 }
113 g_deathRecipient = new PowerDeathRecipient(this);
114 if (g_deathRecipient == nullptr) {
115 return HDF_FAILURE;
116 }
117 AddPowerDeathRecipient(g_callback);
118 g_isHdiStart = true;
119 }
120
121 return HDF_SUCCESS;
122 }
123
UnRegister()124 int32_t PowerInterfaceImpl::UnRegister()
125 {
126 HDF_LOGI("UnRegister");
127 RemovePowerDeathRecipient(g_callback);
128 g_callback = nullptr;
129 g_isHdiStart = false;
130 return HDF_SUCCESS;
131 }
132
StartSuspend()133 int32_t PowerInterfaceImpl::StartSuspend()
134 {
135 HDF_LOGI("start suspend");
136 std::lock_guard<std::mutex> lock(g_mutex);
137 g_suspendRetry = true;
138 if (g_suspending) {
139 g_powerState = PowerHdfState::INACTIVE;
140 g_suspendCv.notify_one();
141 return HDF_SUCCESS;
142 }
143 g_suspending = true;
144 g_daemon = std::make_unique<std::thread>(&AutoSuspendLoop);
145 g_daemon->detach();
146 return HDF_SUCCESS;
147 }
148
AutoSuspendLoop()149 void AutoSuspendLoop()
150 {
151 auto suspendLock = std::unique_lock(g_suspendMutex);
152 while (true) {
153 std::this_thread::sleep_for(waitTime_);
154
155 const std::string wakeupCount = ReadWakeCount();
156 if (wakeupCount.empty()) {
157 continue;
158 }
159 if (!g_suspendRetry) {
160 g_suspendCv.wait(suspendLock);
161 }
162 if (!WriteWakeCount(wakeupCount)) {
163 continue;
164 }
165
166 NotifyCallback(CMD_ON_SUSPEND);
167 g_powerState = PowerHdfState::SLEEP;
168 DoSuspend();
169 g_powerState = PowerHdfState::AWAKE;
170 NotifyCallback(CMD_ON_WAKEUP);
171 }
172 g_suspending = false;
173 g_suspendRetry = false;
174 }
175
DoSuspend()176 int32_t DoSuspend()
177 {
178 std::lock_guard<std::mutex> lock(g_mutex);
179 UniqueFd suspendStateFd(TEMP_FAILURE_RETRY(open(SUSPEND_STATE_PATH, O_RDWR | O_CLOEXEC)));
180 if (suspendStateFd < 0) {
181 return HDF_FAILURE;
182 }
183 bool ret = SaveStringToFd(suspendStateFd, SUSPEND_STATE);
184 if (!ret) {
185 HDF_LOGE("DoSuspend fail");
186 return HDF_FAILURE;
187 }
188 return HDF_SUCCESS;
189 }
190
NotifyCallback(int code)191 void NotifyCallback(int code)
192 {
193 if (g_callback == nullptr) {
194 return;
195 }
196 switch (code) {
197 case CMD_ON_SUSPEND:
198 g_callback->OnSuspend();
199 break;
200 case CMD_ON_WAKEUP:
201 g_callback->OnWakeup();
202 break;
203 default:
204 break;
205 }
206 }
207
StopSuspend()208 int32_t PowerInterfaceImpl::StopSuspend()
209 {
210 HDF_LOGI("stop suspend");
211 std::lock_guard<std::mutex> lock(g_forceMutex);
212 g_forceSuspendStart = false;
213 g_suspendRetry = false;
214 g_powerState = PowerHdfState::AWAKE;
215 return HDF_SUCCESS;
216 }
217
ForceSuspend()218 int32_t PowerInterfaceImpl::ForceSuspend()
219 {
220 HDF_LOGI("force suspend");
221 {
222 std::lock_guard<std::mutex> lock(g_forceMutex);
223 g_forceSuspendStart = true;
224 g_suspendRetry = false;
225 }
226
227 NotifyCallback(CMD_ON_SUSPEND);
228 g_powerState = PowerHdfState::SLEEP;
229 DoSuspend();
230 g_powerState = PowerHdfState::AWAKE;
231 NotifyCallback(CMD_ON_WAKEUP);
232
233 std::lock_guard<std::mutex> lock(g_forceMutex);
234 if (g_forceSuspendStart) {
235 StartSuspend();
236 }
237 return HDF_SUCCESS;
238 }
239
SuspendBlock(const std::string & name)240 int32_t PowerInterfaceImpl::SuspendBlock(const std::string &name)
241 {
242 std::lock_guard<std::mutex> lock(g_mutex);
243 if (name.empty()) {
244 return HDF_ERR_INVALID_PARAM;
245 }
246 UniqueFd fd(TEMP_FAILURE_RETRY(open(LOCK_PATH, O_RDWR | O_CLOEXEC)));
247 bool ret = SaveStringToFd(fd, name);
248 if (!ret) {
249 return HDF_FAILURE;
250 }
251 return HDF_SUCCESS;
252 }
253
SuspendUnblock(const std::string & name)254 int32_t PowerInterfaceImpl::SuspendUnblock(const std::string &name)
255 {
256 std::lock_guard<std::mutex> lock(g_mutex);
257 if (name.empty()) {
258 return HDF_ERR_INVALID_PARAM;
259 }
260 UniqueFd fd(TEMP_FAILURE_RETRY(open(UNLOCK_PATH, O_RDWR | O_CLOEXEC)));
261 bool ret = SaveStringToFd(fd, name);
262 if (!ret) {
263 return HDF_FAILURE;
264 }
265 return HDF_SUCCESS;
266 }
267
AddPowerDeathRecipient(const sptr<IPowerHdiCallback> & callback)268 int32_t PowerInterfaceImpl::AddPowerDeathRecipient(const sptr<IPowerHdiCallback> &callback)
269 {
270 HDF_LOGI("AddPowerDeathRecipient");
271 const sptr<IRemoteObject> &remote = OHOS::HDI::hdi_objcast<IPowerHdiCallback>(callback);
272 bool result = remote->AddDeathRecipient(g_deathRecipient);
273 if (!result) {
274 HDF_LOGI("AddPowerDeathRecipient fail");
275 return HDF_FAILURE;
276 }
277 return HDF_SUCCESS;
278 }
279
RemovePowerDeathRecipient(const sptr<IPowerHdiCallback> & callback)280 int32_t PowerInterfaceImpl::RemovePowerDeathRecipient(const sptr<IPowerHdiCallback> &callback)
281 {
282 HDF_LOGI("RemovePowerDeathRecipient");
283 const sptr<IRemoteObject> &remote = OHOS::HDI::hdi_objcast<IPowerHdiCallback>(callback);
284 bool result = remote->RemoveDeathRecipient(g_deathRecipient);
285 if (!result) {
286 HDF_LOGI("RemovePowerDeathRecipient fail");
287 return HDF_FAILURE;
288 }
289 return HDF_SUCCESS;
290 }
291
OnRemoteDied(const wptr<IRemoteObject> & object)292 void PowerInterfaceImpl::PowerDeathRecipient::OnRemoteDied(const wptr<IRemoteObject> &object)
293 {
294 HDF_LOGI("PowerDeathRecipient OnRemoteDied");
295 powerInterfaceImpl_->UnRegister();
296 RunningLockImpl::Clean();
297 }
298
LoadStringFd(int32_t fd,std::string & content)299 void LoadStringFd(int32_t fd, std::string &content)
300 {
301 if (fd <= 0) {
302 HDF_LOGW("invalid fd: %{public}d", fd);
303 return;
304 }
305
306 const int32_t fileLength = lseek(fd, 0, SEEK_END);
307 if (fileLength > MAX_FILE_LENGTH || fileLength <= 0) {
308 HDF_LOGW("invalid file length(%{public}d)!", fileLength);
309 return;
310 }
311 int32_t loc = lseek(fd, 0, SEEK_SET);
312 if (loc == -1) {
313 HDF_LOGE("lseek file to begin failed!");
314 return;
315 }
316 content.resize(fileLength);
317 const int32_t len = static_cast<int32_t>(read(fd, content.data(), fileLength));
318 if (len <= 0) {
319 HDF_LOGW("the length read from file is failed, len: %{public}d, fileLen: %{public}d", len, fileLength);
320 content.clear();
321 }
322 }
323
ReadWakeCount()324 std::string ReadWakeCount()
325 {
326 if (wakeupCountFd < 0) {
327 wakeupCountFd = UniqueFd(TEMP_FAILURE_RETRY(open(WAKEUP_COUNT_PATH, O_RDWR | O_CLOEXEC)));
328 }
329 std::string wakeupCount;
330 LoadStringFd(wakeupCountFd, wakeupCount);
331
332 return wakeupCount;
333 }
334
WriteWakeCount(const std::string & count)335 bool WriteWakeCount(const std::string &count)
336 {
337 if (wakeupCountFd < 0) {
338 wakeupCountFd = UniqueFd(TEMP_FAILURE_RETRY(open(WAKEUP_COUNT_PATH, O_RDWR | O_CLOEXEC)));
339 }
340 bool ret = SaveStringToFd(wakeupCountFd, count.c_str());
341 return ret;
342 }
343
LoadSystemInfo(const std::string & path,std::string & info)344 static void LoadSystemInfo(const std::string &path, std::string &info)
345 {
346 UniqueFd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDWR | O_CLOEXEC)));
347 std::string str;
348 if (fd >= 0) {
349 bool ret = LoadStringFromFd(fd, str);
350 if (!ret) {
351 str = "# Failed to read";
352 }
353 } else {
354 str = "# Failed to open";
355 }
356 info.append(path);
357 info.append(": " + str + "\n");
358 }
359
PowerDump(std::string & info)360 int32_t PowerInterfaceImpl::PowerDump(std::string &info)
361 {
362 std::string dumpInfo("");
363 LoadSystemInfo(SUSPEND_STATE_PATH, dumpInfo);
364 LoadSystemInfo(LOCK_PATH, dumpInfo);
365 LoadSystemInfo(UNLOCK_PATH, dumpInfo);
366 info = dumpInfo;
367
368 return HDF_SUCCESS;
369 }
370
HoldRunningLock(const RunningLockInfo & info)371 int32_t PowerInterfaceImpl::HoldRunningLock(const RunningLockInfo &info)
372 {
373 return RunningLockImpl::Hold(info, g_powerState);
374 }
375
UnholdRunningLock(const RunningLockInfo & info)376 int32_t PowerInterfaceImpl::UnholdRunningLock(const RunningLockInfo &info)
377 {
378 return RunningLockImpl::Unhold(info);
379 }
380
GetWakeupReason(std::string & reason)381 int32_t PowerInterfaceImpl::GetWakeupReason(std::string &reason)
382 {
383 #ifdef DRIVER_PERIPHERAL_POWER_WAKEUP_CAUSE_PATH
384 auto& powerConfig = PowerConfig::GetInstance();
385 std::map<std::string, PowerConfig::PowerSceneConfig> sceneConfigMap= powerConfig.GetPowerSceneConfigMap();
386 std::map<std::string, PowerConfig::PowerSceneConfig>::iterator it = sceneConfigMap.find("wakeuo_cause");
387 if (it == sceneConfigMap.end()) {
388 HDF_LOGW("wakeuo_cause getPath does not exist");
389 return HDF_FAILURE;
390 }
391 std::string getPath = (it->second).getPath;
392 HDF_LOGI("getPath = %{public}s", getPath.c_str());
393
394 UniqueFd wakeupCauseFd(TEMP_FAILURE_RETRY(open(getPath.c_str(), O_RDONLY | O_CLOEXEC)));
395 if (wakeupCauseFd < 0) {
396 return HDF_FAILURE;
397 }
398 LoadStringFd(wakeupCauseFd, reason);
399 return HDF_SUCCESS;
400 #else
401 HDF_LOGW("wakrup cause path not config");
402 return HDF_FAILURE;
403 #endif
404 }
405 } // namespace V1_1
406 } // namespace Power
407 } // namespace HDI
408 } // namespace OHOS
409