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(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
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 };
72 std::shared_ptr<BundleCommonEventMgr> commonEventMgr = std::make_shared<BundleCommonEventMgr>();
73 commonEventMgr->NotifyBundleStatus(installRes, dataMgr_);
74
75 ResetInstallProperties();
76 PerfProfile::GetInstance().SetBundleInstallEndTime(GetTickCount());
77 APP_LOGI("-n %{public}s -u %{public}d, ret:%{public}d finished",
78 bundleName.c_str(), userId, result);
79 return result;
80 }
81
ProcessBundleInstall(const std::string & bundleName,const int32_t userId)82 ErrCode BundleMultiUserInstaller::ProcessBundleInstall(const std::string &bundleName, const int32_t userId)
83 {
84 if (bundleName.empty()) {
85 APP_LOGE("bundleName empty");
86 return ERR_APPEXECFWK_INSTALL_PARAM_ERROR;
87 }
88
89 if (userId <= Constants::DEFAULT_USERID) {
90 APP_LOGE("userId(%{public}d) invalid", userId);
91 return ERR_BUNDLE_MANAGER_INVALID_USER_ID;
92 }
93 if (GetDataMgr() != ERR_OK) {
94 return ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR;
95 }
96
97 // 1. check whether original application installed or not
98 ScopeGuard bundleEnabledGuard([&] { dataMgr_->EnableBundle(bundleName); });
99 InnerBundleInfo info;
100 bool isExist = dataMgr_->GetInnerBundleInfoWithDisable(bundleName, info);
101 if (!isExist) {
102 APP_LOGE("the bundle is not installed");
103 return ERR_BUNDLE_MANAGER_BUNDLE_NOT_EXIST;
104 }
105
106 // 2. obtain userId
107 if (!dataMgr_->HasUserId(userId)) {
108 APP_LOGE("install app user %{public}d not exist", userId);
109 return ERR_BUNDLE_MANAGER_INVALID_USER_ID;
110 }
111
112 // 3. check whether original application installed at current userId or not
113 InnerBundleUserInfo userInfo;
114 if (info.GetInnerBundleUserInfo(userId, userInfo)) {
115 APP_LOGE("the origin application had installed at current user");
116 return ERR_OK;
117 }
118
119 std::string appDistributionType = info.GetAppDistributionType();
120 if (appDistributionType == Constants::APP_DISTRIBUTION_TYPE_ENTERPRISE
121 || appDistributionType == Constants::APP_DISTRIBUTION_TYPE_ENTERPRISE_NORMAL
122 || appDistributionType == Constants::APP_DISTRIBUTION_TYPE_ENTERPRISE_MDM) {
123 APP_LOGE("the origin application is enterprise, not allow to install here");
124 return ERR_APPEXECFWK_INSTALL_EXISTED_ENTERPRISE_BUNDLE_NOT_ALLOWED;
125 }
126 if (appDistributionType == Constants::APP_DISTRIBUTION_TYPE_INTERNALTESTING) {
127 APP_LOGE("the origin application is inrternaltesting, not allow to install here");
128 return ERR_APPEXECFWK_INSTALL_FAILED_CONTROLLED;
129 }
130
131 // uid
132 InnerBundleUserInfo newUserInfo;
133 newUserInfo.bundleName = bundleName;
134 newUserInfo.bundleUserInfo.userId = userId;
135 if (!dataMgr_->GenerateUidAndGid(newUserInfo)) {
136 return ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR;
137 }
138 int32_t uid = newUserInfo.uid;
139
140 // 4. generate the accesstoken id and inherit original permissions
141 Security::AccessToken::AccessTokenIDEx newTokenIdEx;
142 Security::AccessToken::HapInfoCheckResult checkResult;
143 if (!RecoverHapToken(bundleName, userId, newTokenIdEx, info)) {
144 AppProvisionInfo appProvisionInfo;
145 if (dataMgr_->GetAppProvisionInfo(bundleName, userId, appProvisionInfo) != ERR_OK) {
146 APP_LOGE("GetAppProvisionInfo failed bundleName:%{public}s", bundleName.c_str());
147 }
148 if (BundlePermissionMgr::InitHapToken(info, userId, 0, newTokenIdEx, checkResult,
149 appProvisionInfo.appServiceCapabilities) != ERR_OK) {
150 auto result = BundlePermissionMgr::GetCheckResultMsg(checkResult);
151 APP_LOGE("bundleName:%{public}s InitHapToken failed, %{public}s", bundleName.c_str(), result.c_str());
152 return ERR_APPEXECFWK_INSTALL_GRANT_REQUEST_PERMISSIONS_FAILED;
153 }
154 }
155 ScopeGuard applyAccessTokenGuard([&] {
156 BundlePermissionMgr::DeleteAccessTokenId(newTokenIdEx.tokenIdExStruct.tokenID);
157 });
158 newUserInfo.accessTokenId = newTokenIdEx.tokenIdExStruct.tokenID;
159 newUserInfo.accessTokenIdEx = newTokenIdEx.tokenIDEx;
160 uid_ = uid;
161 accessTokenId_ = newTokenIdEx.tokenIdExStruct.tokenID;
162 int64_t now = BundleUtil::GetCurrentTimeMs();
163 newUserInfo.installTime = now;
164 newUserInfo.updateTime = now;
165 FirstInstallBundleInfo firstInstallBundleInfo;
166 if (dataMgr_->GetFirstInstallBundleInfo(bundleName, userId, firstInstallBundleInfo)) {
167 newUserInfo.firstInstallTime = firstInstallBundleInfo.firstInstallTime;
168 } else {
169 newUserInfo.firstInstallTime = info.IsPreInstallApp() ? ServiceConstants::PREINSTALL_FIRST_INSTALL_TIME : now;
170 }
171
172 ScopeGuard createUserDataDirGuard([&] { RemoveDataDir(bundleName, userId); });
173 ErrCode result = CreateDataDir(info, userId, uid);
174 if (result != ERR_OK) {
175 APP_LOGE("InstallExisted create dir failed");
176 return result;
177 }
178
179 ScopeGuard addBundleUserGuard([&] { dataMgr_->RemoveInnerBundleUserInfo(bundleName, userId); });
180 if (!dataMgr_->AddInnerBundleUserInfo(bundleName, newUserInfo)) {
181 return ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR;
182 }
183
184 CreateEl5Dir(info, userId, uid);
185 CreateDataGroupDir(bundleName, userId);
186
187 // total to commit, avoid rollback
188 applyAccessTokenGuard.Dismiss();
189 createUserDataDirGuard.Dismiss();
190 addBundleUserGuard.Dismiss();
191 APP_LOGI("InstallExisted %{public}s succesfully", bundleName.c_str());
192 return ERR_OK;
193 }
194
CreateDataDir(InnerBundleInfo & info,const int32_t userId,const int32_t & uid) const195 ErrCode BundleMultiUserInstaller::CreateDataDir(InnerBundleInfo &info,
196 const int32_t userId, const int32_t &uid) const
197 {
198 APP_LOGD("CreateDataDir %{public}s begin", info.GetBundleName().c_str());
199 std::string innerDataDir = info.GetBundleName();
200 CreateDirParam createDirParam;
201 createDirParam.bundleName = innerDataDir;
202 createDirParam.userId = userId;
203 createDirParam.uid = uid;
204 createDirParam.gid = uid;
205 createDirParam.apl = info.GetAppPrivilegeLevel();
206 createDirParam.isPreInstallApp = info.IsPreInstallApp();
207 createDirParam.debug = info.GetBaseApplicationInfo().appProvisionType == Constants::APP_PROVISION_TYPE_DEBUG;
208 createDirParam.extensionDirs = info.GetAllExtensionDirs();
209 auto result = InstalldClient::GetInstance()->CreateBundleDataDir(createDirParam);
210 if (result != ERR_OK) {
211 // if user is not activated, access el2-el4 may return ok but dir cannot be created
212 if (AccountHelper::IsOsAccountVerified(userId)) {
213 APP_LOGE("fail to create data dir, error is %{public}d", result);
214 return result;
215 } else {
216 APP_LOGW("user %{public}d is not activated", userId);
217 }
218 }
219 APP_LOGI("CreateDataDir successfully");
220 return result;
221 }
222
CreateDataGroupDir(const std::string & bundleName,const int32_t userId)223 void BundleMultiUserInstaller::CreateDataGroupDir(const std::string &bundleName, const int32_t userId)
224 {
225 if (GetDataMgr() != ERR_OK) {
226 APP_LOGE("get dataMgr failed");
227 return;
228 }
229 dataMgr_->GenerateNewUserDataGroupInfos(bundleName, userId);
230 }
231
CreateEl5Dir(InnerBundleInfo & info,const int32_t userId,const int32_t & uid)232 void BundleMultiUserInstaller::CreateEl5Dir(InnerBundleInfo &info, const int32_t userId, const int32_t &uid)
233 {
234 std::vector<RequestPermission> reqPermissions = info.GetAllRequestPermissions();
235 auto it = std::find_if(reqPermissions.begin(), reqPermissions.end(), [](const RequestPermission& permission) {
236 return permission.name == ServiceConstants::PERMISSION_PROTECT_SCREEN_LOCK_DATA;
237 });
238 if (it == reqPermissions.end()) {
239 APP_LOGI("no el5 permission %{public}s", info.GetBundleName().c_str());
240 return;
241 }
242 if (GetDataMgr() != ERR_OK) {
243 APP_LOGE("get dataMgr failed");
244 return;
245 }
246 CreateDirParam el5Param;
247 el5Param.bundleName = info.GetBundleName();
248 el5Param.userId = userId;
249 el5Param.uid = uid;
250 el5Param.apl = info.GetAppPrivilegeLevel();
251 el5Param.isPreInstallApp = info.IsPreInstallApp();
252 el5Param.debug = info.GetBaseApplicationInfo().appProvisionType == Constants::APP_PROVISION_TYPE_DEBUG;
253 dataMgr_->CreateEl5Dir(std::vector<CreateDirParam> {el5Param}, true);
254 return;
255 }
256
RemoveDataDir(const std::string bundleName,int32_t userId)257 ErrCode BundleMultiUserInstaller::RemoveDataDir(const std::string bundleName, int32_t userId)
258 {
259 std::string key = bundleName;
260 if (InstalldClient::GetInstance()->RemoveBundleDataDir(key, userId) != ERR_OK) {
261 APP_LOGW("App cannot remove the data dir");
262 return ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR;
263 }
264 return ERR_OK;
265 }
266
GetDataMgr()267 ErrCode BundleMultiUserInstaller::GetDataMgr()
268 {
269 if (dataMgr_ == nullptr) {
270 dataMgr_ = DelayedSingleton<BundleMgrService>::GetInstance()->GetDataMgr();
271 if (dataMgr_ == nullptr) {
272 APP_LOGE("Get dataMgr shared_ptr nullptr");
273 return ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR;
274 }
275 }
276 return ERR_OK;
277 }
278
ResetInstallProperties()279 void BundleMultiUserInstaller::ResetInstallProperties()
280 {
281 uid_ = 0;
282 accessTokenId_ = 0;
283 }
284
RecoverHapToken(const std::string & bundleName,const int32_t userId,Security::AccessToken::AccessTokenIDEx & accessTokenIdEx,const InnerBundleInfo & innerBundleInfo)285 bool BundleMultiUserInstaller::RecoverHapToken(const std::string &bundleName, const int32_t userId,
286 Security::AccessToken::AccessTokenIDEx& accessTokenIdEx, const InnerBundleInfo &innerBundleInfo)
287 {
288 UninstallBundleInfo uninstallBundleInfo;
289 if (!dataMgr_->GetUninstallBundleInfo(bundleName, uninstallBundleInfo)) {
290 return false;
291 }
292 APP_LOGI("bundleName:%{public}s getUninstallBundleInfo success", bundleName.c_str());
293 if (uninstallBundleInfo.userInfos.empty()) {
294 APP_LOGW("bundleName:%{public}s empty userInfos", bundleName.c_str());
295 return false;
296 }
297 if (uninstallBundleInfo.userInfos.find(std::to_string(userId)) != uninstallBundleInfo.userInfos.end()) {
298 accessTokenIdEx.tokenIdExStruct.tokenID =
299 uninstallBundleInfo.userInfos.at(std::to_string(userId)).accessTokenId;
300 accessTokenIdEx.tokenIDEx = uninstallBundleInfo.userInfos.at(std::to_string(userId)).accessTokenIdEx;
301 Security::AccessToken::HapInfoCheckResult checkResult;
302 AppProvisionInfo appProvisionInfo;
303 if (dataMgr_->GetAppProvisionInfo(bundleName, userId, appProvisionInfo) != ERR_OK) {
304 APP_LOGE("GetAppProvisionInfo failed bundleName:%{public}s", bundleName.c_str());
305 }
306 if (BundlePermissionMgr::UpdateHapToken(accessTokenIdEx, innerBundleInfo, userId, checkResult,
307 appProvisionInfo.appServiceCapabilities) == ERR_OK) {
308 return true;
309 } else {
310 auto result = BundlePermissionMgr::GetCheckResultMsg(checkResult);
311 APP_LOGW("bundleName:%{public}s UpdateHapToken failed, %{public}s", bundleName.c_str(), result.c_str());
312 }
313 }
314 return false;
315 }
316 } // AppExecFwk
317 } // OHOS
318