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