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_multiuser_installer.h"
17 
18 #include "ability_manager_helper.h"
19 #include "bms_extension_data_mgr.h"
20 #include "bundle_constants.h"
21 #include "bundle_mgr_service.h"
22 #include "bundle_permission_mgr.h"
23 #include "bundle_resource_helper.h"
24 #include "bundle_util.h"
25 #include "datetime_ex.h"
26 #include "hitrace_meter.h"
27 #include "installd_client.h"
28 #include "perf_profile.h"
29 #include "scope_guard.h"
30 
31 
32 namespace OHOS {
33 namespace AppExecFwk {
34 using namespace OHOS::Security;
35 
BundleMultiUserInstaller()36 BundleMultiUserInstaller::BundleMultiUserInstaller()
37 {
38     APP_LOGD("created");
39 }
40 
~BundleMultiUserInstaller()41 BundleMultiUserInstaller::~BundleMultiUserInstaller()
42 {
43     APP_LOGD("~");
44 }
45 
InstallExistedApp(const std::string & bundleName,const int32_t userId)46 ErrCode BundleMultiUserInstaller::InstallExistedApp(const std::string &bundleName, const int32_t userId)
47 {
48     HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
49     APP_LOGI("-n %{public}s -u %{public}d begin", bundleName.c_str(), userId);
50 
51     BmsExtensionDataMgr bmsExtensionDataMgr;
52     if (bmsExtensionDataMgr.IsAppInBlocklist(bundleName, userId)) {
53         APP_LOGE("app %{public}s is in blocklist", bundleName.c_str());
54         return ERR_APPEXECFWK_INSTALL_APP_IN_BLOCKLIST;
55     }
56 
57     if (GetDataMgr() != ERR_OK) {
58         return ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR;
59     }
60 
61     PerfProfile::GetInstance().SetBundleInstallStartTime(GetTickCount());
62     ErrCode result = ProcessBundleInstall(bundleName, userId);
63     NotifyBundleEvents installRes = {
64         .bundleName = bundleName,
65         .resultCode = result,
66         .type = NotifyType::INSTALL,
67         .uid = uid_,
68         .accessTokenId = accessTokenId_,
69         .appIndex = 0,
70     };
71     std::shared_ptr<BundleCommonEventMgr> commonEventMgr = std::make_shared<BundleCommonEventMgr>();
72     commonEventMgr->NotifyBundleStatus(installRes, dataMgr_);
73 
74     ResetInstallProperties();
75     PerfProfile::GetInstance().SetBundleInstallEndTime(GetTickCount());
76     APP_LOGI("-n %{public}s -u %{public}d, ret:%{public}d finished",
77         bundleName.c_str(), userId, result);
78     return result;
79 }
80 
ProcessBundleInstall(const std::string & bundleName,const int32_t userId)81 ErrCode BundleMultiUserInstaller::ProcessBundleInstall(const std::string &bundleName, const int32_t userId)
82 {
83     if (bundleName.empty()) {
84         APP_LOGE("bundleName empty");
85         return ERR_APPEXECFWK_INSTALL_PARAM_ERROR;
86     }
87 
88     if (userId <= Constants::DEFAULT_USERID) {
89         APP_LOGE("userId(%{public}d) invalid", userId);
90         return ERR_BUNDLE_MANAGER_INVALID_USER_ID;
91     }
92     if (GetDataMgr() != ERR_OK) {
93         return ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR;
94     }
95 
96     // 1. check whether original application installed or not
97     ScopeGuard bundleEnabledGuard([&] { dataMgr_->EnableBundle(bundleName); });
98     InnerBundleInfo info;
99     bool isExist = dataMgr_->GetInnerBundleInfo(bundleName, info);
100     if (!isExist) {
101         APP_LOGE("the bundle is not installed");
102         return ERR_BUNDLE_MANAGER_BUNDLE_NOT_EXIST;
103     }
104 
105     // 2. obtain userId
106     if (!dataMgr_->HasUserId(userId)) {
107         APP_LOGE("install app user %{public}d not exist", userId);
108         return ERR_BUNDLE_MANAGER_INVALID_USER_ID;
109     }
110 
111     // 3. check whether original application installed at current userId or not
112     InnerBundleUserInfo userInfo;
113     if (info.GetInnerBundleUserInfo(userId, userInfo)) {
114         APP_LOGE("the origin application had installed at current user");
115         return ERR_OK;
116     }
117 
118     std::string appDistributionType = info.GetAppDistributionType();
119     if (appDistributionType == Constants::APP_DISTRIBUTION_TYPE_ENTERPRISE
120         || appDistributionType == Constants::APP_DISTRIBUTION_TYPE_ENTERPRISE_NORMAL
121         || appDistributionType == Constants::APP_DISTRIBUTION_TYPE_ENTERPRISE_MDM) {
122         APP_LOGE("the origin application is enterprise, not allow to install here");
123         return ERR_APPEXECFWK_INSTALL_EXISTED_ENTERPRISE_BUNDLE_NOT_ALLOWED;
124     }
125 
126     // uid
127     InnerBundleUserInfo newUserInfo;
128     newUserInfo.bundleName = bundleName;
129     newUserInfo.bundleUserInfo.userId = userId;
130     if (!dataMgr_->GenerateUidAndGid(newUserInfo)) {
131         return ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR;
132     }
133     int32_t uid = newUserInfo.uid;
134 
135     // 4. generate the accesstoken id and inherit original permissions
136     Security::AccessToken::AccessTokenIDEx newTokenIdEx;
137     if (BundlePermissionMgr::InitHapToken(info, userId, 0, newTokenIdEx) != ERR_OK) {
138         APP_LOGE("bundleName:%{public}s InitHapToken failed", bundleName.c_str());
139         return ERR_APPEXECFWK_INSTALL_GRANT_REQUEST_PERMISSIONS_FAILED;
140     }
141     ScopeGuard applyAccessTokenGuard([&] {
142         BundlePermissionMgr::DeleteAccessTokenId(newTokenIdEx.tokenIdExStruct.tokenID);
143     });
144     newUserInfo.accessTokenId = newTokenIdEx.tokenIdExStruct.tokenID;
145     newUserInfo.accessTokenIdEx = newTokenIdEx.tokenIDEx;
146     uid_ = uid;
147     accessTokenId_ = newTokenIdEx.tokenIdExStruct.tokenID;
148     int64_t now = BundleUtil::GetCurrentTime();
149     newUserInfo.installTime = now;
150     newUserInfo.updateTime = now;
151 
152     ScopeGuard createUserDataDirGuard([&] { RemoveDataDir(bundleName, userId); });
153     ErrCode result = CreateDataDir(info, userId, uid);
154     if (result != ERR_OK) {
155         APP_LOGE("InstallExisted create dir failed");
156         return result;
157     }
158 
159     ScopeGuard addBundleUserGuard([&] { dataMgr_->RemoveInnerBundleUserInfo(bundleName, userId); });
160     if (!dataMgr_->AddInnerBundleUserInfo(bundleName, newUserInfo)) {
161         return ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR;
162     }
163 
164     CreateEl5Dir(info, userId, uid);
165     CreateDataGroupDir(bundleName, userId);
166 
167     // total to commit, avoid rollback
168     applyAccessTokenGuard.Dismiss();
169     createUserDataDirGuard.Dismiss();
170     addBundleUserGuard.Dismiss();
171     APP_LOGI("InstallExisted %{public}s succesfully", bundleName.c_str());
172     return ERR_OK;
173 }
174 
CreateDataDir(InnerBundleInfo & info,const int32_t userId,const int32_t & uid) const175 ErrCode BundleMultiUserInstaller::CreateDataDir(InnerBundleInfo &info,
176     const int32_t userId, const int32_t &uid) const
177 {
178     APP_LOGD("CreateDataDir %{public}s begin", info.GetBundleName().c_str());
179     std::string innerDataDir = info.GetBundleName();
180     CreateDirParam createDirParam;
181     createDirParam.bundleName = innerDataDir;
182     createDirParam.userId = userId;
183     createDirParam.uid = uid;
184     createDirParam.gid = uid;
185     createDirParam.apl = info.GetAppPrivilegeLevel();
186     createDirParam.isPreInstallApp = info.IsPreInstallApp();
187     createDirParam.debug = info.GetBaseApplicationInfo().appProvisionType == Constants::APP_PROVISION_TYPE_DEBUG;
188     createDirParam.extensionDirs = info.GetAllExtensionDirs();
189     auto result = InstalldClient::GetInstance()->CreateBundleDataDir(createDirParam);
190     if (result != ERR_OK) {
191         APP_LOGE("fail to create data dir, error is %{public}d", result);
192         return result;
193     }
194     APP_LOGI("CreateDataDir successfully");
195     return result;
196 }
197 
CreateDataGroupDir(const std::string & bundleName,const int32_t userId)198 void BundleMultiUserInstaller::CreateDataGroupDir(const std::string &bundleName, const int32_t userId)
199 {
200     if (GetDataMgr() != ERR_OK) {
201         APP_LOGE("get dataMgr failed");
202         return;
203     }
204     dataMgr_->GenerateNewUserDataGroupInfos(bundleName, userId);
205     std::vector<DataGroupInfo> infos;
206     if (!dataMgr_->QueryDataGroupInfos(bundleName, userId, infos)) {
207         APP_LOGE("find %{public}s in %{public}d failed", bundleName.c_str(), userId);
208         return;
209     }
210     if (infos.empty()) {
211         return;
212     }
213     for (const DataGroupInfo &dataGroupInfo : infos) {
214         std::string parentDir = std::string(ServiceConstants::REAL_DATA_PATH) + ServiceConstants::PATH_SEPARATOR
215             + std::to_string(dataGroupInfo.userId);
216         if (!BundleUtil::IsExistDirNoLog(parentDir)) {
217             APP_LOGE("group parent dir %{public}s not exist", parentDir.c_str());
218             return;
219         }
220         std::string dir = parentDir + ServiceConstants::DATA_GROUP_PATH + dataGroupInfo.uuid;
221         if (BundleUtil::IsExistDirNoLog(dir)) {
222             APP_LOGI("group dir exist, no need to create");
223             continue;
224         }
225         auto result = InstalldClient::GetInstance()->Mkdir(dir, ServiceConstants::DATA_GROUP_DIR_MODE,
226             dataGroupInfo.uid, dataGroupInfo.gid);
227         if (result != ERR_OK) {
228             APP_LOGE("mkdir group dir failed, uid %{public}d err %{public}d", dataGroupInfo.uid, result);
229         }
230     }
231 }
232 
CreateEl5Dir(InnerBundleInfo & info,const int32_t userId,const int32_t & uid)233 void BundleMultiUserInstaller::CreateEl5Dir(InnerBundleInfo &info, const int32_t userId, const int32_t &uid)
234 {
235     std::vector<RequestPermission> reqPermissions = info.GetAllRequestPermissions();
236     auto it = std::find_if(reqPermissions.begin(), reqPermissions.end(), [](const RequestPermission& permission) {
237         return permission.name == ServiceConstants::PERMISSION_PROTECT_SCREEN_LOCK_DATA;
238     });
239     if (it == reqPermissions.end()) {
240         APP_LOGI("no el5 permission %{public}s", info.GetBundleName().c_str());
241         return;
242     }
243     if (GetDataMgr() != ERR_OK) {
244         APP_LOGE("get dataMgr failed");
245         return;
246     }
247     CreateDirParam el5Param;
248     el5Param.bundleName = info.GetBundleName();
249     el5Param.userId = userId;
250     el5Param.uid = uid;
251     el5Param.apl = info.GetAppPrivilegeLevel();
252     el5Param.isPreInstallApp = info.IsPreInstallApp();
253     el5Param.debug = info.GetBaseApplicationInfo().appProvisionType == Constants::APP_PROVISION_TYPE_DEBUG;
254     dataMgr_->CreateEl5Dir(std::vector<CreateDirParam> {el5Param});
255     return;
256 }
257 
RemoveDataDir(const std::string bundleName,int32_t userId)258 ErrCode BundleMultiUserInstaller::RemoveDataDir(const std::string bundleName, int32_t userId)
259 {
260     std::string key = bundleName;
261     if (InstalldClient::GetInstance()->RemoveBundleDataDir(key, userId) != ERR_OK) {
262         APP_LOGW("App cannot remove the data dir");
263         return ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR;
264     }
265     return ERR_OK;
266 }
267 
GetDataMgr()268 ErrCode BundleMultiUserInstaller::GetDataMgr()
269 {
270     if (dataMgr_ == nullptr) {
271         dataMgr_ = DelayedSingleton<BundleMgrService>::GetInstance()->GetDataMgr();
272         if (dataMgr_ == nullptr) {
273             APP_LOGE("Get dataMgr shared_ptr nullptr");
274             return ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR;
275         }
276     }
277     return ERR_OK;
278 }
279 
ResetInstallProperties()280 void BundleMultiUserInstaller::ResetInstallProperties()
281 {
282     uid_ = 0;
283     accessTokenId_ = 0;
284 }
285 } // AppExecFwk
286 } // OHOS
287