1 /*
2 * Copyright (c) 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 "bundle_clone_installer.h"
17
18 #include "ability_manager_helper.h"
19 #include "bms_extension_data_mgr.h"
20 #include "bundle_mgr_service.h"
21 #include "bundle_permission_mgr.h"
22 #include "bundle_resource_helper.h"
23 #include "code_protect_bundle_info.h"
24 #include "datetime_ex.h"
25 #include "hitrace_meter.h"
26 #include "installd_client.h"
27 #include "inner_bundle_clone_common.h"
28 #include "perf_profile.h"
29 #include "scope_guard.h"
30
31 namespace OHOS {
32 namespace AppExecFwk {
33 using namespace OHOS::Security;
34
35 std::mutex gCloneInstallerMutex;
36
BundleCloneInstaller()37 BundleCloneInstaller::BundleCloneInstaller()
38 {
39 APP_LOGD("bundle clone installer instance is created");
40 }
41
~BundleCloneInstaller()42 BundleCloneInstaller::~BundleCloneInstaller()
43 {
44 APP_LOGD("bundle clone installer instance is destroyed");
45 }
46
InstallCloneApp(const std::string &bundleName, const int32_t userId, int32_t &appIndex)47 ErrCode BundleCloneInstaller::InstallCloneApp(const std::string &bundleName,
48 const int32_t userId, int32_t &appIndex)
49 {
50 HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
51 APP_LOGD("InstallCloneApp %{public}s begin", bundleName.c_str());
52
53 PerfProfile::GetInstance().SetBundleInstallStartTime(GetTickCount());
54
55 ErrCode result = ProcessCloneBundleInstall(bundleName, userId, appIndex);
56 NotifyBundleEvents installRes = {
57 .type = NotifyType::INSTALL,
58 .resultCode = result,
59 .accessTokenId = accessTokenId_,
60 .uid = uid_,
61 .appIndex = appIndex,
62 .bundleName = bundleName,
63 };
64 std::shared_ptr<BundleCommonEventMgr> commonEventMgr = std::make_shared<BundleCommonEventMgr>();
65 std::shared_ptr<BundleDataMgr> dataMgr = DelayedSingleton<BundleMgrService>::GetInstance()->GetDataMgr();
66 commonEventMgr->NotifyBundleStatus(installRes, dataMgr);
67
68 ResetInstallProperties();
69 PerfProfile::GetInstance().SetBundleInstallEndTime(GetTickCount());
70 return result;
71 }
72
UninstallCloneApp( const std::string &bundleName, const int32_t userId, const int32_t appIndex)73 ErrCode BundleCloneInstaller::UninstallCloneApp(
74 const std::string &bundleName, const int32_t userId, const int32_t appIndex)
75 {
76 HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
77 APP_LOGD("UninstallCloneApp %{public}s _ %{public}d begin", bundleName.c_str(), appIndex);
78
79 PerfProfile::GetInstance().SetBundleUninstallStartTime(GetTickCount());
80
81 ErrCode result = ProcessCloneBundleUninstall(bundleName, userId, appIndex);
82 NotifyBundleEvents installRes = {
83 .type = NotifyType::UNINSTALL_BUNDLE,
84 .resultCode = result,
85 .accessTokenId = accessTokenId_,
86 .bundleName = bundleName,
87 .uid = uid_,
88 .appIndex = appIndex
89 };
90 std::shared_ptr<BundleCommonEventMgr> commonEventMgr = std::make_shared<BundleCommonEventMgr>();
91 std::shared_ptr<BundleDataMgr> dataMgr = DelayedSingleton<BundleMgrService>::GetInstance()->GetDataMgr();
92 commonEventMgr->NotifyBundleStatus(installRes, dataMgr);
93
94 ResetInstallProperties();
95 PerfProfile::GetInstance().SetBundleUninstallEndTime(GetTickCount());
96 return result;
97 }
98
UninstallAllCloneApps(const std::string &bundleName, int32_t userId)99 ErrCode BundleCloneInstaller::UninstallAllCloneApps(const std::string &bundleName, int32_t userId)
100 {
101 // All clone will be uninstalled when the original application is updated or uninstalled
102 APP_LOGI_NOFUNC("UninstallAllCloneApps begin");
103 if (bundleName.empty()) {
104 APP_LOGE("UninstallAllCloneApps failed due to empty bundle name");
105 return ERR_APPEXECFWK_CLONE_UNINSTALL_INVALID_BUNDLE_NAME;
106 }
107 if (GetDataMgr() != ERR_OK) {
108 APP_LOGE("Get dataMgr shared_ptr nullptr");
109 return ERR_APPEXECFWK_CLONE_UNINSTALL_INTERNAL_ERROR;
110 }
111 if (!dataMgr_->HasUserId(userId)) {
112 APP_LOGE("install clone app user %{public}d not exist", userId);
113 return ERR_APPEXECFWK_CLONE_UNINSTALL_USER_NOT_EXIST;
114 }
115 InnerBundleInfo info;
116 bool isExist = dataMgr_->FetchInnerBundleInfo(bundleName, info);
117 if (!isExist) {
118 APP_LOGE("the bundle is not installed");
119 return ERR_APPEXECFWK_CLONE_UNINSTALL_APP_NOT_EXISTED;
120 }
121 InnerBundleUserInfo userInfo;
122 if (!info.GetInnerBundleUserInfo(userId, userInfo)) {
123 APP_LOGE_NOFUNC("the origin application is not installed at current user");
124 return ERR_APPEXECFWK_CLONE_UNINSTALL_NOT_INSTALLED_AT_SPECIFIED_USERID;
125 }
126 ErrCode result = ERR_OK;
127 for (auto it = userInfo.cloneInfos.begin(); it != userInfo.cloneInfos.end(); it++) {
128 if (UninstallCloneApp(bundleName, userId, std::stoi(it->first)) != ERR_OK) {
129 APP_LOGE("UninstallCloneApp failed, appIndex %{public}s", it->first.c_str());
130 result = ERR_APPEXECFWK_CLONE_UNINSTALL_INTERNAL_ERROR;
131 }
132 }
133 APP_LOGI_NOFUNC("UninstallAllCloneApps end");
134 return result;
135 }
136
ProcessCloneBundleInstall(const std::string &bundleName, const int32_t userId, int32_t &appIndex)137 ErrCode BundleCloneInstaller::ProcessCloneBundleInstall(const std::string &bundleName,
138 const int32_t userId, int32_t &appIndex)
139 {
140 if (bundleName.empty()) {
141 APP_LOGE("the bundle name is empty");
142 return ERR_APPEXECFWK_CLONE_INSTALL_PARAM_ERROR;
143 }
144
145 std::shared_ptr<BundleDataMgr> dataMgr = DelayedSingleton<BundleMgrService>::GetInstance()->GetDataMgr();
146
147 std::lock_guard<std::mutex> cloneGuard(gCloneInstallerMutex);
148 // 1. check whether original application installed or not
149 InnerBundleInfo info;
150 bool isExist = dataMgr->FetchInnerBundleInfo(bundleName, info);
151 if (!isExist) {
152 APP_LOGE("the bundle is not installed");
153 return ERR_APPEXECFWK_CLONE_INSTALL_APP_NOT_EXISTED;
154 }
155
156 // 2. obtain userId
157 if (userId < Constants::DEFAULT_USERID) {
158 APP_LOGE("userId(%{public}d) invalid", userId);
159 return ERR_APPEXECFWK_CLONE_INSTALL_USER_NOT_EXIST;
160 }
161 if (!dataMgr->HasUserId(userId)) {
162 APP_LOGE("install clone app user %{public}d not exist", userId);
163 return ERR_APPEXECFWK_CLONE_INSTALL_USER_NOT_EXIST;
164 }
165
166 // 3. check whether original application installed at current userId or not
167 InnerBundleUserInfo userInfo;
168 if (!info.GetInnerBundleUserInfo(userId, userInfo)) {
169 APP_LOGE("the origin application is not installed at current user");
170 return ERR_APPEXECFWK_CLONE_INSTALL_NOT_INSTALLED_AT_SPECIFIED_USERID;
171 }
172
173 ErrCode ackRes = info.VerifyAndAckCloneAppIndex(userId, appIndex);
174 if (ackRes != ERR_OK) {
175 APP_LOGE("installCloneApp fail for verifyAndAck res %{public}d", ackRes);
176 return ackRes;
177 }
178
179 // uid
180 std::string cloneBundleName = BundleCloneCommonHelper::GetCloneBundleIdKey(bundleName, appIndex);
181 InnerBundleUserInfo tmpUserInfo;
182 tmpUserInfo.bundleName = cloneBundleName;
183 tmpUserInfo.bundleUserInfo.userId = userId;
184 dataMgr->GenerateUidAndGid(tmpUserInfo);
185 int32_t uid = tmpUserInfo.uid;
186
187 // 4. generate the accesstoken id and inherit original permissions
188 info.SetAppIndex(appIndex);
189 Security::AccessToken::AccessTokenIDEx newTokenIdEx;
190 if (BundlePermissionMgr::InitHapToken(info, userId, 0, newTokenIdEx) != ERR_OK) {
191 APP_LOGE("bundleName:%{public}s InitHapToken failed", bundleName.c_str());
192 return ERR_APPEXECFWK_INSTALL_GRANT_REQUEST_PERMISSIONS_FAILED;
193 }
194 ScopeGuard applyAccessTokenGuard([&] {
195 BundlePermissionMgr::DeleteAccessTokenId(newTokenIdEx.tokenIdExStruct.tokenID);
196 });
197
198 InnerBundleCloneInfo attr = {
199 .userId = userId,
200 .appIndex = appIndex,
201 .uid = uid,
202 .gids = tmpUserInfo.gids,
203 .accessTokenId = newTokenIdEx.tokenIdExStruct.tokenID,
204 .accessTokenIdEx = newTokenIdEx.tokenIDEx,
205 };
206 uid_ = uid;
207 accessTokenId_ = newTokenIdEx.tokenIdExStruct.tokenID;
208
209 ErrCode result = CreateCloneDataDir(info, userId, uid, appIndex);
210 if (result != ERR_OK) {
211 APP_LOGE("InstallCloneApp create clone dir failed");
212 return result;
213 }
214 ScopeGuard createCloneDataDirGuard([&] { RemoveCloneDataDir(bundleName, userId, appIndex); });
215
216 ScopeGuard addCloneBundleGuard([&] { dataMgr->RemoveCloneBundle(bundleName, userId, appIndex); });
217 ErrCode addRes = dataMgr->AddCloneBundle(bundleName, attr);
218 if (addRes != ERR_OK) {
219 APP_LOGE("dataMgr add clone bundle fail, bundleName: %{public}s, userId: %{public}d, appIndex: %{public}d",
220 bundleName.c_str(), userId, appIndex);
221 return addRes;
222 }
223
224 // process icon and label
225 {
226 auto appIndexes = info.GetCloneBundleAppIndexes();
227 // appIndex not exist, need parse
228 if (appIndexes.find(appIndex) == appIndexes.end()) {
229 BundleResourceHelper::AddCloneBundleResourceInfo(bundleName, appIndex, userId);
230 }
231 }
232 AddKeyOperation(bundleName, appIndex, userId, uid);
233
234 // total to commit, avoid rollback
235 applyAccessTokenGuard.Dismiss();
236 createCloneDataDirGuard.Dismiss();
237 addCloneBundleGuard.Dismiss();
238 APP_LOGI("InstallCloneApp %{public}s appIndex:%{public}d succesfully", bundleName.c_str(), appIndex);
239 return ERR_OK;
240 }
241
ProcessCloneBundleUninstall(const std::string &bundleName, int32_t userId, int32_t appIndex)242 ErrCode BundleCloneInstaller::ProcessCloneBundleUninstall(const std::string &bundleName,
243 int32_t userId, int32_t appIndex)
244 {
245 if (bundleName.empty()) {
246 APP_LOGE("UninstallCloneApp failed due to empty bundle name");
247 return ERR_APPEXECFWK_CLONE_UNINSTALL_INVALID_BUNDLE_NAME;
248 }
249 if (appIndex < ServiceConstants::CLONE_APP_INDEX_MIN || appIndex > ServiceConstants::CLONE_APP_INDEX_MAX) {
250 APP_LOGE("Add Clone Bundle Fail, appIndex: %{public}d not in valid range", appIndex);
251 return ERR_APPEXECFWK_CLONE_UNINSTALL_INVALID_APP_INDEX;
252 }
253 if (GetDataMgr() != ERR_OK) {
254 APP_LOGE("Get dataMgr shared_ptr nullptr");
255 return ERR_APPEXECFWK_CLONE_UNINSTALL_INTERNAL_ERROR;
256 }
257 std::lock_guard<std::mutex> cloneGuard(gCloneInstallerMutex);
258 if (!dataMgr_->HasUserId(userId)) {
259 APP_LOGE("install clone app user %{public}d not exist", userId);
260 return ERR_APPEXECFWK_CLONE_UNINSTALL_USER_NOT_EXIST;
261 }
262 InnerBundleInfo info;
263 bool isExist = dataMgr_->FetchInnerBundleInfo(bundleName, info);
264 if (!isExist) {
265 APP_LOGE("the bundle is not installed");
266 return ERR_APPEXECFWK_CLONE_UNINSTALL_APP_NOT_EXISTED;
267 }
268 InnerBundleUserInfo userInfo;
269 if (!info.GetInnerBundleUserInfo(userId, userInfo)) {
270 APP_LOGE("the origin application is not installed at current user");
271 return ERR_APPEXECFWK_CLONE_UNINSTALL_NOT_INSTALLED_AT_SPECIFIED_USERID;
272 }
273 auto it = userInfo.cloneInfos.find(std::to_string(appIndex));
274 if (it == userInfo.cloneInfos.end()) {
275 APP_LOGE("the clone app is not installed");
276 return ERR_APPEXECFWK_CLONE_UNINSTALL_APP_NOT_CLONED;
277 }
278 uid_ = it->second.uid;
279 accessTokenId_ = it->second.accessTokenId;
280 if (!AbilityManagerHelper::UninstallApplicationProcesses(bundleName, uid_, false, appIndex)) {
281 APP_LOGE("fail to kill running application");
282 }
283 if (BundlePermissionMgr::DeleteAccessTokenId(accessTokenId_) !=
284 AccessToken::AccessTokenKitRet::RET_SUCCESS) {
285 APP_LOGE("delete AT failed clone");
286 }
287 if (dataMgr_->RemoveCloneBundle(bundleName, userId, appIndex)) {
288 APP_LOGE("RemoveCloneBundle failed");
289 return ERR_APPEXECFWK_CLONE_UNINSTALL_INTERNAL_ERROR;
290 }
291 if (RemoveCloneDataDir(bundleName, userId, appIndex) != ERR_OK) {
292 APP_LOGW("RemoveCloneDataDir failed");
293 }
294 // process icon and label
295 {
296 InnerBundleInfo info;
297 if (dataMgr_->FetchInnerBundleInfo(bundleName, info)) {
298 auto appIndexes = info.GetCloneBundleAppIndexes();
299 if (appIndexes.find(appIndex) == appIndexes.end()) {
300 BundleResourceHelper::DeleteCloneBundleResourceInfo(bundleName, appIndex, userId);
301 }
302 }
303 }
304 #ifdef BUNDLE_FRAMEWORK_APP_CONTROL
305 std::shared_ptr<AppControlManager> appControlMgr = DelayedSingleton<AppControlManager>::GetInstance();
306 if (appControlMgr != nullptr) {
307 APP_LOGD("Delete disposed rule when bundleName :%{public}s uninstall", bundleName.c_str());
308 appControlMgr->DeleteAllDisposedRuleByBundle(info, appIndex, userId);
309 }
310 #endif
311 DeleteKeyOperation(bundleName, appIndex, userId, uid_);
312 APP_LOGI("UninstallCloneApp %{public}s _ %{public}d succesfully", bundleName.c_str(), appIndex);
313 return ERR_OK;
314 }
315
AddKeyOperation( const std::string &bundleName, int32_t appIndex, int32_t userId, int32_t uid)316 bool BundleCloneInstaller::AddKeyOperation(
317 const std::string &bundleName, int32_t appIndex, int32_t userId, int32_t uid)
318 {
319 if (GetDataMgr() != ERR_OK) {
320 APP_LOGE("Get dataMgr shared_ptr nullptr");
321 return false;
322 }
323 InnerBundleInfo innerBundleInfo;
324 if (!dataMgr_->FetchInnerBundleInfo(bundleName, innerBundleInfo)) {
325 APP_LOGE("get failed");
326 return false;
327 }
328 bool appEncrypted = innerBundleInfo.GetApplicationReservedFlag() &
329 static_cast<uint32_t>(ApplicationReservedFlag::ENCRYPTED_APPLICATION);
330 if (!appEncrypted) {
331 return true;
332 }
333 CodeProtectBundleInfo info;
334 info.bundleName = innerBundleInfo.GetBundleName();
335 info.versionCode = innerBundleInfo.GetVersionCode();
336 info.applicationReservedFlag = innerBundleInfo.GetApplicationReservedFlag();
337 info.uid = uid;
338 info.appIndex = appIndex;
339
340 BmsExtensionDataMgr bmsExtensionDataMgr;
341 auto res = bmsExtensionDataMgr.KeyOperation(std::vector<CodeProtectBundleInfo> { info }, CodeOperation::ADD);
342 if (res == ERR_OK) {
343 dataMgr_->UpdateAppEncryptedStatus(bundleName, true, appIndex);
344 } else {
345 dataMgr_->UpdateAppEncryptedStatus(bundleName, false, appIndex);
346 }
347 return res == ERR_OK;
348 }
349
DeleteKeyOperation(const std::string &bundleName, int32_t appIndex, int32_t userId, int32_t uid)350 void BundleCloneInstaller::DeleteKeyOperation(const std::string &bundleName,
351 int32_t appIndex, int32_t userId, int32_t uid)
352 {
353 if (GetDataMgr() != ERR_OK) {
354 APP_LOGE("Get dataMgr shared_ptr nullptr");
355 return;
356 }
357 InnerBundleInfo innerBundleInfo;
358 if (!dataMgr_->FetchInnerBundleInfo(bundleName, innerBundleInfo)) {
359 APP_LOGE("get failed");
360 return;
361 }
362 auto appIndexSet = innerBundleInfo.GetCloneBundleAppIndexes();
363 if (appIndexSet.find(appIndex) != appIndexSet.end()) {
364 return;
365 }
366 bool appEncrypted = innerBundleInfo.GetApplicationReservedFlag() &
367 static_cast<uint32_t>(ApplicationReservedFlag::ENCRYPTED_APPLICATION);
368 if (!appEncrypted) {
369 return;
370 }
371 CodeProtectBundleInfo info;
372 info.bundleName = innerBundleInfo.GetBundleName();
373 info.versionCode = innerBundleInfo.GetVersionCode();
374 info.applicationReservedFlag = innerBundleInfo.GetApplicationReservedFlag();
375 info.uid = uid;
376 info.appIndex = appIndex;
377
378 BmsExtensionDataMgr bmsExtensionDataMgr;
379 auto res = bmsExtensionDataMgr.KeyOperation(std::vector<CodeProtectBundleInfo> { info }, CodeOperation::DELETE);
380 if (res == ERR_OK) {
381 dataMgr_->UpdateAppEncryptedStatus(bundleName, false, appIndex);
382 } else {
383 dataMgr_->UpdateAppEncryptedStatus(bundleName, true, appIndex);
384 }
385 }
386
CreateCloneDataDir(InnerBundleInfo &info, const int32_t userId, const int32_t &uid, const int32_t &appIndex) const387 ErrCode BundleCloneInstaller::CreateCloneDataDir(InnerBundleInfo &info,
388 const int32_t userId, const int32_t &uid, const int32_t &appIndex) const
389 {
390 APP_LOGD("CreateCloneDataDir %{public}s _ %{public}d begin", info.GetBundleName().c_str(), appIndex);
391 std::string innerDataDir = BundleCloneCommonHelper::GetCloneDataDir(info.GetBundleName(), appIndex);
392 CreateDirParam createDirParam;
393 createDirParam.bundleName = innerDataDir;
394 createDirParam.userId = userId;
395 createDirParam.uid = uid;
396 createDirParam.gid = uid;
397 createDirParam.apl = info.GetAppPrivilegeLevel();
398 createDirParam.isPreInstallApp = info.IsPreInstallApp();
399 createDirParam.debug = info.GetBaseApplicationInfo().appProvisionType == Constants::APP_PROVISION_TYPE_DEBUG;
400 auto result = InstalldClient::GetInstance()->CreateBundleDataDir(createDirParam);
401 if (result != ERR_OK) {
402 APP_LOGE("fail to create sandbox data dir, error is %{public}d", result);
403 return result;
404 }
405 APP_LOGI("CreateCloneDataDir successfully");
406 return result;
407 }
408
RemoveCloneDataDir(const std::string bundleName, int32_t userId, int32_t appIndex)409 ErrCode BundleCloneInstaller::RemoveCloneDataDir(const std::string bundleName, int32_t userId, int32_t appIndex)
410 {
411 std::string key = BundleCloneCommonHelper::GetCloneDataDir(bundleName, appIndex);
412 if (InstalldClient::GetInstance()->RemoveBundleDataDir(key, userId) != ERR_OK) {
413 APP_LOGW("CloneApp cannot remove the data dir");
414 return ERR_APPEXECFWK_CLONE_INSTALL_INTERNAL_ERROR;
415 }
416 return ERR_OK;
417 }
418
GetDataMgr()419 ErrCode BundleCloneInstaller::GetDataMgr()
420 {
421 if (dataMgr_ == nullptr) {
422 dataMgr_ = DelayedSingleton<BundleMgrService>::GetInstance()->GetDataMgr();
423 if (dataMgr_ == nullptr) {
424 APP_LOGE("Get dataMgr shared_ptr nullptr");
425 return ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR;
426 }
427 }
428 return ERR_OK;
429 }
430
ResetInstallProperties()431 void BundleCloneInstaller::ResetInstallProperties()
432 {
433 uid_ = 0;
434 accessTokenId_ = 0;
435 }
436 } // AppExecFwk
437 } // OHOS
438