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 "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 namespace OHOS {
44 namespace HDI {
45 namespace Power {
46 namespace V1_1 {
47 static constexpr const int32_t MAX_FILE_LENGTH = 32 * 1024 * 1024;
48 static constexpr const char * const SUSPEND_STATE = "mem";
49 static constexpr const char * const SUSPEND_STATE_PATH = "/sys/power/state";
50 static constexpr const char * const LOCK_PATH = "/sys/power/wake_lock";
51 static constexpr const char * const UNLOCK_PATH = "/sys/power/wake_unlock";
52 static constexpr const char * const WAKEUP_COUNT_PATH = "/sys/power/wakeup_count";
53 static std::chrono::milliseconds waitTime_(100); // {100ms};
54 static std::mutex g_mutex;
55 static std::mutex g_suspendMutex;
56 static std::condition_variable g_suspendCv;
57 static std::unique_ptr<std::thread> g_daemon;
58 static std::atomic_bool g_suspending;
59 static std::atomic_bool g_suspendRetry;
60 static sptr<IPowerHdiCallback> g_callback;
61 static UniqueFd wakeupCountFd;
62 static PowerHdfState g_powerState {PowerHdfState::AWAKE};
63 static void AutoSuspendLoop();
64 static int32_t DoSuspend();
65 static void LoadStringFd(int32_t fd, std::string &content);
66 static std::string ReadWakeCount();
67 static bool WriteWakeCount(const std::string &count);
68 static void NotifyCallback(int code);
69 namespace {
70 sptr<PowerInterfaceImpl::PowerDeathRecipient> g_deathRecipient = nullptr;
71 bool g_isHdiStart = false;
72 } // namespace
73
PowerInterfaceImplGetInstance(void)74 extern "C" IPowerInterface *PowerInterfaceImplGetInstance(void)
75 {
76 return new (std::nothrow) PowerInterfaceImpl();
77 }
78
RegisterCallback(const sptr<IPowerHdiCallback> & ipowerHdiCallback)79 int32_t PowerInterfaceImpl::RegisterCallback(const sptr<IPowerHdiCallback> &ipowerHdiCallback)
80 {
81 std::lock_guard<std::mutex> lock(g_mutex);
82 if (!g_isHdiStart) {
83 g_callback = ipowerHdiCallback;
84 if (g_callback == nullptr) {
85 UnRegister();
86 return HDF_SUCCESS;
87 }
88 g_deathRecipient = new PowerDeathRecipient(this);
89 if (g_deathRecipient == nullptr) {
90 return HDF_FAILURE;
91 }
92 AddPowerDeathRecipient(g_callback);
93 g_isHdiStart = true;
94 }
95 return HDF_SUCCESS;
96 }
97
UnRegister()98 int32_t PowerInterfaceImpl::UnRegister()
99 {
100 HDF_LOGI("UnRegister");
101 RemovePowerDeathRecipient(g_callback);
102 g_callback = nullptr;
103 g_isHdiStart = false;
104 return HDF_SUCCESS;
105 }
106
StartSuspend()107 int32_t PowerInterfaceImpl::StartSuspend()
108 {
109 std::lock_guard<std::mutex> lock(g_mutex);
110 g_suspendRetry = true;
111 if (g_suspending) {
112 g_powerState = PowerHdfState::INACTIVE;
113 g_suspendCv.notify_one();
114 return HDF_SUCCESS;
115 }
116 g_suspending = true;
117 g_daemon = std::make_unique<std::thread>(&AutoSuspendLoop);
118 g_daemon->detach();
119 return HDF_SUCCESS;
120 }
121
AutoSuspendLoop()122 void AutoSuspendLoop()
123 {
124 auto suspendLock = std::unique_lock(g_suspendMutex);
125 while (true) {
126 std::this_thread::sleep_for(waitTime_);
127
128 const std::string wakeupCount = ReadWakeCount();
129 if (wakeupCount.empty()) {
130 continue;
131 }
132 if (!g_suspendRetry) {
133 g_suspendCv.wait(suspendLock);
134 }
135 if (!WriteWakeCount(wakeupCount)) {
136 continue;
137 }
138
139 NotifyCallback(CMD_ON_SUSPEND);
140 g_powerState = PowerHdfState::SLEEP;
141 DoSuspend();
142 g_powerState = PowerHdfState::AWAKE;
143 NotifyCallback(CMD_ON_WAKEUP);
144 }
145 g_suspending = false;
146 g_suspendRetry = false;
147 }
148
DoSuspend()149 int32_t DoSuspend()
150 {
151 std::lock_guard<std::mutex> lock(g_mutex);
152 UniqueFd suspendStateFd(TEMP_FAILURE_RETRY(open(SUSPEND_STATE_PATH, O_RDWR | O_CLOEXEC)));
153 if (suspendStateFd < 0) {
154 return HDF_FAILURE;
155 }
156 bool ret = SaveStringToFd(suspendStateFd, SUSPEND_STATE);
157 if (!ret) {
158 HDF_LOGE("DoSuspend fail");
159 return HDF_FAILURE;
160 }
161 return HDF_SUCCESS;
162 }
163
NotifyCallback(int code)164 void NotifyCallback(int code)
165 {
166 if (g_callback == nullptr) {
167 return;
168 }
169 switch (code) {
170 case CMD_ON_SUSPEND:
171 g_callback->OnSuspend();
172 break;
173 case CMD_ON_WAKEUP:
174 g_callback->OnWakeup();
175 break;
176 default:
177 break;
178 }
179 }
180
StopSuspend()181 int32_t PowerInterfaceImpl::StopSuspend()
182 {
183 g_suspendRetry = false;
184 g_powerState = PowerHdfState::AWAKE;
185 return HDF_SUCCESS;
186 }
187
ForceSuspend()188 int32_t PowerInterfaceImpl::ForceSuspend()
189 {
190 g_suspendRetry = false;
191
192 NotifyCallback(CMD_ON_SUSPEND);
193 g_powerState = PowerHdfState::SLEEP;
194 DoSuspend();
195 g_powerState = PowerHdfState::AWAKE;
196 NotifyCallback(CMD_ON_WAKEUP);
197 return HDF_SUCCESS;
198 }
199
SuspendBlock(const std::string & name)200 int32_t PowerInterfaceImpl::SuspendBlock(const std::string &name)
201 {
202 std::lock_guard<std::mutex> lock(g_mutex);
203 if (name.empty()) {
204 return HDF_ERR_INVALID_PARAM;
205 }
206 UniqueFd fd(TEMP_FAILURE_RETRY(open(LOCK_PATH, O_RDWR | O_CLOEXEC)));
207 bool ret = SaveStringToFd(fd, name);
208 if (!ret) {
209 return HDF_FAILURE;
210 }
211 return HDF_SUCCESS;
212 }
213
SuspendUnblock(const std::string & name)214 int32_t PowerInterfaceImpl::SuspendUnblock(const std::string &name)
215 {
216 std::lock_guard<std::mutex> lock(g_mutex);
217 if (name.empty()) {
218 return HDF_ERR_INVALID_PARAM;
219 }
220 UniqueFd fd(TEMP_FAILURE_RETRY(open(UNLOCK_PATH, O_RDWR | O_CLOEXEC)));
221 bool ret = SaveStringToFd(fd, name);
222 if (!ret) {
223 return HDF_FAILURE;
224 }
225 return HDF_SUCCESS;
226 }
227
AddPowerDeathRecipient(const sptr<IPowerHdiCallback> & callback)228 int32_t PowerInterfaceImpl::AddPowerDeathRecipient(const sptr<IPowerHdiCallback> &callback)
229 {
230 HDF_LOGI("AddPowerDeathRecipient");
231 const sptr<IRemoteObject> &remote = OHOS::HDI::hdi_objcast<IPowerHdiCallback>(callback);
232 bool result = remote->AddDeathRecipient(g_deathRecipient);
233 if (!result) {
234 HDF_LOGI("AddPowerDeathRecipient fail");
235 return HDF_FAILURE;
236 }
237 return HDF_SUCCESS;
238 }
239
RemovePowerDeathRecipient(const sptr<IPowerHdiCallback> & callback)240 int32_t PowerInterfaceImpl::RemovePowerDeathRecipient(const sptr<IPowerHdiCallback> &callback)
241 {
242 HDF_LOGI("RemovePowerDeathRecipient");
243 const sptr<IRemoteObject> &remote = OHOS::HDI::hdi_objcast<IPowerHdiCallback>(callback);
244 bool result = remote->RemoveDeathRecipient(g_deathRecipient);
245 if (!result) {
246 HDF_LOGI("RemovePowerDeathRecipient fail");
247 return HDF_FAILURE;
248 }
249 return HDF_SUCCESS;
250 }
251
OnRemoteDied(const wptr<IRemoteObject> & object)252 void PowerInterfaceImpl::PowerDeathRecipient::OnRemoteDied(const wptr<IRemoteObject> &object)
253 {
254 powerInterfaceImpl_->UnRegister();
255 }
256
LoadStringFd(int32_t fd,std::string & content)257 void LoadStringFd(int32_t fd, std::string &content)
258 {
259 if (fd <= 0) {
260 HDF_LOGW("invalid fd: %{public}d", fd);
261 return;
262 }
263
264 const int32_t fileLength = lseek(fd, 0, SEEK_END);
265 if (fileLength > MAX_FILE_LENGTH || fileLength <= 0) {
266 HDF_LOGW("invalid file length(%{public}d)!", fileLength);
267 return;
268 }
269 int32_t loc = lseek(fd, 0, SEEK_SET);
270 if (loc == -1) {
271 HDF_LOGE("lseek file to begin failed!");
272 return;
273 }
274 content.resize(fileLength);
275 const int32_t len = static_cast<int32_t>(read(fd, content.data(), fileLength));
276 if (len <= 0) {
277 HDF_LOGW("the length read from file is failed, len: %{public}d, fileLen: %{public}d", len, fileLength);
278 content.clear();
279 }
280 }
281
ReadWakeCount()282 std::string ReadWakeCount()
283 {
284 if (wakeupCountFd < 0) {
285 wakeupCountFd = UniqueFd(TEMP_FAILURE_RETRY(open(WAKEUP_COUNT_PATH, O_RDWR | O_CLOEXEC)));
286 }
287 std::string wakeupCount;
288 LoadStringFd(wakeupCountFd, wakeupCount);
289
290 return wakeupCount;
291 }
292
WriteWakeCount(const std::string & count)293 bool WriteWakeCount(const std::string &count)
294 {
295 if (wakeupCountFd < 0) {
296 wakeupCountFd = UniqueFd(TEMP_FAILURE_RETRY(open(WAKEUP_COUNT_PATH, O_RDWR | O_CLOEXEC)));
297 }
298 bool ret = SaveStringToFd(wakeupCountFd, count.c_str());
299 return ret;
300 }
301
LoadSystemInfo(const std::string & path,std::string & info)302 static void LoadSystemInfo(const std::string &path, std::string &info)
303 {
304 UniqueFd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDWR | O_CLOEXEC)));
305 std::string str;
306 if (fd >= 0) {
307 bool ret = LoadStringFromFd(fd, str);
308 if (!ret) {
309 str = "# Failed to read";
310 }
311 } else {
312 str = "# Failed to open";
313 }
314 info.append(path);
315 info.append(": " + str + "\n");
316 }
317
PowerDump(std::string & info)318 int32_t PowerInterfaceImpl::PowerDump(std::string &info)
319 {
320 std::string dumpInfo("");
321 LoadSystemInfo(SUSPEND_STATE_PATH, dumpInfo);
322 LoadSystemInfo(LOCK_PATH, dumpInfo);
323 LoadSystemInfo(UNLOCK_PATH, dumpInfo);
324 info = dumpInfo;
325
326 return HDF_SUCCESS;
327 }
328
HoldRunningLock(const RunningLockInfo & info)329 int32_t PowerInterfaceImpl::HoldRunningLock(const RunningLockInfo &info)
330 {
331 return RunningLockImpl::Hold(info, g_powerState);
332 }
333
UnholdRunningLock(const RunningLockInfo & info)334 int32_t PowerInterfaceImpl::UnholdRunningLock(const RunningLockInfo &info)
335 {
336 return RunningLockImpl::Unhold(info);
337 }
338 } // namespace V1_1
339 } // namespace Power
340 } // namespace HDI
341 } // namespace OHOS
342