1 /*
2  * Copyright (c) 2023-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 #include "js_ability_auto_startup_manager.h"
16 
17 #include "ability_business_error.h"
18 #include "ability_manager_client.h"
19 #include "ability_manager_interface.h"
20 #include "auto_startup_info.h"
21 #include "hilog_tag_wrapper.h"
22 #include "ipc_skeleton.h"
23 #include "js_ability_auto_startup_manager_utils.h"
24 #include "js_error_utils.h"
25 #include "js_runtime_utils.h"
26 #include "permission_constants.h"
27 #include "tokenid_kit.h"
28 
29 namespace OHOS {
30 namespace AbilityRuntime {
31 using namespace OHOS::AAFwk;
32 namespace {
33 constexpr size_t ARGC_ONE = 1;
34 constexpr size_t ARGC_TWO = 2;
35 constexpr int32_t INDEX_ZERO = 0;
36 constexpr int32_t INDEX_ONE = 1;
37 constexpr int32_t INVALID_PARAM = static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INVALID_PARAM);
38 constexpr const char *ON_OFF_TYPE_SYSTEM = "systemAutoStartup";
39 } // namespace
40 
Finalizer(napi_env env,void * data,void * hint)41 void JsAbilityAutoStartupManager::Finalizer(napi_env env, void *data, void *hint)
42 {
43     TAG_LOGD(AAFwkTag::AUTO_STARTUP, "called");
44     std::unique_ptr<JsAbilityAutoStartupManager>(static_cast<JsAbilityAutoStartupManager *>(data));
45 }
46 
RegisterAutoStartupCallback(napi_env env,napi_callback_info info)47 napi_value JsAbilityAutoStartupManager::RegisterAutoStartupCallback(napi_env env, napi_callback_info info)
48 {
49     GET_NAPI_INFO_AND_CALL(env, info, JsAbilityAutoStartupManager, OnRegisterAutoStartupCallback);
50 }
51 
UnregisterAutoStartupCallback(napi_env env,napi_callback_info info)52 napi_value JsAbilityAutoStartupManager::UnregisterAutoStartupCallback(napi_env env, napi_callback_info info)
53 {
54     GET_NAPI_INFO_AND_CALL(env, info, JsAbilityAutoStartupManager, OnUnregisterAutoStartupCallback);
55 }
56 
SetApplicationAutoStartup(napi_env env,napi_callback_info info)57 napi_value JsAbilityAutoStartupManager::SetApplicationAutoStartup(napi_env env, napi_callback_info info)
58 {
59     GET_NAPI_INFO_AND_CALL(env, info, JsAbilityAutoStartupManager, OnSetApplicationAutoStartup);
60 }
61 
CancelApplicationAutoStartup(napi_env env,napi_callback_info info)62 napi_value JsAbilityAutoStartupManager::CancelApplicationAutoStartup(napi_env env, napi_callback_info info)
63 {
64     GET_NAPI_INFO_AND_CALL(env, info, JsAbilityAutoStartupManager, OnCancelApplicationAutoStartup);
65 }
66 
QueryAllAutoStartupApplications(napi_env env,napi_callback_info info)67 napi_value JsAbilityAutoStartupManager::QueryAllAutoStartupApplications(napi_env env, napi_callback_info info)
68 {
69     GET_NAPI_INFO_AND_CALL(env, info, JsAbilityAutoStartupManager, OnQueryAllAutoStartupApplications);
70 }
71 
CheckCallerIsSystemApp()72 bool JsAbilityAutoStartupManager::CheckCallerIsSystemApp()
73 {
74     auto selfToken = IPCSkeleton::GetSelfTokenID();
75     if (!Security::AccessToken::TokenIdKit::IsSystemAppByFullTokenID(selfToken)) {
76         TAG_LOGE(AAFwkTag::AUTO_STARTUP, "not system app");
77         return false;
78     }
79     return true;
80 }
81 
OnRegisterAutoStartupCallback(napi_env env,NapiCallbackInfo & info)82 napi_value JsAbilityAutoStartupManager::OnRegisterAutoStartupCallback(napi_env env, NapiCallbackInfo &info)
83 {
84     TAG_LOGD(AAFwkTag::AUTO_STARTUP, "called");
85     if (info.argc < ARGC_TWO) {
86         TAG_LOGE(AAFwkTag::AUTO_STARTUP, "invalid argc");
87         ThrowTooFewParametersError(env);
88         return CreateJsUndefined(env);
89     }
90 
91     std::string type;
92     if (!ConvertFromJsValue(env, info.argv[INDEX_ZERO], type) || type != ON_OFF_TYPE_SYSTEM) {
93         TAG_LOGE(AAFwkTag::AUTO_STARTUP, "invalid param");
94         ThrowError(env, INVALID_PARAM, "Parameter error. Convert type fail.");
95         return CreateJsUndefined(env);
96     }
97 
98     if (!CheckCallerIsSystemApp()) {
99         TAG_LOGE(AAFwkTag::AUTO_STARTUP, "not system app");
100         ThrowError(env, AbilityErrorCode::ERROR_CODE_NOT_SYSTEM_APP);
101         return CreateJsUndefined(env);
102     }
103 
104     if (jsAutoStartupCallback_ == nullptr) {
105         jsAutoStartupCallback_ = new (std::nothrow) JsAbilityAutoStartupCallBack(env);
106         if (jsAutoStartupCallback_ == nullptr) {
107             TAG_LOGE(AAFwkTag::AUTO_STARTUP, "null jsAutoStartupCallback_");
108             ThrowError(env, AbilityErrorCode::ERROR_CODE_INNER);
109             return CreateJsUndefined(env);
110         }
111 
112         auto ret =
113             AbilityManagerClient::GetInstance()->RegisterAutoStartupSystemCallback(jsAutoStartupCallback_->AsObject());
114         if (ret != ERR_OK) {
115             jsAutoStartupCallback_ = nullptr;
116             TAG_LOGE(AAFwkTag::AUTO_STARTUP, "reg callback failed[%{public}d]", ret);
117             if (ret == CHECK_PERMISSION_FAILED) {
118                 ThrowNoPermissionError(env, PermissionConstants::PERMISSION_MANAGE_APP_BOOT);
119             } else {
120                 ThrowError(env, GetJsErrorCodeByNativeError(ret));
121             }
122             return CreateJsUndefined(env);
123         }
124     }
125 
126     jsAutoStartupCallback_->Register(info.argv[INDEX_ONE]);
127     return CreateJsUndefined(env);
128 }
129 
OnUnregisterAutoStartupCallback(napi_env env,NapiCallbackInfo & info)130 napi_value JsAbilityAutoStartupManager::OnUnregisterAutoStartupCallback(napi_env env, NapiCallbackInfo &info)
131 {
132     TAG_LOGD(AAFwkTag::AUTO_STARTUP, "called");
133     if (info.argc < ARGC_ONE) {
134         TAG_LOGE(AAFwkTag::AUTO_STARTUP, "invalid argc");
135         ThrowTooFewParametersError(env);
136         return CreateJsUndefined(env);
137     }
138 
139     std::string type;
140     if (!ConvertFromJsValue(env, info.argv[INDEX_ZERO], type) || type != ON_OFF_TYPE_SYSTEM) {
141         TAG_LOGE(AAFwkTag::AUTO_STARTUP, "parse type failed");
142         ThrowError(env, INVALID_PARAM, "Parameter error. Convert type fail.");
143         return CreateJsUndefined(env);
144     }
145 
146     if (!CheckCallerIsSystemApp()) {
147         ThrowError(env, AbilityErrorCode::ERROR_CODE_NOT_SYSTEM_APP);
148         return CreateJsUndefined(env);
149     }
150 
151     if (jsAutoStartupCallback_ == nullptr) {
152         TAG_LOGE(AAFwkTag::AUTO_STARTUP, "null jsAutoStartupCallback_");
153         ThrowError(env, AbilityErrorCode::ERROR_CODE_INNER);
154         return CreateJsUndefined(env);
155     }
156 
157     auto callback = info.argc > ARGC_ONE ? info.argv[INDEX_ONE] : CreateJsUndefined(env);
158     jsAutoStartupCallback_->UnRegister(callback);
159     if (jsAutoStartupCallback_->IsCallbacksEmpty()) {
160         auto ret = AbilityManagerClient::GetInstance()->UnregisterAutoStartupSystemCallback(
161             jsAutoStartupCallback_->AsObject());
162         if (ret != ERR_OK) {
163             if (ret == CHECK_PERMISSION_FAILED) {
164                 ThrowNoPermissionError(env, PermissionConstants::PERMISSION_MANAGE_APP_BOOT);
165             } else {
166                 ThrowError(env, GetJsErrorCodeByNativeError(ret));
167             }
168         }
169         jsAutoStartupCallback_ = nullptr;
170     }
171 
172     return CreateJsUndefined(env);
173 }
174 
OnSetApplicationAutoStartup(napi_env env,NapiCallbackInfo & info)175 napi_value JsAbilityAutoStartupManager::OnSetApplicationAutoStartup(napi_env env, NapiCallbackInfo &info)
176 {
177     TAG_LOGD(AAFwkTag::AUTO_STARTUP, "called");
178     if (info.argc < ARGC_ONE) {
179         TAG_LOGE(AAFwkTag::AUTO_STARTUP, "invalid argc");
180         ThrowTooFewParametersError(env);
181         return CreateJsUndefined(env);
182     }
183 
184     if (!CheckCallerIsSystemApp()) {
185         TAG_LOGE(AAFwkTag::AUTO_STARTUP, "not system app");
186         ThrowError(env, AbilityErrorCode::ERROR_CODE_NOT_SYSTEM_APP);
187         return CreateJsUndefined(env);
188     }
189 
190     AutoStartupInfo autoStartupInfo;
191     if (!UnwrapAutoStartupInfo(env, info.argv[INDEX_ZERO], autoStartupInfo)) {
192         ThrowError(env, INVALID_PARAM, "unwrap AutoStartupInfo failed");
193         return CreateJsUndefined(env);
194     }
195 
196     auto retVal = std::make_shared<int32_t>(0);
197     NapiAsyncTask::ExecuteCallback execute = [autoStartupInfo, ret = retVal] () {
198         if (ret == nullptr) {
199             TAG_LOGE(AAFwkTag::AUTO_STARTUP, "null ret");
200             return;
201         }
202         *ret = AbilityManagerClient::GetInstance()->SetApplicationAutoStartup(autoStartupInfo);
203     };
204     NapiAsyncTask::CompleteCallback complete = [ret = retVal](napi_env env, NapiAsyncTask &task, int32_t status) {
205         if (ret == nullptr) {
206             TAG_LOGE(AAFwkTag::AUTO_STARTUP, "null ret");
207             task.Reject(env, CreateJsError(env, GetJsErrorCodeByNativeError(INNER_ERR)));
208             return;
209         }
210         if (*ret != ERR_OK) {
211             TAG_LOGE(AAFwkTag::AUTO_STARTUP, "error:%{public}d", *ret);
212             task.Reject(env, CreateJsError(env, GetJsErrorCodeByNativeError(*ret)));
213             return;
214         }
215         task.ResolveWithNoError(env, CreateJsUndefined(env));
216     };
217 
218     napi_value lastParam = (info.argc >= ARGC_TWO) ? info.argv[INDEX_ONE] : nullptr;
219     napi_value result = nullptr;
220     NapiAsyncTask::ScheduleHighQos("JsAbilityAutoStartupManager::OnSetApplicationAutoStartup", env,
221         CreateAsyncTaskWithLastParam(env, lastParam, std::move(execute), std::move(complete), &result));
222     return result;
223 }
224 
OnCancelApplicationAutoStartup(napi_env env,NapiCallbackInfo & info)225 napi_value JsAbilityAutoStartupManager::OnCancelApplicationAutoStartup(napi_env env, NapiCallbackInfo &info)
226 {
227     TAG_LOGD(AAFwkTag::AUTO_STARTUP, "called");
228     if (info.argc < ARGC_ONE) {
229         TAG_LOGE(AAFwkTag::AUTO_STARTUP, "invalid argc");
230         ThrowTooFewParametersError(env);
231         return CreateJsUndefined(env);
232     }
233 
234     if (!CheckCallerIsSystemApp()) {
235         TAG_LOGE(AAFwkTag::AUTO_STARTUP, "not system app");
236         ThrowError(env, AbilityErrorCode::ERROR_CODE_NOT_SYSTEM_APP);
237         return CreateJsUndefined(env);
238     }
239 
240     AutoStartupInfo autoStartupInfo;
241     if (!UnwrapAutoStartupInfo(env, info.argv[INDEX_ZERO], autoStartupInfo)) {
242         ThrowError(env, INVALID_PARAM, "Parameter error. Convert autoStartupInfo fail.");
243         return CreateJsUndefined(env);
244     }
245 
246     auto retVal = std::make_shared<int32_t>(0);
247     NapiAsyncTask::ExecuteCallback execute = [autoStartupInfo, ret = retVal] () {
248         if (ret == nullptr) {
249             TAG_LOGE(AAFwkTag::AUTO_STARTUP, "null ret");
250             return;
251         }
252         *ret = AbilityManagerClient::GetInstance()->CancelApplicationAutoStartup(autoStartupInfo);
253     };
254 
255     NapiAsyncTask::CompleteCallback complete = [ret = retVal](napi_env env, NapiAsyncTask &task, int32_t status) {
256         if (ret == nullptr) {
257             TAG_LOGE(AAFwkTag::AUTO_STARTUP, "null ret");
258             task.Reject(env, CreateJsError(env, GetJsErrorCodeByNativeError(INNER_ERR)));
259             return;
260         }
261         if (*ret != ERR_OK) {
262             TAG_LOGE(AAFwkTag::AUTO_STARTUP, "error:%{public}d", *ret);
263             task.Reject(env, CreateJsError(env, GetJsErrorCodeByNativeError(*ret)));
264             return;
265         }
266         task.ResolveWithNoError(env, CreateJsUndefined(env));
267     };
268 
269     napi_value lastParam = (info.argc >= ARGC_TWO) ? info.argv[INDEX_ONE] : nullptr;
270     napi_value result = nullptr;
271     NapiAsyncTask::Schedule("JsAbilityAutoStartupManager::OnCancelApplicationAutoStartup", env,
272         CreateAsyncTaskWithLastParam(env, lastParam, std::move(execute), std::move(complete), &result));
273     return result;
274 }
275 
OnQueryAllAutoStartupApplications(napi_env env,const NapiCallbackInfo & info)276 napi_value JsAbilityAutoStartupManager::OnQueryAllAutoStartupApplications(napi_env env, const NapiCallbackInfo &info)
277 {
278     TAG_LOGD(AAFwkTag::AUTO_STARTUP, "called");
279     if (!CheckCallerIsSystemApp()) {
280         ThrowError(env, AbilityErrorCode::ERROR_CODE_NOT_SYSTEM_APP);
281         return CreateJsUndefined(env);
282     }
283 
284     auto retVal = std::make_shared<int32_t>(0);
285     auto infoList = std::make_shared<std::vector<AutoStartupInfo>>();
286     NapiAsyncTask::ExecuteCallback execute = [infos = infoList, ret = retVal] () {
287         if (ret == nullptr || infos == nullptr) {
288             TAG_LOGE(AAFwkTag::AUTO_STARTUP, "null ret or infos");
289             return;
290         }
291         *ret = AbilityManagerClient::GetInstance()->QueryAllAutoStartupApplications(*infos);
292     };
293 
294     NapiAsyncTask::CompleteCallback complete = [infos = infoList, ret = retVal](
295                                                    napi_env env, NapiAsyncTask &task, int32_t status) {
296         if (ret == nullptr || infos == nullptr) {
297             TAG_LOGE(AAFwkTag::AUTO_STARTUP, "null ret or infos");
298             task.Reject(env, CreateJsError(env, GetJsErrorCodeByNativeError(INNER_ERR)));
299             return;
300         }
301         if (*ret != ERR_OK) {
302             TAG_LOGE(AAFwkTag::AUTO_STARTUP, "error:%{public}d", *ret);
303             task.Reject(env, CreateJsError(env, GetJsErrorCodeByNativeError(*ret)));
304             return;
305         }
306         task.ResolveWithNoError(env, CreateJsAutoStartupInfoArray(env, *infos));
307     };
308 
309     napi_value lastParam = (info.argc >= ARGC_ONE) ? info.argv[INDEX_ZERO] : nullptr;
310     napi_value result = nullptr;
311     NapiAsyncTask::Schedule("JsAbilityAutoStartupManager::OnQueryAllAutoStartupApplications", env,
312         CreateAsyncTaskWithLastParam(env, lastParam, std::move(execute), std::move(complete), &result));
313     return result;
314 }
315 
JsAbilityAutoStartupManagerInit(napi_env env,napi_value exportObj)316 napi_value JsAbilityAutoStartupManagerInit(napi_env env, napi_value exportObj)
317 {
318     TAG_LOGD(AAFwkTag::AUTO_STARTUP, "called");
319     if (env == nullptr || exportObj == nullptr) {
320         TAG_LOGE(AAFwkTag::AUTO_STARTUP, "null env or exportObj");
321         return nullptr;
322     }
323 
324     auto jsAbilityAutoStartupManager = std::make_unique<JsAbilityAutoStartupManager>();
325     napi_wrap(env, exportObj, jsAbilityAutoStartupManager.release(),
326         JsAbilityAutoStartupManager::Finalizer, nullptr, nullptr);
327 
328     const char *moduleName = "JsAbilityAutoStartupManager";
329     BindNativeFunction(env, exportObj, "on", moduleName, JsAbilityAutoStartupManager::RegisterAutoStartupCallback);
330     BindNativeFunction(env, exportObj, "off", moduleName, JsAbilityAutoStartupManager::UnregisterAutoStartupCallback);
331     BindNativeFunction(env, exportObj, "setApplicationAutoStartup", moduleName,
332         JsAbilityAutoStartupManager::SetApplicationAutoStartup);
333     BindNativeFunction(env, exportObj, "cancelApplicationAutoStartup", moduleName,
334         JsAbilityAutoStartupManager::CancelApplicationAutoStartup);
335     BindNativeFunction(env, exportObj, "queryAllAutoStartupApplications", moduleName,
336         JsAbilityAutoStartupManager::QueryAllAutoStartupApplications);
337     TAG_LOGD(AAFwkTag::AUTO_STARTUP, "end");
338     return CreateJsUndefined(env);
339 }
340 } // namespace AbilityRuntime
341 } // namespace OHOS