• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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