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