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