1 /*
2 * Copyright (c) 2025 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 <string>
17
18 #include "ability_manager_client.h"
19 #include "ani.h"
20 #include "ani_common_start_options.h"
21 #include <ani_signature_builder.h>
22 #include "app_log_wrapper.h"
23 #include "business_error_ani.h"
24 #include "common_fun_ani.h"
25 #include "common_func.h"
26 #include "ipc_skeleton.h"
27 #include "js_launcher_service.h"
28 #include "launcher_ability_info.h"
29 #include "napi_constants.h"
30 #include "shortcut_info.h"
31 #include "start_options.h"
32
33 namespace OHOS {
34 namespace AppExecFwk {
35 namespace {
36 constexpr int32_t EMPTY_USER_ID = -500;
37 constexpr const char* NS_NAME_LAUNCHERMANAGER = "@ohos.bundle.launcherBundleManager.launcherBundleManager";
38
39 const std::map<int32_t, int32_t> START_SHORTCUT_RES_MAP = {
40 { ERR_OK, ERR_OK },
41 { ERR_PERMISSION_DENIED, ERR_BUNDLE_MANAGER_PERMISSION_DENIED },
42 { ERR_NOT_SYSTEM_APP, ERR_BUNDLE_MANAGER_SYSTEM_API_DENIED }
43 };
44 } // namespace
45
AniStartShortcut(ani_env * env,ani_object aniShortcutInfo,ani_object aniStartOptions)46 static void AniStartShortcut(ani_env *env, ani_object aniShortcutInfo, ani_object aniStartOptions)
47 {
48 APP_LOGD("ani StartShortcut called");
49 ShortcutInfo shortcutInfo;
50 if (!CommonFunAni::ParseShortcutInfo(env, aniShortcutInfo, shortcutInfo)) {
51 APP_LOGE("parse shortcutInfo failed");
52 BusinessErrorAni::ThrowError(env, ERROR_PARAM_CHECK_ERROR, PARSE_SHORTCUT_INFO_FAILED);
53 return;
54 }
55 if (shortcutInfo.intents.empty()) {
56 APP_LOGW("intents is empty");
57 BusinessErrorAni::ThrowError(env, ERROR_PARAM_CHECK_ERROR, ERROR_EMPTY_WANT);
58 return;
59 }
60 AAFwk::Want want;
61 ElementName element;
62 element.SetBundleName(shortcutInfo.intents[0].targetBundle);
63 element.SetModuleName(shortcutInfo.intents[0].targetModule);
64 element.SetAbilityName(shortcutInfo.intents[0].targetClass);
65 want.SetElement(element);
66 std::for_each(shortcutInfo.intents[0].parameters.begin(), shortcutInfo.intents[0].parameters.end(),
67 [&want](const auto& item) { want.SetParam(item.first, item.second); });
68
69 want.SetParam(AAFwk::Want::PARAM_APP_CLONE_INDEX_KEY, shortcutInfo.appIndex);
70 auto abilityManagerClient = AAFwk::AbilityManagerClient::GetInstance();
71 if (abilityManagerClient == nullptr) {
72 APP_LOGI("abilityManagerClient is nullptr");
73 return;
74 }
75 StartOptions startOptions;
76 if (aniStartOptions != nullptr) {
77 if (!UnwrapStartOptions(env, aniStartOptions, startOptions)) {
78 APP_LOGE("ParseStartOptions error");
79 BusinessErrorAni::ThrowError(env, ERROR_PARAM_CHECK_ERROR, PARSE_START_OPTIONS_FAILED);
80 return;
81 }
82 }
83 ErrCode result = abilityManagerClient->StartShortcut(want, startOptions);
84 auto iter = START_SHORTCUT_RES_MAP.find(result);
85 result = iter == START_SHORTCUT_RES_MAP.end() ? ERR_BUNDLE_MANAGER_START_SHORTCUT_FAILED : iter->second;
86 if (result != ERR_OK) {
87 APP_LOGE("StartShortcut failed, result: %{public}d", result);
88 BusinessErrorAni::ThrowCommonError(
89 env, CommonFunc::ConvertErrCode(result), START_SHORTCUT, Constants::PERMISSION_START_SHORTCUT);
90 }
91 }
92
AniGetShortcutInfo(ani_env * env,ani_string aniBundleName,ani_double aniUserId,ani_boolean aniIsSync)93 static ani_object AniGetShortcutInfo(ani_env *env,
94 ani_string aniBundleName, ani_double aniUserId, ani_boolean aniIsSync)
95 {
96 APP_LOGD("ani GetShortcutInfo called");
97 std::string bundleName;
98 if (!CommonFunAni::ParseString(env, aniBundleName, bundleName)) {
99 APP_LOGE("parse bundleName failed");
100 BusinessErrorAni::ThrowCommonError(env, ERROR_PARAM_CHECK_ERROR, BUNDLE_NAME, TYPE_STRING);
101 return nullptr;
102 }
103 int32_t userId = EMPTY_USER_ID;
104 if (!CommonFunAni::TryCastDoubleTo(aniUserId, &userId)) {
105 APP_LOGW("try cast userId failed");
106 }
107 if (userId == EMPTY_USER_ID) {
108 userId = Constants::UNSPECIFIED_USERID;
109 }
110 bool isSync = CommonFunAni::AniBooleanToBool(aniIsSync);
111 auto launcherService = JSLauncherService::GetLauncherService();
112 if (launcherService == nullptr) {
113 APP_LOGE("launcherService is nullptr");
114 BusinessErrorAni::ThrowCommonError(env, ERROR_BUNDLE_SERVICE_EXCEPTION,
115 isSync ? GET_SHORTCUT_INFO_SYNC : GET_SHORTCUT_INFO, Constants::PERMISSION_GET_BUNDLE_INFO_PRIVILEGED);
116 return nullptr;
117 }
118
119 std::vector<ShortcutInfo> shortcutInfos;
120 ErrCode ret = launcherService->GetShortcutInfoV9(bundleName, shortcutInfos, userId);
121 if (ret != ERR_OK) {
122 APP_LOGE("GetShortcutInfoV9 failed, ret %{public}d", ret);
123 BusinessErrorAni::ThrowCommonError(env, CommonFunc::ConvertErrCode(ret),
124 isSync ? GET_SHORTCUT_INFO_SYNC : GET_SHORTCUT_INFO, Constants::PERMISSION_GET_BUNDLE_INFO_PRIVILEGED);
125 return nullptr;
126 }
127 ani_object shortcutInfosObject =
128 CommonFunAni::ConvertAniArray(env, shortcutInfos, CommonFunAni::ConvertShortcutInfo);
129 if (shortcutInfosObject == nullptr) {
130 APP_LOGE("nullptr shortcutInfosObject");
131 return nullptr;
132 }
133 return shortcutInfosObject;
134 }
135
AniGetLauncherAbilityInfo(ani_env * env,ani_string aniBundleName,ani_double aniUserId,ani_boolean aniIsSync)136 static ani_object AniGetLauncherAbilityInfo(ani_env *env,
137 ani_string aniBundleName, ani_double aniUserId, ani_boolean aniIsSync)
138 {
139 APP_LOGD("ani GetLauncherAbilityInfo called");
140 std::string bundleName;
141 if (!CommonFunAni::ParseString(env, aniBundleName, bundleName)) {
142 APP_LOGE("parse bundleName failed");
143 BusinessErrorAni::ThrowCommonError(env, ERROR_PARAM_CHECK_ERROR, BUNDLE_NAME, TYPE_STRING);
144 return nullptr;
145 }
146 int32_t userId = Constants::UNSPECIFIED_USERID;
147 if (!CommonFunAni::TryCastDoubleTo(aniUserId, &userId)) {
148 APP_LOGE("try cast userId failed");
149 BusinessErrorAni::ThrowCommonError(env, ERROR_PARAM_CHECK_ERROR, USER_ID, TYPE_NUMBER);
150 return nullptr;
151 }
152 bool isSync = CommonFunAni::AniBooleanToBool(aniIsSync);
153
154 auto launcherService = JSLauncherService::GetLauncherService();
155 if (launcherService == nullptr) {
156 APP_LOGE("launcherService is nullptr");
157 BusinessErrorAni::ThrowCommonError(env, ERROR_BUNDLE_SERVICE_EXCEPTION,
158 isSync ? GET_LAUNCHER_ABILITY_INFO_SYNC : GET_LAUNCHER_ABILITY_INFO,
159 Constants::PERMISSION_GET_BUNDLE_INFO_PRIVILEGED);
160 return nullptr;
161 }
162
163 std::vector<LauncherAbilityInfo> launcherAbilityInfos;
164 ErrCode ret = ERR_OK;
165 if (isSync) {
166 ret = launcherService->GetLauncherAbilityInfoSync(bundleName, userId, launcherAbilityInfos);
167 } else {
168 ret = launcherService->GetLauncherAbilityByBundleName(bundleName, userId, launcherAbilityInfos);
169 }
170 if (ret != ERR_OK) {
171 APP_LOGE("GetLauncherAbilityInfo failed ret:%{public}d, bundleName:%{public}s, userId:%{public}d",
172 ret, bundleName.c_str(), userId);
173 BusinessErrorAni::ThrowCommonError(env, CommonFunc::ConvertErrCode(ret),
174 isSync ? GET_LAUNCHER_ABILITY_INFO_SYNC : GET_LAUNCHER_ABILITY_INFO,
175 Constants::PERMISSION_GET_BUNDLE_INFO_PRIVILEGED);
176 return nullptr;
177 }
178
179 ani_object launcherAbilityInfosObject = CommonFunAni::ConvertAniArray(
180 env, launcherAbilityInfos, CommonFunAni::ConvertLauncherAbilityInfo);
181 if (launcherAbilityInfosObject == nullptr) {
182 APP_LOGE("nullptr launcherAbilityInfosObject");
183 }
184
185 return launcherAbilityInfosObject;
186 }
187
AniGetAllLauncherAbilityInfo(ani_env * env,ani_double aniUserId)188 static ani_object AniGetAllLauncherAbilityInfo(ani_env *env, ani_double aniUserId)
189 {
190 APP_LOGD("ani GetAllLauncherAbilityInfo called");
191 int32_t userId = 0;
192 if (!CommonFunAni::TryCastDoubleTo(aniUserId, &userId)) {
193 APP_LOGE("try cast userId failed");
194 BusinessErrorAni::ThrowCommonError(env, ERROR_PARAM_CHECK_ERROR, USER_ID, TYPE_NUMBER);
195 return nullptr;
196 }
197
198 auto launcherService = JSLauncherService::GetLauncherService();
199 if (launcherService == nullptr) {
200 APP_LOGE("launcherService is nullptr");
201 BusinessErrorAni::ThrowCommonError(env, ERROR_BUNDLE_SERVICE_EXCEPTION,
202 GET_ALL_LAUNCHER_ABILITY_INFO, Constants::PERMISSION_GET_BUNDLE_INFO_PRIVILEGED);
203 return nullptr;
204 }
205
206 std::vector<LauncherAbilityInfo> launcherAbilityInfos;
207 ErrCode ret = launcherService->GetAllLauncherAbility(userId, launcherAbilityInfos);
208 if (ret != ERR_OK) {
209 APP_LOGE("GetAllLauncherAbility failed ret:%{public}d,userId:%{public}d", ret, userId);
210 BusinessErrorAni::ThrowCommonError(env, CommonFunc::ConvertErrCode(ret),
211 GET_ALL_LAUNCHER_ABILITY_INFO, Constants::PERMISSION_GET_BUNDLE_INFO_PRIVILEGED);
212 return nullptr;
213 }
214
215 ani_object launcherAbilityInfosObject = CommonFunAni::ConvertAniArray(
216 env, launcherAbilityInfos, CommonFunAni::ConvertLauncherAbilityInfo);
217 if (launcherAbilityInfosObject == nullptr) {
218 APP_LOGE("nullptr launcherAbilityInfosObject");
219 }
220
221 return launcherAbilityInfosObject;
222 }
223
224 extern "C" {
ANI_Constructor(ani_vm * vm,uint32_t * result)225 ANI_EXPORT ani_status ANI_Constructor(ani_vm *vm, uint32_t *result)
226 {
227 APP_LOGI("ANI_Constructor launcherBundleManager called");
228 ani_env* env;
229 ani_status status = vm->GetEnv(ANI_VERSION_1, &env);
230 RETURN_ANI_STATUS_IF_NOT_OK(status, "Unsupported ANI_VERSION_1");
231
232 arkts::ani_signature::Namespace nsName = arkts::ani_signature::Builder::BuildNamespace(NS_NAME_LAUNCHERMANAGER);
233 ani_namespace kitNs = nullptr;
234 status = env->FindNamespace(nsName.Descriptor().c_str(), &kitNs);
235 if (status != ANI_OK) {
236 APP_LOGE("FindNamespace: %{public}s fail with %{public}d", NS_NAME_LAUNCHERMANAGER, status);
237 return status;
238 }
239
240 std::array methods = {
241 ani_native_function { "startShortcutNative", nullptr, reinterpret_cast<void*>(AniStartShortcut) },
242 ani_native_function { "getShortcutInfoNative", nullptr, reinterpret_cast<void*>(AniGetShortcutInfo) },
243 ani_native_function { "getLauncherAbilityInfoNative", nullptr,
244 reinterpret_cast<void*>(AniGetLauncherAbilityInfo) },
245 ani_native_function { "getAllLauncherAbilityInfoNative", nullptr,
246 reinterpret_cast<void*>(AniGetAllLauncherAbilityInfo) },
247 };
248
249 status = env->Namespace_BindNativeFunctions(kitNs, methods.data(), methods.size());
250 if (status != ANI_OK) {
251 APP_LOGE("Namespace_BindNativeFunctions: %{public}s fail with %{public}d", NS_NAME_LAUNCHERMANAGER, status);
252 return status;
253 }
254
255 *result = ANI_VERSION_1;
256
257 APP_LOGI("ANI_Constructor finished");
258
259 return ANI_OK;
260 }
261 } // extern "C"
262 } // namespace AppExecFwk
263 } // namespace OHOS