1 /*
2  * Copyright (c) 2022-2023 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 "package.h"
16 #include <string>
17 
18 #include "app_log_wrapper.h"
19 #include "bundle_constants.h"
20 #include "bundle_mgr_host.h"
21 #include "bundle_mgr_interface.h"
22 #include "if_system_ability_manager.h"
23 #include "ipc_skeleton.h"
24 #include "iservice_registry.h"
25 #include "napi/native_api.h"
26 #include "napi/native_node_api.h"
27 
28 #include "securec.h"
29 #include "system_ability_definition.h"
30 
31 namespace OHOS {
32 namespace AppExecFwk {
33 using namespace OHOS;
34 using namespace OHOS::AAFwk;
35 using namespace OHOS::AppExecFwk;
36 namespace {
37 constexpr int32_t NAPI_RETURN_ZERO = 0;
38 constexpr size_t ARGS_SIZE_ONE = 1;
39 constexpr size_t ARGS_SIZE_TWO = 2;
40 constexpr int32_t PARAM0 = 0;
41 constexpr int32_t PARAM1 = 1;
42 constexpr int32_t NAPI_RETURN_ONE = 1;
43 constexpr int32_t INVALID_PARAM = 2;
44 constexpr int32_t INVALID_NUMBER = 202;
45 constexpr const char* BUNDLE_NAME = "bundleName";
46 constexpr const char* COMPLETE = "complete";
47 constexpr const char* FAIL = "fail";
48 constexpr const char* SUCCESS = "success";
49 }
50 
~CheckPackageHasInstalledOptions()51 CheckPackageHasInstalledOptions::~CheckPackageHasInstalledOptions()
52 {
53     if (successRef) {
54         APP_LOGD("CheckPackageHasInstalledOptions::~CheckPackageHasInstalledOptions delete successRef");
55         napi_delete_reference(env, successRef);
56         successRef = nullptr;
57     }
58     if (failRef) {
59         APP_LOGD("CheckPackageHasInstalledOptions::~CheckPackageHasInstalledOptions delete failRef");
60         napi_delete_reference(env, failRef);
61         failRef = nullptr;
62     }
63     if (completeRef) {
64         APP_LOGD("CheckPackageHasInstalledOptions::~CheckPackageHasInstalledOptions delete completeRef");
65         napi_delete_reference(env, completeRef);
66         completeRef = nullptr;
67     }
68     if (asyncWork) {
69         APP_LOGD("CheckPackageHasInstalledOptions::~CheckPackageHasInstalledOptions delete callbackRef");
70         napi_delete_async_work(env, asyncWork);
71         asyncWork = nullptr;
72     }
73 }
74 
GetBundleMgr()75 static OHOS::sptr<OHOS::AppExecFwk::IBundleMgr> GetBundleMgr()
76 {
77     auto systemAbilityManager = OHOS::SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
78     if (systemAbilityManager == nullptr) {
79         APP_LOGE("GetBundleMgr GetSystemAbilityManager is null");
80         return nullptr;
81     }
82     auto bundleMgrSa = systemAbilityManager->GetSystemAbility(OHOS::BUNDLE_MGR_SERVICE_SYS_ABILITY_ID);
83     if (bundleMgrSa == nullptr) {
84         APP_LOGE("GetBundleMgr GetSystemAbility is null");
85         return nullptr;
86     }
87     auto bundleMgr = OHOS::iface_cast<IBundleMgr>(bundleMgrSa);
88     if (bundleMgr == nullptr) {
89         APP_LOGE("GetBundleMgr iface_cast get null");
90     }
91     return bundleMgr;
92 }
93 
GetStringFromNAPI(napi_env env,napi_value value)94 static std::string GetStringFromNAPI(napi_env env, napi_value value)
95 {
96     std::string result;
97     size_t size = 0;
98 
99     if (napi_get_value_string_utf8(env, value, nullptr, NAPI_RETURN_ZERO, &size) != napi_ok) {
100         APP_LOGE("can not get string size");
101         return "";
102     }
103     result.reserve(size + NAPI_RETURN_ONE);
104     result.resize(size);
105     if (napi_get_value_string_utf8(env, value, result.data(), (size + NAPI_RETURN_ONE), &size) != napi_ok) {
106         APP_LOGE("can not get string value");
107         return "";
108     }
109     return result;
110 }
111 
ParseCheckPackageHasInstalledOptions(napi_env env,napi_value param,OHOS::AppExecFwk::CheckPackageHasInstalledOptions * hasInstalledOptions)112 static void ParseCheckPackageHasInstalledOptions(napi_env env, napi_value param,
113     OHOS::AppExecFwk::CheckPackageHasInstalledOptions *hasInstalledOptions)
114 {
115     if (hasInstalledOptions == nullptr) {
116         APP_LOGW("hasInstalledOptions is nullptr");
117         return;
118     }
119     napi_valuetype valueType;
120     napi_value prop = nullptr;
121     // parse bundleName
122     napi_get_named_property(env, param, BUNDLE_NAME, &prop);
123     napi_typeof(env, prop, &valueType);
124     hasInstalledOptions->isString = false;
125     if (valueType == napi_string) {
126         hasInstalledOptions->bundleName = GetStringFromNAPI(env, prop);
127         hasInstalledOptions->isString = true;
128     }
129     // parse success function
130     napi_value jsFunc = nullptr;
131     napi_ref jsFuncRef = nullptr;
132     napi_get_named_property(env, param, SUCCESS, &jsFunc);
133     napi_typeof(env, jsFunc, &valueType);
134     if (valueType == napi_function) {
135         napi_create_reference(env, jsFunc, NAPI_RETURN_ONE, &jsFuncRef);
136         hasInstalledOptions->successRef = jsFuncRef;
137     }
138     // parse fail function
139     napi_get_named_property(env, param, FAIL, &jsFunc);
140     napi_typeof(env, jsFunc, &valueType);
141     if (valueType == napi_function) {
142         napi_create_reference(env, jsFunc, NAPI_RETURN_ONE, &jsFuncRef);
143         hasInstalledOptions->failRef = jsFuncRef;
144     }
145     // parse complete function
146     napi_get_named_property(env, param, COMPLETE, &jsFunc);
147     napi_typeof(env, jsFunc, &valueType);
148     if (valueType == napi_function) {
149         napi_create_reference(env, jsFunc, NAPI_RETURN_ONE, &jsFuncRef);
150         hasInstalledOptions->completeRef = jsFuncRef;
151     }
152 }
153 
InnerHasInstalled(std::string bundleName)154 static bool InnerHasInstalled(std::string bundleName)
155 {
156     if (bundleName.empty()) {
157         APP_LOGE("bundleName is invalid param");
158         return false;
159     }
160     auto iBundleMgr = GetBundleMgr();
161     if (iBundleMgr == nullptr) {
162         APP_LOGE("can not get iBundleMgr");
163         return false;
164     }
165     BundleInfo bundleInfo;
166     bool ret = iBundleMgr->GetBundleInfo(bundleName, 0, bundleInfo);
167     if (!ret) {
168         APP_LOGE("bundleInfo is not find, bundleName=%{public}s", bundleName.c_str());
169     }
170     return ret;
171 }
172 
ConvertCheckPackageHasInstalledResponse(napi_env env,napi_value hasInstalledResponseObj,const OHOS::AppExecFwk::CheckPackageHasInstalledResponse & response)173 static void ConvertCheckPackageHasInstalledResponse(napi_env env, napi_value hasInstalledResponseObj,
174     const OHOS::AppExecFwk::CheckPackageHasInstalledResponse &response)
175 {
176     APP_LOGD("convert CheckPackageHasInstalledResponse start");
177     napi_value nResult;
178     NAPI_CALL_RETURN_VOID(env, napi_get_boolean(env, response.result, &nResult));
179     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, hasInstalledResponseObj, "result", nResult));
180 }
181 
HasInstalledExecute(napi_env env,void * data)182 static void HasInstalledExecute(napi_env env, void *data)
183 {
184     APP_LOGD("NAPI_HasInstalled, worker pool thread execute");
185     CheckPackageHasInstalledOptions *asyncCallbackInfo = static_cast<CheckPackageHasInstalledOptions *>(data);
186     if (asyncCallbackInfo == nullptr) {
187         APP_LOGW("NAPI_HasInstalled, asyncCallbackInfo == nullptr");
188         return;
189     }
190     if (!asyncCallbackInfo->errCode && asyncCallbackInfo->isString && asyncCallbackInfo->successRef) {
191         asyncCallbackInfo->response.result = InnerHasInstalled(asyncCallbackInfo->bundleName);
192     }
193     APP_LOGD("NAPI_HasInstalled, worker pool thread execute end");
194 }
195 
HasInstalledAsyncComplete(napi_env env,napi_status status,void * data)196 static void HasInstalledAsyncComplete(napi_env env, napi_status status, void *data)
197 {
198     APP_LOGD("NAPI_HasInstalled, main event thread complete");
199     CheckPackageHasInstalledOptions *asyncCallbackInfo = static_cast<CheckPackageHasInstalledOptions *>(data);
200     std::unique_ptr<CheckPackageHasInstalledOptions> callbackPtr {asyncCallbackInfo};
201     if (asyncCallbackInfo == nullptr) {
202         APP_LOGW("NAPI_HasInstalled, asyncCallbackInfo == nullptr");
203         return;
204     }
205     napi_value callback = nullptr;
206     napi_value placeHolder = nullptr;
207     if (!asyncCallbackInfo->isString) {
208         if (asyncCallbackInfo->failRef) {
209             napi_value result[ARGS_SIZE_TWO] = { 0 };
210             NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, "value is not an available number",
211                 NAPI_AUTO_LENGTH, &result[PARAM0]));
212             NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, INVALID_NUMBER, &result[PARAM1]));
213             NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, asyncCallbackInfo->failRef, &callback));
214             napi_call_function(env, nullptr, callback, ARGS_SIZE_TWO, result, &placeHolder);
215         }
216     } else {
217         if (asyncCallbackInfo->successRef) {
218             napi_value result[ARGS_SIZE_ONE] = { 0 };
219             NAPI_CALL_RETURN_VOID(env, napi_create_object(env, &result[PARAM0]));
220             ConvertCheckPackageHasInstalledResponse(env, result[PARAM0], asyncCallbackInfo->response);
221             NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, asyncCallbackInfo->successRef, &callback));
222             napi_call_function(env, nullptr, callback, ARGS_SIZE_ONE, result, &placeHolder);
223         }
224     }
225     if (asyncCallbackInfo->completeRef) {
226         NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, asyncCallbackInfo->completeRef, &callback));
227         napi_call_function(env, nullptr, callback, 0, nullptr, &placeHolder);
228     }
229     APP_LOGD("NAPI_HasInstalled, main event thread complete end");
230 }
231 
HasInstalled(napi_env env,napi_callback_info info)232 napi_value HasInstalled(napi_env env, napi_callback_info info)
233 {
234     APP_LOGD("asyncCallback");
235     size_t requireArgc = ARGS_SIZE_ONE;
236     size_t argc = ARGS_SIZE_TWO;
237     napi_value argv[ARGS_SIZE_TWO] = { 0 };
238     napi_value thisArg = nullptr;
239     void *data = nullptr;
240 
241     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisArg, &data));
242     if (argc != requireArgc) {
243         APP_LOGW("requires 1 parameter");
244         return nullptr;
245     }
246 
247     CheckPackageHasInstalledOptions *asyncCallbackInfo = new (std::nothrow) CheckPackageHasInstalledOptions();
248     if (asyncCallbackInfo == nullptr) {
249         return nullptr;
250     }
251     std::unique_ptr<CheckPackageHasInstalledOptions> callbackPtr {asyncCallbackInfo};
252     asyncCallbackInfo->env = env;
253     napi_valuetype valueType = napi_undefined;
254     NAPI_CALL(env, napi_typeof(env, argv[PARAM0], &valueType));
255     if (valueType == napi_object) {
256         ParseCheckPackageHasInstalledOptions(env, argv[PARAM0], asyncCallbackInfo);
257     } else {
258         asyncCallbackInfo->errCode = INVALID_PARAM;
259     }
260 
261     napi_value resource = nullptr;
262     NAPI_CALL(env, napi_create_string_utf8(env, "JSHasInstalled", NAPI_AUTO_LENGTH, &resource));
263     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource, HasInstalledExecute,
264                        HasInstalledAsyncComplete, (void *)asyncCallbackInfo, &asyncCallbackInfo->asyncWork));
265     NAPI_CALL(env, napi_queue_async_work(env, asyncCallbackInfo->asyncWork));
266     callbackPtr.release();
267     return nullptr;
268 }
269 }  // namespace AppExecFwk
270 }  // namespace OHOS
271