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