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
31namespace OHOS {
32namespace AppExecFwk {
33using namespace OHOS;
34using namespace OHOS::AAFwk;
35using namespace OHOS::AppExecFwk;
36namespace {
37constexpr int32_t NAPI_RETURN_ZERO = 0;
38constexpr size_t ARGS_SIZE_ONE = 1;
39constexpr size_t ARGS_SIZE_TWO = 2;
40constexpr int32_t PARAM0 = 0;
41constexpr int32_t PARAM1 = 1;
42constexpr int32_t NAPI_RETURN_ONE = 1;
43constexpr int32_t INVALID_PARAM = 2;
44constexpr int32_t INVALID_NUMBER = 202;
45constexpr const char* BUNDLE_NAME = "bundleName";
46constexpr const char* COMPLETE = "complete";
47constexpr const char* FAIL = "fail";
48constexpr const char* SUCCESS = "success";
49}
50
51CheckPackageHasInstalledOptions::~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
75static 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
94static 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
112static 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
154static 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
173static 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
182static 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
196static 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
232napi_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