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