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