• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024-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 "bundle_multiuser_installer.h"
17 
18 #include "ability_manager_helper.h"
19 #include "account_helper.h"
20 #include "bms_extension_data_mgr.h"
21 #include "bundle_constants.h"
22 #include "bundle_mgr_service.h"
23 #include "bundle_permission_mgr.h"
24 #include "bundle_resource_helper.h"
25 #include "bundle_util.h"
26 #include "datetime_ex.h"
27 #include "hitrace_meter.h"
28 #include "installd_client.h"
29 #include "perf_profile.h"
30 #include "scope_guard.h"
31 
32 
33 namespace OHOS {
34 namespace AppExecFwk {
35 using namespace OHOS::Security;
36 
BundleMultiUserInstaller()37 BundleMultiUserInstaller::BundleMultiUserInstaller()
38 {
39     APP_LOGD("created");
40 }
41 
~BundleMultiUserInstaller()42 BundleMultiUserInstaller::~BundleMultiUserInstaller()
43 {
44     APP_LOGD("~");
45 }
46 
InstallExistedApp(const std::string & bundleName,const int32_t userId)47 ErrCode BundleMultiUserInstaller::InstallExistedApp(const std::string &bundleName, const int32_t userId)
48 {
49     HITRACE_METER_NAME_EX(HITRACE_LEVEL_INFO, HITRACE_TAG_APP, __PRETTY_FUNCTION__, nullptr);
50     APP_LOGI("-n %{public}s -u %{public}d begin", bundleName.c_str(), userId);
51 
52     BmsExtensionDataMgr bmsExtensionDataMgr;
53     if (bmsExtensionDataMgr.IsAppInBlocklist(bundleName, userId)) {
54         APP_LOGE("app %{public}s is in blocklist", bundleName.c_str());
55         return ERR_APPEXECFWK_INSTALL_APP_IN_BLOCKLIST;
56     }
57 
58     if (GetDataMgr() != ERR_OK) {
59         return ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR;
60     }
61 
62     PerfProfile::GetInstance().SetBundleInstallStartTime(GetTickCount());
63     ErrCode result = ProcessBundleInstall(bundleName, userId);
64     NotifyBundleEvents installRes = {
65         .type = NotifyType::INSTALL,
66         .resultCode = result,
67         .accessTokenId = accessTokenId_,
68         .uid = uid_,
69         .appIndex = 0,
70         .bundleName = bundleName,
71         .crossAppSharedConfig = isBundleCrossAppSharedConfig_,
72     };
73     std::shared_ptr<BundleCommonEventMgr> commonEventMgr = std::make_shared<BundleCommonEventMgr>();
74     commonEventMgr->NotifyBundleStatus(installRes, dataMgr_);
75 
76     ResetInstallProperties();
77     PerfProfile::GetInstance().SetBundleInstallEndTime(GetTickCount());
78     APP_LOGI("-n %{public}s -u %{public}d, ret:%{public}d finished",
79         bundleName.c_str(), userId, result);
80     return result;
81 }
82 
ProcessBundleInstall(const std::string & bundleName,const int32_t userId)83 ErrCode BundleMultiUserInstaller::ProcessBundleInstall(const std::string &bundleName, const int32_t userId)
84 {
85     if (bundleName.empty()) {
86         APP_LOGE("bundleName empty");
87         return ERR_APPEXECFWK_INSTALL_PARAM_ERROR;
88     }
89 
90     if (userId <= Constants::DEFAULT_USERID) {
91         APP_LOGE("userId(%{public}d) invalid", userId);
92         return ERR_BUNDLE_MANAGER_INVALID_USER_ID;
93     }
94     if (GetDataMgr() != ERR_OK) {
95         return ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR;
96     }
97 
98     // 1. check whether original application installed or not
99     ScopeGuard bundleEnabledGuard([&] { dataMgr_->EnableBundle(bundleName); });
100     InnerBundleInfo info;
101     bool isExist = dataMgr_->GetInnerBundleInfoWithDisable(bundleName, info);
102     if (!isExist) {
103         APP_LOGE("the bundle is not installed");
104         return ERR_BUNDLE_MANAGER_BUNDLE_NOT_EXIST;
105     }
106     isBundleCrossAppSharedConfig_ = info.IsBundleCrossAppSharedConfig();
107 
108     // 2. obtain userId
109     if (!dataMgr_->HasUserId(userId)) {
110         APP_LOGE("install app user %{public}d not exist", userId);
111         return ERR_BUNDLE_MANAGER_INVALID_USER_ID;
112     }
113 
114     // 3. check whether original application installed at current userId or not
115     InnerBundleUserInfo userInfo;
116     if (info.GetInnerBundleUserInfo(userId, userInfo)) {
117         APP_LOGE("the origin application had installed at current user");
118         return ERR_OK;
119     }
120 
121     if (info.IsSingleton()) {
122         APP_LOGE("singleton app cannot be installed in other user");
123         return ERR_OK;
124     }
125 
126     // 4. check whether the account constraint is enabled
127     if (AccountHelper::CheckOsAccountConstraintEnabled(userId, ServiceConstants::CONSTRAINT_APPS_INSTALL)) {
128         APP_LOGE("user %{public}d is not allowed to install app", userId);
129         return ERR_APPEXECFWK_INSTALL_FAILED_ACCOUNT_CONSTRAINT;
130     }
131 
132     std::string appDistributionType = info.GetAppDistributionType();
133     if (appDistributionType == Constants::APP_DISTRIBUTION_TYPE_ENTERPRISE
134         || appDistributionType == Constants::APP_DISTRIBUTION_TYPE_ENTERPRISE_NORMAL
135         || appDistributionType == Constants::APP_DISTRIBUTION_TYPE_ENTERPRISE_MDM) {
136         APP_LOGE("the origin application is enterprise, not allow to install here");
137         return ERR_APPEXECFWK_INSTALL_EXISTED_ENTERPRISE_BUNDLE_NOT_ALLOWED;
138     }
139     if (appDistributionType == Constants::APP_DISTRIBUTION_TYPE_INTERNALTESTING) {
140         APP_LOGE("the origin application is inrternaltesting, not allow to install here");
141         return ERR_APPEXECFWK_INSTALL_FAILED_CONTROLLED;
142     }
143 
144     // uid
145     InnerBundleUserInfo newUserInfo;
146     newUserInfo.bundleName = bundleName;
147     newUserInfo.bundleUserInfo.userId = userId;
148     if (!dataMgr_->GenerateUidAndGid(newUserInfo)) {
149         return ERR_APPEXECFWK_INSTALL_GENERATE_UID_ERROR;
150     }
151     BundleUtil::MakeFsConfig(info.GetBundleName(), ServiceConstants::HMDFS_CONFIG_PATH, info.GetAppProvisionType(),
152         Constants::APP_PROVISION_TYPE_FILE_NAME);
153     int32_t uid = newUserInfo.uid;
154 
155     // 4. generate the accesstoken id and inherit original permissions
156     Security::AccessToken::AccessTokenIDEx newTokenIdEx;
157     Security::AccessToken::HapInfoCheckResult checkResult;
158     if (!RecoverHapToken(bundleName, userId, newTokenIdEx, info)) {
159         AppProvisionInfo appProvisionInfo;
160         if (dataMgr_->GetAppProvisionInfo(bundleName, userId, appProvisionInfo) != ERR_OK) {
161             APP_LOGE("GetAppProvisionInfo failed bundleName:%{public}s", bundleName.c_str());
162         }
163         if (BundlePermissionMgr::InitHapToken(info, userId, 0, newTokenIdEx, checkResult,
164             appProvisionInfo.appServiceCapabilities) != ERR_OK) {
165             auto result = BundlePermissionMgr::GetCheckResultMsg(checkResult);
166             APP_LOGE("bundleName:%{public}s InitHapToken failed, %{public}s", bundleName.c_str(), result.c_str());
167             return ERR_APPEXECFWK_INSTALL_GRANT_REQUEST_PERMISSIONS_FAILED;
168         }
169     }
170     ScopeGuard applyAccessTokenGuard([&] {
171         BundlePermissionMgr::DeleteAccessTokenId(newTokenIdEx.tokenIdExStruct.tokenID);
172     });
173     newUserInfo.accessTokenId = newTokenIdEx.tokenIdExStruct.tokenID;
174     newUserInfo.accessTokenIdEx = newTokenIdEx.tokenIDEx;
175     uid_ = uid;
176     accessTokenId_ = newTokenIdEx.tokenIdExStruct.tokenID;
177     int64_t now = BundleUtil::GetCurrentTimeMs();
178     newUserInfo.installTime = now;
179     newUserInfo.updateTime = now;
180     FirstInstallBundleInfo firstInstallBundleInfo;
181     if (dataMgr_->GetFirstInstallBundleInfo(bundleName, userId, firstInstallBundleInfo)) {
182         newUserInfo.firstInstallTime = firstInstallBundleInfo.firstInstallTime;
183     } else {
184         newUserInfo.firstInstallTime = info.IsPreInstallApp() ? ServiceConstants::PREINSTALL_FIRST_INSTALL_TIME : now;
185     }
186 
187     ScopeGuard createUserDataDirGuard([&] { RemoveDataDir(bundleName, userId); });
188     ErrCode result = CreateDataDir(info, userId, uid);
189     if (result != ERR_OK) {
190         APP_LOGE("InstallExisted create dir failed");
191         return result;
192     }
193 
194     ScopeGuard addBundleUserGuard([&] { dataMgr_->RemoveInnerBundleUserInfo(bundleName, userId); });
195     result = dataMgr_->AddInnerBundleUserInfo(bundleName, newUserInfo);
196     if (result != ERR_OK) {
197         return result;
198     }
199     // add new user bundle info
200     BundleResourceHelper::AddResourceInfoByBundleName(bundleName, userId, ADD_RESOURCE_TYPE::CREATE_USER);
201     CreateEl5Dir(info, userId, uid);
202     CreateDataGroupDir(bundleName, userId);
203 
204     // total to commit, avoid rollback
205     applyAccessTokenGuard.Dismiss();
206     createUserDataDirGuard.Dismiss();
207     addBundleUserGuard.Dismiss();
208     APP_LOGI("InstallExisted %{public}s succesfully", bundleName.c_str());
209     return ERR_OK;
210 }
211 
CreateDataDir(InnerBundleInfo & info,const int32_t userId,const int32_t & uid) const212 ErrCode BundleMultiUserInstaller::CreateDataDir(InnerBundleInfo &info,
213     const int32_t userId, const int32_t &uid) const
214 {
215     APP_LOGD("CreateDataDir %{public}s begin", info.GetBundleName().c_str());
216     std::string innerDataDir = info.GetBundleName();
217     CreateDirParam createDirParam;
218     createDirParam.bundleName = innerDataDir;
219     createDirParam.userId = userId;
220     createDirParam.uid = uid;
221     createDirParam.gid = uid;
222     createDirParam.apl = info.GetAppPrivilegeLevel();
223     createDirParam.isPreInstallApp = info.IsPreInstallApp();
224     createDirParam.debug = info.GetBaseApplicationInfo().appProvisionType == Constants::APP_PROVISION_TYPE_DEBUG;
225     createDirParam.extensionDirs = info.GetAllExtensionDirs();
226     auto result = InstalldClient::GetInstance()->CreateBundleDataDir(createDirParam);
227     if (result != ERR_OK) {
228         // if user is not activated, access el2-el4 may return ok but dir cannot be created
229         if (AccountHelper::IsOsAccountVerified(userId)) {
230             APP_LOGE("create dir fail, error is %{public}d", result);
231             return result;
232         } else {
233             APP_LOGW("user %{public}d is not activated", userId);
234         }
235     }
236     APP_LOGI("CreateDataDir successfully");
237     return result;
238 }
239 
CreateDataGroupDir(const std::string & bundleName,const int32_t userId)240 void BundleMultiUserInstaller::CreateDataGroupDir(const std::string &bundleName, const int32_t userId)
241 {
242     if (GetDataMgr() != ERR_OK) {
243         APP_LOGE("get dataMgr failed");
244         return;
245     }
246     dataMgr_->GenerateNewUserDataGroupInfos(bundleName, userId);
247 }
248 
CreateEl5Dir(InnerBundleInfo & info,const int32_t userId,const int32_t & uid)249 void BundleMultiUserInstaller::CreateEl5Dir(InnerBundleInfo &info, const int32_t userId, const int32_t &uid)
250 {
251     std::vector<RequestPermission> reqPermissions = info.GetAllRequestPermissions();
252     auto it = std::find_if(reqPermissions.begin(), reqPermissions.end(), [](const RequestPermission& permission) {
253         return permission.name == ServiceConstants::PERMISSION_PROTECT_SCREEN_LOCK_DATA;
254     });
255     if (it == reqPermissions.end()) {
256         APP_LOGI("no el5 permission %{public}s", info.GetBundleName().c_str());
257         return;
258     }
259     if (GetDataMgr() != ERR_OK) {
260         APP_LOGE("get dataMgr failed");
261         return;
262     }
263     CreateDirParam el5Param;
264     el5Param.bundleName = info.GetBundleName();
265     el5Param.userId = userId;
266     el5Param.uid = uid;
267     el5Param.apl = info.GetAppPrivilegeLevel();
268     el5Param.isPreInstallApp = info.IsPreInstallApp();
269     el5Param.debug = info.GetBaseApplicationInfo().appProvisionType == Constants::APP_PROVISION_TYPE_DEBUG;
270     dataMgr_->CreateEl5Dir(std::vector<CreateDirParam> {el5Param}, true);
271     return;
272 }
273 
RemoveDataDir(const std::string bundleName,int32_t userId)274 ErrCode BundleMultiUserInstaller::RemoveDataDir(const std::string bundleName, int32_t userId)
275 {
276     std::string key = bundleName;
277     ErrCode ret = InstalldClient::GetInstance()->RemoveBundleDataDir(key, userId);
278     if (ret != ERR_OK) {
279         APP_LOGW("App cannot remove the data dir");
280         return ret;
281     }
282     return ERR_OK;
283 }
284 
GetDataMgr()285 ErrCode BundleMultiUserInstaller::GetDataMgr()
286 {
287     if (dataMgr_ == nullptr) {
288         dataMgr_ = DelayedSingleton<BundleMgrService>::GetInstance()->GetDataMgr();
289         if (dataMgr_ == nullptr) {
290             APP_LOGE("Get dataMgr shared_ptr nullptr");
291             return ERR_APPEXECFWK_NULL_PTR;
292         }
293     }
294     return ERR_OK;
295 }
296 
ResetInstallProperties()297 void BundleMultiUserInstaller::ResetInstallProperties()
298 {
299     uid_ = 0;
300     accessTokenId_ = 0;
301     isBundleCrossAppSharedConfig_ = false;
302 }
303 
RecoverHapToken(const std::string & bundleName,const int32_t userId,Security::AccessToken::AccessTokenIDEx & accessTokenIdEx,const InnerBundleInfo & innerBundleInfo)304 bool BundleMultiUserInstaller::RecoverHapToken(const std::string &bundleName, const int32_t userId,
305     Security::AccessToken::AccessTokenIDEx& accessTokenIdEx, const InnerBundleInfo &innerBundleInfo)
306 {
307     UninstallBundleInfo uninstallBundleInfo;
308     if (!dataMgr_->GetUninstallBundleInfo(bundleName, uninstallBundleInfo)) {
309         return false;
310     }
311     APP_LOGI("bundleName:%{public}s getUninstallBundleInfo success", bundleName.c_str());
312     if (uninstallBundleInfo.userInfos.empty()) {
313         APP_LOGW("bundleName:%{public}s empty userInfos", bundleName.c_str());
314         return false;
315     }
316     if (uninstallBundleInfo.userInfos.find(std::to_string(userId)) != uninstallBundleInfo.userInfos.end()) {
317         accessTokenIdEx.tokenIdExStruct.tokenID =
318             uninstallBundleInfo.userInfos.at(std::to_string(userId)).accessTokenId;
319         accessTokenIdEx.tokenIDEx = uninstallBundleInfo.userInfos.at(std::to_string(userId)).accessTokenIdEx;
320         Security::AccessToken::HapInfoCheckResult checkResult;
321         AppProvisionInfo appProvisionInfo;
322         if (dataMgr_->GetAppProvisionInfo(bundleName, userId, appProvisionInfo) != ERR_OK) {
323             APP_LOGE("GetAppProvisionInfo failed bundleName:%{public}s", bundleName.c_str());
324         }
325         if (BundlePermissionMgr::UpdateHapToken(accessTokenIdEx, innerBundleInfo, userId, checkResult,
326             appProvisionInfo.appServiceCapabilities) == ERR_OK) {
327             return true;
328         } else {
329             auto result = BundlePermissionMgr::GetCheckResultMsg(checkResult);
330             APP_LOGW("bundleName:%{public}s UpdateHapToken failed, %{public}s", bundleName.c_str(), result.c_str());
331         }
332     }
333     return false;
334 }
335 } // AppExecFwk
336 } // OHOS
337