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_napi.h"
17
18 #include "napi_errors.h"
19 #include "napi_utils.h"
20 #include "power_common.h"
21 #include "power_log.h"
22 #include "power_mgr_client.h"
23 #include <fcntl.h>
24 #include <sys/ioctl.h>
25 #include <unistd.h>
26 #include "app_manager_utils.h"
27
28 #define SET_REBOOT _IOW(BOOT_DETECTOR_IOCTL_BASE, 109, int)
29
30 namespace OHOS {
31 namespace PowerMgr {
32 namespace {
33 constexpr uint32_t REBOOT_SHUTDOWN_MAX_ARGC = 1;
34 constexpr uint32_t WAKEUP_MAX_ARGC = 1;
35 constexpr uint32_t SET_MODE_CALLBACK_MAX_ARGC = 2;
36 constexpr uint32_t SET_MODE_PROMISE_MAX_ARGC = 1;
37 constexpr uint32_t SUSPEND_MAX_ARGC = 1;
38 constexpr uint32_t SET_SCREEN_OFFTIME_ARGC = 1;
39 constexpr uint32_t HIBERNATE_ARGC = 1;
40 constexpr int32_t INDEX_0 = 0;
41 constexpr int32_t INDEX_1 = 1;
42 constexpr int32_t RESTORE_DEFAULT_SCREENOFF_TIME = -1;
43 static PowerMgrClient& g_powerMgrClient = PowerMgrClient::GetInstance();
44 } // namespace
Shutdown(napi_env env,napi_callback_info info)45 napi_value PowerNapi::Shutdown(napi_env env, napi_callback_info info)
46 {
47 return RebootOrShutdown(env, info, false);
48 }
49
Reboot(napi_env env,napi_callback_info info)50 napi_value PowerNapi::Reboot(napi_env env, napi_callback_info info)
51 {
52 return RebootOrShutdown(env, info, true);
53 }
54
IsActive(napi_env env,napi_callback_info info)55 napi_value PowerNapi::IsActive(napi_env env, napi_callback_info info)
56 {
57 bool isScreen = g_powerMgrClient.IsScreenOn();
58 napi_value napiValue;
59 NAPI_CALL(env, napi_get_boolean(env, isScreen, &napiValue));
60 return napiValue;
61 }
62
Wakeup(napi_env env,napi_callback_info info)63 napi_value PowerNapi::Wakeup(napi_env env, napi_callback_info info)
64 {
65 size_t argc = WAKEUP_MAX_ARGC;
66 napi_value argv[argc];
67 NapiUtils::GetCallbackInfo(env, info, argc, argv);
68
69 NapiErrors error;
70 if (argc != WAKEUP_MAX_ARGC || !NapiUtils::CheckValueType(env, argv[INDEX_0], napi_string)) {
71 return error.ThrowError(env, PowerErrors::ERR_PARAM_INVALID);
72 }
73
74 std::string detail = NapiUtils::GetStringFromNapi(env, argv[INDEX_0]);
75 POWER_HILOGD(FEATURE_WAKEUP, "Wakeup type: APPLICATION, reason: %{public}s", detail.c_str());
76 int32_t apiVersion = AppManagerUtils::GetApiTargetVersion();
77 PowerErrors code = g_powerMgrClient.WakeupDevice(
78 WakeupDeviceType::WAKEUP_DEVICE_APPLICATION, detail, std::to_string(apiVersion));
79 if (code != PowerErrors::ERR_OK) {
80 error.ThrowError(env, code);
81 }
82 return nullptr;
83 }
84
Suspend(napi_env env,napi_callback_info info)85 napi_value PowerNapi::Suspend(napi_env env, napi_callback_info info)
86 {
87 size_t argc = SUSPEND_MAX_ARGC;
88 napi_value argv[argc];
89 NapiUtils::GetCallbackInfo(env, info, argc, argv);
90
91 NapiErrors error;
92 if (argc != SUSPEND_MAX_ARGC || !NapiUtils::CheckValueType(env, argv[INDEX_0], napi_boolean)) {
93 if (!NapiUtils::CheckValueType(env, argv[INDEX_0], napi_undefined)) {
94 std::string detail = NapiUtils::GetStringFromNapi(env, argv[INDEX_0]);
95 if (!detail.empty()) {
96 return error.ThrowError(env, PowerErrors::ERR_PARAM_INVALID);
97 }
98 }
99 }
100
101 bool isForce = false;
102 napi_get_value_bool(env, argv[0], &isForce);
103
104 PowerErrors code;
105 int32_t apiVersion = AppManagerUtils::GetApiTargetVersion();
106 if (isForce) {
107 code = g_powerMgrClient.ForceSuspendDevice(std::to_string(apiVersion));
108 } else {
109 code = g_powerMgrClient.SuspendDevice(
110 SuspendDeviceType::SUSPEND_DEVICE_REASON_APPLICATION, false, std::to_string(apiVersion));
111 }
112 if (code != PowerErrors::ERR_OK) {
113 POWER_HILOGE(FEATURE_WAKEUP, "Suspend Device fail, isForce:%{public}d", isForce);
114 return error.ThrowError(env, code);
115 }
116 return nullptr;
117 }
118
Hibernate(napi_env env,napi_callback_info info)119 napi_value PowerNapi::Hibernate(napi_env env, napi_callback_info info)
120 {
121 size_t argc = HIBERNATE_ARGC;
122 napi_value argv[argc];
123 NapiUtils::GetCallbackInfo(env, info, argc, argv);
124
125 NapiErrors error;
126 if (argc != HIBERNATE_ARGC || !NapiUtils::CheckValueType(env, argv[INDEX_0], napi_boolean)) {
127 if (!NapiUtils::CheckValueType(env, argv[INDEX_0], napi_undefined)) {
128 std::string detail = NapiUtils::GetStringFromNapi(env, argv[INDEX_0]);
129 if (!detail.empty()) {
130 return error.ThrowError(env, PowerErrors::ERR_PARAM_INVALID);
131 }
132 }
133 }
134
135 bool clearMemory = false;
136 napi_get_value_bool(env, argv[0], &clearMemory);
137
138 int32_t apiVersion = AppManagerUtils::GetApiTargetVersion();
139 PowerErrors code = g_powerMgrClient.Hibernate(clearMemory, std::to_string(apiVersion));
140 if (code != PowerErrors::ERR_OK) {
141 POWER_HILOGE(FEATURE_WAKEUP, "Hibernate failed.");
142 error.ThrowError(env, code);
143 }
144 return nullptr;
145 }
146
SetPowerMode(napi_env env,napi_callback_info info)147 napi_value PowerNapi::SetPowerMode(napi_env env, napi_callback_info info)
148 {
149 size_t argc = SET_MODE_CALLBACK_MAX_ARGC;
150 napi_value argv[argc];
151 NapiUtils::GetCallbackInfo(env, info, argc, argv);
152
153 NapiErrors error;
154 if (argc != SET_MODE_CALLBACK_MAX_ARGC && argc != SET_MODE_PROMISE_MAX_ARGC) {
155 return error.ThrowError(env, PowerErrors::ERR_PARAM_INVALID);
156 }
157
158 std::unique_ptr<AsyncCallbackInfo> asyncInfo = std::make_unique<AsyncCallbackInfo>();
159 RETURN_IF_WITH_RET(asyncInfo == nullptr, nullptr);
160 // callback
161 if (argc == SET_MODE_CALLBACK_MAX_ARGC) {
162 POWER_HILOGD(FEATURE_POWER_MODE, "Call setPowerMode callback");
163 return SetPowerModeCallback(env, argv, asyncInfo);
164 }
165
166 // promise
167 POWER_HILOGD(FEATURE_POWER_MODE, "Call setPowerMode promise");
168 return SetPowerModePromise(env, argv, asyncInfo);
169 }
170
GetPowerMode(napi_env env,napi_callback_info info)171 napi_value PowerNapi::GetPowerMode(napi_env env, napi_callback_info info)
172 {
173 PowerMode mode = g_powerMgrClient.GetDeviceMode();
174 napi_value napiValue;
175 NAPI_CALL(env, napi_create_uint32(env, static_cast<uint32_t>(mode), &napiValue));
176 return napiValue;
177 }
178
SetFrameworkBootStage(bool isReboot)179 static void SetFrameworkBootStage(bool isReboot)
180 {
181 int fd = open("/dev/bbox", O_WRONLY);
182 if (fd < 0) {
183 POWER_HILOGE(FEATURE_SHUTDOWN, "open /dev/bbox failed!");
184 return;
185 }
186 int rebootFlag = isReboot ? 1 : 0;
187 int ret = ioctl(fd, SET_REBOOT, &rebootFlag);
188 if (ret < 0) {
189 POWER_HILOGE(FEATURE_SHUTDOWN, "set reboot flag failed!");
190 close(fd);
191 return;
192 }
193 int stage = SHUT_STAGE_FRAMEWORK_START;
194 ret = ioctl(fd, SET_SHUT_STAGE, &stage);
195 if (ret < 0) {
196 POWER_HILOGE(FEATURE_SHUTDOWN, "set shut stage failed!");
197 }
198 close(fd);
199 return;
200 }
201
RebootOrShutdown(napi_env env,napi_callback_info info,bool isReboot)202 napi_value PowerNapi::RebootOrShutdown(napi_env env, napi_callback_info info, bool isReboot)
203 {
204 size_t argc = REBOOT_SHUTDOWN_MAX_ARGC;
205 napi_value argv[argc];
206 SetFrameworkBootStage(isReboot);
207 NapiUtils::GetCallbackInfo(env, info, argc, argv);
208
209 NapiErrors error;
210 if (argc != REBOOT_SHUTDOWN_MAX_ARGC || !NapiUtils::CheckValueType(env, argv[INDEX_0], napi_string)) {
211 return error.ThrowError(env, PowerErrors::ERR_PARAM_INVALID);
212 }
213
214 std::string reason = NapiUtils::GetStringFromNapi(env, argv[INDEX_0]);
215 POWER_HILOGD(FEATURE_SHUTDOWN, "reboot: %{public}d, reason: %{public}s", isReboot, reason.c_str());
216
217 PowerErrors code;
218 if (isReboot) {
219 code = g_powerMgrClient.RebootDevice(reason);
220 } else {
221 code = g_powerMgrClient.ShutDownDevice(reason);
222 }
223 if (code != PowerErrors::ERR_OK) {
224 error.ThrowError(env, code);
225 }
226
227 return nullptr;
228 }
229
SetPowerModeCallback(napi_env & env,napi_value argv[],std::unique_ptr<AsyncCallbackInfo> & asyncInfo)230 napi_value PowerNapi::SetPowerModeCallback(
231 napi_env& env, napi_value argv[], std::unique_ptr<AsyncCallbackInfo>& asyncInfo)
232 {
233 bool isNum = NapiUtils::CheckValueType(env, argv[INDEX_0], napi_number);
234 bool isFunc = NapiUtils::CheckValueType(env, argv[INDEX_1], napi_function);
235 if (!isNum || !isFunc) {
236 POWER_HILOGW(FEATURE_POWER_MODE, "isNum: %{public}d, isFunc: %{public}d", isNum, isFunc);
237 return asyncInfo->GetError().ThrowError(env, PowerErrors::ERR_PARAM_INVALID);
238 }
239
240 asyncInfo->GetData().SetMode(env, argv[INDEX_0]);
241 asyncInfo->CreateCallback(env, argv[INDEX_1]);
242
243 AsyncWork(
244 env, asyncInfo, "SetPowerModeCallback",
245 [](napi_env env, void* data) {
246 AsyncCallbackInfo* asyncInfo = reinterpret_cast<AsyncCallbackInfo*>(data);
247 RETURN_IF(asyncInfo == nullptr);
248 PowerErrors error = g_powerMgrClient.SetDeviceMode(asyncInfo->GetData().GetMode());
249 asyncInfo->GetError().Error(error);
250 },
251 [](napi_env env, napi_status status, void* data) {
252 AsyncCallbackInfo* asyncInfo = reinterpret_cast<AsyncCallbackInfo*>(data);
253 RETURN_IF(asyncInfo == nullptr);
254 asyncInfo->CallFunction(env, nullptr);
255 asyncInfo->Release(env);
256 delete asyncInfo;
257 });
258 return nullptr;
259 }
260
SetPowerModePromise(napi_env & env,napi_value argv[],std::unique_ptr<AsyncCallbackInfo> & asyncInfo)261 napi_value PowerNapi::SetPowerModePromise(
262 napi_env& env, napi_value argv[], std::unique_ptr<AsyncCallbackInfo>& asyncInfo)
263 {
264 bool isNum = NapiUtils::CheckValueType(env, argv[INDEX_0], napi_number);
265 if (!isNum) {
266 POWER_HILOGW(FEATURE_POWER_MODE, "isNum: %{public}d", isNum);
267 return asyncInfo->GetError().ThrowError(env, PowerErrors::ERR_PARAM_INVALID);
268 }
269 napi_value promise;
270 asyncInfo->CreatePromise(env, promise);
271 RETURN_IF_WITH_RET(promise == nullptr, nullptr);
272 asyncInfo->GetData().SetMode(env, argv[INDEX_0]);
273
274 AsyncWork(
275 env, asyncInfo, "SetPowerModePromise",
276 [](napi_env env, void* data) {
277 AsyncCallbackInfo* asyncInfo = reinterpret_cast<AsyncCallbackInfo*>(data);
278 RETURN_IF(asyncInfo == nullptr);
279 PowerErrors error = g_powerMgrClient.SetDeviceMode(asyncInfo->GetData().GetMode());
280 asyncInfo->GetError().Error(error);
281 },
282 [](napi_env env, napi_status status, void* data) {
283 AsyncCallbackInfo* asyncInfo = reinterpret_cast<AsyncCallbackInfo*>(data);
284 RETURN_IF(asyncInfo == nullptr);
285 if (asyncInfo->GetError().IsError()) {
286 napi_reject_deferred(env, asyncInfo->GetDeferred(), asyncInfo->GetError().GetNapiError(env));
287 } else {
288 napi_value undefined;
289 napi_get_undefined(env, &undefined);
290 napi_resolve_deferred(env, asyncInfo->GetDeferred(), undefined);
291 }
292 asyncInfo->Release(env);
293 delete asyncInfo;
294 });
295 return promise;
296 }
297
AsyncWork(napi_env & env,std::unique_ptr<AsyncCallbackInfo> & asyncInfo,const std::string & resourceName,napi_async_execute_callback execute,napi_async_complete_callback complete)298 void PowerNapi::AsyncWork(napi_env& env, std::unique_ptr<AsyncCallbackInfo>& asyncInfo, const std::string& resourceName,
299 napi_async_execute_callback execute, napi_async_complete_callback complete)
300 {
301 napi_value resource = nullptr;
302 napi_create_string_utf8(env, resourceName.c_str(), NAPI_AUTO_LENGTH, &resource);
303 napi_create_async_work(env, nullptr, resource, execute, complete,
304 reinterpret_cast<void*>(asyncInfo.get()), &(asyncInfo->GetAsyncWork()));
305 NAPI_CALL_RETURN_VOID(env, napi_queue_async_work_with_qos(env, asyncInfo->GetAsyncWork(), napi_qos_utility));
306 asyncInfo.release();
307 }
308
SetScreenOffTime(napi_env env,napi_callback_info info)309 napi_value PowerNapi::SetScreenOffTime(napi_env env, napi_callback_info info)
310 {
311 size_t argc = SET_SCREEN_OFFTIME_ARGC;
312 napi_value argv[argc];
313 NapiUtils::GetCallbackInfo(env, info, argc, argv);
314
315 NapiErrors error;
316 if (argc != SET_SCREEN_OFFTIME_ARGC || !NapiUtils::CheckValueType(env, argv[INDEX_0], napi_number)) {
317 POWER_HILOGE(FEATURE_WAKEUP, "check value type failed.");
318 return error.ThrowError(env, PowerErrors::ERR_PARAM_INVALID);
319 }
320
321 int64_t timeout;
322 if (napi_ok != napi_get_value_int64(env, argv[INDEX_0], &timeout)) {
323 POWER_HILOGE(FEATURE_WAKEUP, "napi get int64 value failed.");
324 return error.ThrowError(env, PowerErrors::ERR_PARAM_INVALID);
325 }
326
327 if (timeout == 0 || (timeout < 0 && timeout != RESTORE_DEFAULT_SCREENOFF_TIME)) {
328 POWER_HILOGE(FEATURE_WAKEUP, "timeout is not right.");
329 return error.ThrowError(env, PowerErrors::ERR_PARAM_INVALID);
330 }
331
332 PowerErrors code;
333 int32_t apiVersion = AppManagerUtils::GetApiTargetVersion();
334 if (timeout == RESTORE_DEFAULT_SCREENOFF_TIME) {
335 code = g_powerMgrClient.RestoreScreenOffTime(std::to_string(apiVersion));
336 } else {
337 code = g_powerMgrClient.OverrideScreenOffTime(timeout, std::to_string(apiVersion));
338 }
339 if (code != PowerErrors::ERR_OK) {
340 POWER_HILOGE(FEATURE_WAKEUP, "SetScreenOffTime failed.");
341 return error.ThrowError(env, code);
342 }
343 return nullptr;
344 }
345
IsStandby(napi_env env,napi_callback_info info)346 napi_value PowerNapi::IsStandby(napi_env env, napi_callback_info info)
347 {
348 bool isStandby = false;
349 PowerErrors code = g_powerMgrClient.IsStandby(isStandby);
350 if (code == PowerErrors::ERR_OK) {
351 napi_value napiValue;
352 NAPI_CALL(env, napi_get_boolean(env, isStandby, &napiValue));
353 return napiValue;
354 }
355 NapiErrors error;
356 return error.ThrowError(env, code);
357 }
358 } // namespace PowerMgr
359 } // namespace OHOS
360