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 32namespace OHOS { 33namespace PowerMgr { 34namespace { 35constexpr uint32_t REBOOT_SHUTDOWN_MAX_ARGC = 1; 36constexpr uint32_t WAKEUP_MAX_ARGC = 1; 37constexpr uint32_t SET_MODE_CALLBACK_MAX_ARGC = 2; 38constexpr uint32_t SET_MODE_PROMISE_MAX_ARGC = 1; 39constexpr uint32_t SUSPEND_MAX_ARGC = 1; 40constexpr uint32_t SET_SCREEN_OFFTIME_ARGC = 1; 41constexpr uint32_t HIBERNATE_ARGC = 1; 42constexpr int32_t INDEX_0 = 0; 43constexpr int32_t INDEX_1 = 1; 44constexpr int32_t RESTORE_DEFAULT_SCREENOFF_TIME = -1; 45static PowerMgrClient& g_powerMgrClient = PowerMgrClient::GetInstance(); 46} // namespace 47napi_value PowerNapi::Shutdown(napi_env env, napi_callback_info info) 48{ 49 return RebootOrShutdown(env, info, false); 50} 51 52napi_value PowerNapi::Reboot(napi_env env, napi_callback_info info) 53{ 54 return RebootOrShutdown(env, info, true); 55} 56 57napi_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 65napi_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 85napi_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 117napi_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 144napi_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 168napi_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 176static 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 199napi_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 227napi_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 258napi_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 295void 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 306napi_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 342napi_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