1 /*
2 * Copyright (c) 2022-2024 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 "app_recovery_api.h"
17
18 #include "app_recovery.h"
19 #include "hilog_tag_wrapper.h"
20 #include "js_runtime.h"
21 #include "js_runtime_utils.h"
22
23 #include "napi/native_api.h"
24 #include "napi/native_common.h"
25 #include "napi/native_node_api.h"
26
27 #include "napi_common_want.h"
28 #include "recovery_param.h"
29 #include "want.h"
30
31 namespace OHOS {
32 namespace AbilityRuntime {
33 using namespace OHOS::AppExecFwk;
34 namespace {
35 enum RestartErrno {
36 NO_ERROR,
37 SAVED_STATE_NOT_EXIST,
38 LAST_RESTART_ENCOUNTER_ERROR,
39 };
40 class AppRecoveryApiRegistry {
41 public:
42 AppRecoveryApiRegistry() = default;
43 ~AppRecoveryApiRegistry() = default;
44
Finalizer(napi_env env,void * data,void * hint)45 static void Finalizer(napi_env env, void *data, void *hint)
46 {
47 std::unique_ptr<AppRecoveryApiRegistry>(static_cast<AppRecoveryApiRegistry*>(data));
48 }
49
EnableAppRecovery(napi_env env,napi_callback_info info)50 static napi_value EnableAppRecovery(napi_env env, napi_callback_info info)
51 {
52 GET_CB_INFO_AND_CALL(env, info, AppRecoveryApiRegistry, OnEnableAppRecovery);
53 }
54
RestartApp(napi_env env,napi_callback_info info)55 static napi_value RestartApp(napi_env env, napi_callback_info info)
56 {
57 GET_CB_INFO_AND_CALL(env, info, AppRecoveryApiRegistry, OnRestartApp);
58 }
59
SaveAppState(napi_env env,napi_callback_info info)60 static napi_value SaveAppState(napi_env env, napi_callback_info info)
61 {
62 GET_CB_INFO_AND_CALL(env, info, AppRecoveryApiRegistry, OnSaveAppState);
63 }
64
SetRestartWant(napi_env env,napi_callback_info info)65 static napi_value SetRestartWant(napi_env env, napi_callback_info info)
66 {
67 GET_CB_INFO_AND_CALL(env, info, AppRecoveryApiRegistry, OnSetRestartWant);
68 }
69
70 private:
OnEnableAppRecovery(napi_env env,const size_t argc,napi_value * argv)71 napi_value OnEnableAppRecovery(napi_env env, const size_t argc, napi_value* argv)
72 {
73 size_t parameterCount = argc;
74 napi_value result = CreateJsUndefined(env);
75 constexpr int maxCount = 3;
76 if (parameterCount > maxCount) {
77 return result;
78 }
79
80 uint16_t flags[] = {
81 RestartFlag::ALWAYS_RESTART,
82 SaveOccasionFlag::SAVE_WHEN_ERROR,
83 SaveModeFlag::SAVE_WITH_FILE
84 };
85
86 for (size_t i = 0; i < parameterCount; ++i) {
87 napi_valuetype paramType;
88 napi_typeof(env, argv[i], ¶mType);
89 if (paramType != napi_number) {
90 TAG_LOGE(
91 AAFwkTag::RECOVERY, "argv[%{public}s] not number", std::to_string(i).c_str());
92 return result;
93 }
94 int32_t tmp = 0;
95 napi_get_value_int32(env, argv[i], &tmp);
96 flags[i] = static_cast<uint16_t>(tmp);
97 }
98
99 if (!CheckParamsValid(flags)) {
100 return result;
101 }
102
103 AppRecovery::GetInstance().EnableAppRecovery(flags[0], // 0:RestartFlag
104 flags[1], // 1:SaveOccasionFlag
105 flags[2]); // 2:SaveModeFlag
106 return result;
107 }
108
CheckParamsValid(const uint16_t params[])109 bool CheckParamsValid(const uint16_t params[])
110 {
111 uint16_t restartFlag = params[0];
112 constexpr uint16_t restartMaxVal = 0x0003;
113 if ((restartFlag < 0 || restartFlag > restartMaxVal) && (restartFlag != RestartFlag::NO_RESTART)) {
114 TAG_LOGE(AAFwkTag::RECOVERY, "invalid restartFlag: %{public}d", restartFlag);
115 return false;
116 }
117 uint16_t saveFlag = params[1];
118 constexpr uint16_t saveMaxVal = 0x0003;
119 if (saveFlag < SaveOccasionFlag::SAVE_WHEN_ERROR || saveFlag > saveMaxVal) {
120 TAG_LOGE(AAFwkTag::RECOVERY, "invalid saveOccasionFlag: %{public}d", saveFlag);
121 return false;
122 }
123 uint16_t saveModeFlag = params[2];
124 if (saveModeFlag < SaveModeFlag::SAVE_WITH_FILE || saveModeFlag > SaveModeFlag::SAVE_WITH_SHARED_MEMORY) {
125 TAG_LOGE(AAFwkTag::RECOVERY, "invalid saveModeFlag: %{public}d", saveModeFlag);
126 return false;
127 }
128 return true;
129 }
130
OnSaveAppState(napi_env env,const size_t argc,napi_value * argv)131 napi_value OnSaveAppState(napi_env env, const size_t argc, napi_value* argv)
132 {
133 if (argc > 1) {
134 TAG_LOGE(AAFwkTag::RECOVERY, "invalid argc");
135 return CreateJsValue(env, false);
136 }
137 uintptr_t ability = 0;
138 if (argc == 1) {
139 napi_value value = argv[0];
140 if (value == nullptr) {
141 TAG_LOGE(AAFwkTag::RECOVERY, "null abilityContext");
142 return CreateJsValue(env, false);
143 }
144 void* result = nullptr;
145 napi_unwrap(env, value, &result);
146 ability = reinterpret_cast<uintptr_t>(result);
147 }
148 if (AppRecovery::GetInstance().ScheduleSaveAppState(StateReason::DEVELOPER_REQUEST, ability)) {
149 return CreateJsValue(env, true);
150 }
151 return CreateJsValue(env, false);
152 }
153
OnRestartApp(napi_env env,const size_t argc,napi_value * argv)154 napi_value OnRestartApp(napi_env env, const size_t argc, napi_value* argv)
155 {
156 if (argc != 0) {
157 TAG_LOGE(AAFwkTag::RECOVERY, "invalid argc");
158 return CreateJsUndefined(env);
159 }
160
161 AppRecovery::GetInstance().ScheduleRecoverApp(StateReason::DEVELOPER_REQUEST);
162 return CreateJsUndefined(env);
163 }
164
OnSetRestartWant(napi_env env,const size_t argc,napi_value * argv)165 napi_value OnSetRestartWant(napi_env env, const size_t argc, napi_value* argv)
166 {
167 if (argc != 1) {
168 TAG_LOGE(AAFwkTag::RECOVERY, "invalid argc");
169 return CreateJsUndefined(env);
170 }
171 std::shared_ptr<AAFwk::Want> want = std::make_shared<AAFwk::Want>();
172 OHOS::AppExecFwk::UnwrapWant(env, argv[0], *(want.get()));
173 AppRecovery::GetInstance().SetRestartWant(want);
174 return CreateJsUndefined(env);
175 }
176 };
177 } // namespace
178
AppRecoveryRestartFlagInit(napi_env env)179 napi_value AppRecoveryRestartFlagInit(napi_env env)
180 {
181 if (env == nullptr) {
182 TAG_LOGE(AAFwkTag::RECOVERY, "null env");
183 return nullptr;
184 }
185
186 napi_value objValue = nullptr;
187 napi_create_object(env, &objValue);
188
189 if (objValue == nullptr) {
190 TAG_LOGE(AAFwkTag::RECOVERY, "null obj");
191 return nullptr;
192 }
193
194 napi_set_named_property(env, objValue, "ALWAYS_RESTART", CreateJsValue(env, RestartFlag::ALWAYS_RESTART));
195 napi_set_named_property(env, objValue, "RESTART_WHEN_JS_CRASH",
196 CreateJsValue(env, RestartFlag::RESTART_WHEN_JS_CRASH));
197 napi_set_named_property(env, objValue, "RESTART_WHEN_APP_FREEZE",
198 CreateJsValue(env, RestartFlag::RESTART_WHEN_APP_FREEZE));
199 napi_set_named_property(env, objValue, "NO_RESTART", CreateJsValue(env, RestartFlag::NO_RESTART));
200 return objValue;
201 }
202
AppRecoveryStateSaveFlagInit(napi_env env)203 napi_value AppRecoveryStateSaveFlagInit(napi_env env)
204 {
205 if (env == nullptr) {
206 TAG_LOGE(AAFwkTag::RECOVERY, "null env");
207 return nullptr;
208 }
209
210 napi_value objValue = nullptr;
211 napi_create_object(env, &objValue);
212
213 if (objValue == nullptr) {
214 TAG_LOGE(AAFwkTag::RECOVERY, "null obj");
215 return nullptr;
216 }
217
218 napi_set_named_property(env, objValue, "NONE", CreateJsValue(env, SaveOccasionFlag::NO_SAVE));
219 napi_set_named_property(env, objValue, "SAVE_WHEN_ERROR",
220 CreateJsValue(env, SaveOccasionFlag::SAVE_WHEN_ERROR));
221 napi_set_named_property(env, objValue, "SAVE_WHEN_BACKGROUND",
222 CreateJsValue(env, SaveOccasionFlag::SAVE_WHEN_BACKGROUND));
223 return objValue;
224 }
225
AppRecoverySaveModeFlagInit(napi_env env)226 napi_value AppRecoverySaveModeFlagInit(napi_env env)
227 {
228 if (env == nullptr) {
229 TAG_LOGE(AAFwkTag::RECOVERY, "null env");
230 return nullptr;
231 }
232
233 napi_value objValue = nullptr;
234 napi_create_object(env, &objValue);
235
236 if (objValue == nullptr) {
237 TAG_LOGE(AAFwkTag::RECOVERY, "null obj");
238 return nullptr;
239 }
240 napi_set_named_property(env, objValue, "SAVE_WITH_FILE",
241 CreateJsValue(env, SaveModeFlag::SAVE_WITH_FILE));
242 napi_set_named_property(env, objValue, "SAVE_WITH_SHARED_MEMORY",
243 CreateJsValue(env, SaveModeFlag::SAVE_WITH_SHARED_MEMORY));
244 return objValue;
245 }
246
InitAppRecoveryApiModule(napi_env env,napi_value exportObj)247 napi_value InitAppRecoveryApiModule(napi_env env, napi_value exportObj)
248 {
249 if (env == nullptr || exportObj == nullptr) {
250 TAG_LOGE(AAFwkTag::RECOVERY, "null env or exportObj");
251 return nullptr;
252 }
253
254 std::unique_ptr<AppRecoveryApiRegistry> appRecoveryApi = std::make_unique<AppRecoveryApiRegistry>();
255 napi_wrap(env, exportObj, appRecoveryApi.release(), AppRecoveryApiRegistry::Finalizer, nullptr, nullptr);
256
257 const char *moduleName = "AppRecovery";
258 BindNativeFunction(env, exportObj, "enableAppRecovery", moduleName, AppRecoveryApiRegistry::EnableAppRecovery);
259 BindNativeFunction(env, exportObj, "restartApp", moduleName, AppRecoveryApiRegistry::RestartApp);
260 BindNativeFunction(env, exportObj, "saveAppState", moduleName, AppRecoveryApiRegistry::SaveAppState);
261 BindNativeFunction(env, exportObj, "setRestartWant", moduleName, AppRecoveryApiRegistry::SetRestartWant);
262
263 napi_set_named_property(env, exportObj, "RestartFlag", AppRecoveryRestartFlagInit(env));
264 napi_set_named_property(env, exportObj, "SaveOccasionFlag", AppRecoveryStateSaveFlagInit(env));
265 napi_set_named_property(env, exportObj, "SaveModeFlag", AppRecoverySaveModeFlagInit(env));
266
267 return CreateJsUndefined(env);
268 }
269 } // namespace AbilityRuntime
270 } // namespace OHOS