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 <cstring>
17 #include <dirent.h>
18
19 #include "hmp_bundle_installer.h"
20
21 #include "app_log_wrapper.h"
22 #include "app_service_fwk_installer.h"
23 #include "bundle_constants.h"
24 #include "bundle_data_mgr.h"
25 #include "bundle_parser.h"
26 #include "bundle_service_constants.h"
27 #include "bundle_mgr_service.h"
28
29 namespace OHOS {
30 namespace AppExecFwk {
31 namespace {
32 const std::string APP_DIR = "/app";
33 const std::string APP_SERVICE_FWK_DIR = "appServiceFwk";
34 const std::string HAP_PATH_DATA_AREA = "/data/app/el1/bundle/public";
35 } // namespace
36
HmpBundleInstaller()37 HmpBundleInstaller::HmpBundleInstaller()
38 {
39 APP_LOGD("hmp bundle installer instance is created");
40 }
41
~HmpBundleInstaller()42 HmpBundleInstaller::~HmpBundleInstaller()
43 {
44 APP_LOGD("hmp bundle installer instance is destroyed");
45 }
46
GetHmpBundleList(const std::string & path) const47 std::set<std::string> HmpBundleInstaller::GetHmpBundleList(const std::string &path) const
48 {
49 std::set<std::string> hmpBundleList;
50 DIR *dir = opendir(path.c_str());
51 if (dir == nullptr) {
52 APP_LOGE("fail to opendir:%{public}s, errno:%{public}d", path.c_str(), errno);
53 return hmpBundleList;
54 }
55 struct dirent *ptr;
56 while ((ptr = readdir(dir)) != nullptr) {
57 if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0 ||
58 strcmp(ptr->d_name, APP_SERVICE_FWK_DIR.c_str()) == 0) {
59 continue;
60 }
61 if (ptr->d_type == DT_DIR) {
62 hmpBundleList.insert(std::string(ptr->d_name));
63 continue;
64 }
65 }
66 closedir(dir);
67 return hmpBundleList;
68 }
69
InstallSystemHspInHmp(const std::string & bundleDir) const70 ErrCode HmpBundleInstaller::InstallSystemHspInHmp(const std::string &bundleDir) const
71 {
72 AppServiceFwkInstaller installer;
73 InstallParam installParam;
74 installParam.isPreInstallApp = true;
75 installParam.removable = false;
76 installParam.copyHapToInstallPath = false;
77 installParam.needSavePreInstallInfo = true;
78 ErrCode ret = installer.Install({ bundleDir }, installParam);
79 if (ret != ERR_OK) {
80 APP_LOGE("install hmp system hsp %{public}s error with code: %{public}d", bundleDir.c_str(), ret);
81 }
82 return ret;
83 }
84
InstallNormalAppInHmp(const std::string & bundleDir,bool removable)85 ErrCode HmpBundleInstaller::InstallNormalAppInHmp(const std::string &bundleDir, bool removable)
86 {
87 auto pos = bundleDir.rfind('/');
88 auto bundleName = pos != std::string::npos ? bundleDir.substr(pos + 1) : "";
89 std::set<int32_t> requiredUserIds;
90 if (!GetRequiredUserIds(bundleName, requiredUserIds)) {
91 APP_LOGI("%{public}s need not to install", bundleDir.c_str());
92 return ERR_OK;
93 }
94 InstallParam installParam;
95 installParam.isPreInstallApp = true;
96 installParam.SetKillProcess(false);
97 installParam.needSendEvent = true;
98 installParam.needSavePreInstallInfo = true;
99 installParam.copyHapToInstallPath = false;
100 installParam.userId = Constants::DEFAULT_USERID;
101 installParam.installFlag = InstallFlag::REPLACE_EXISTING;
102 installParam.isOTA = true;
103 installParam.removable = removable;
104 installParam.preinstallSourceFlag = ApplicationInfoFlag::FLAG_OTA_INSTALLED;
105 ErrCode ret = InstallBundle(bundleDir, installParam, Constants::AppType::SYSTEM_APP);
106 ResetInstallProperties();
107 if (ret == ERR_OK) {
108 APP_LOGI("install hmp normal app %{public}s for user 0 success", bundleDir.c_str());
109 return ret;
110 }
111 if (!InitDataMgr()) {
112 APP_LOGE("InitDataMgr fail");
113 return ERR_APPEXECFWK_NULL_PTR;
114 }
115 if (dataMgr_->IsSystemHsp(bundleName)) {
116 APP_LOGE("install hmp system hsp %{public}s error with code: %{public}d", bundleDir.c_str(), ret);
117 return ret;
118 }
119 bool installSuccess = false;
120 for (auto userId : requiredUserIds) {
121 if (userId == Constants::DEFAULT_USERID) {
122 continue;
123 }
124 installParam.userId = userId;
125 ret = InstallBundle(bundleDir, installParam, Constants::AppType::SYSTEM_APP);
126 ResetInstallProperties();
127 APP_LOGI("install hmp bundleName: %{public}s, userId: %{public}d, result: %{public}d",
128 bundleName.c_str(), userId, ret);
129 if (ret != ERR_OK) {
130 APP_LOGE("install hmp normal app %{public}s error with code: %{public}d", bundleDir.c_str(), ret);
131 return ret;
132 }
133 installSuccess = true;
134 }
135 return installSuccess ? ERR_OK : ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR;
136 }
137
GetRequiredUserIds(std::string bundleName,std::set<int32_t> & userIds)138 bool HmpBundleInstaller::GetRequiredUserIds(std::string bundleName, std::set<int32_t> &userIds)
139 {
140 if (!InitDataMgr()) {
141 APP_LOGE("InitDataMgr fail");
142 return false;
143 }
144 // if bundle exists, return the set of user ids that have installed the bundle
145 if (dataMgr_->GetInnerBundleInfoUsers(bundleName, userIds)) {
146 return true;
147 }
148 // if bundle does not exist, check whether the bundle is pre-installed
149 // if so, it means the bundle is uninstalled by all users, return empty set
150 PreInstallBundleInfo preInfo;
151 if (dataMgr_->GetPreInstallBundleInfo(bundleName, preInfo)) {
152 return false;
153 }
154 // if bundle does not exist and is not pre-installed, it means the bundle is new, return all user ids
155 for (auto userId : dataMgr_->GetAllUser()) {
156 if (userId >= Constants::START_USERID) {
157 userIds.insert(userId);
158 }
159 }
160 return true;
161 }
162
CheckAppIsUpdatedByUser(const std::string & bundleName)163 bool HmpBundleInstaller::CheckAppIsUpdatedByUser(const std::string &bundleName)
164 {
165 if (bundleName.empty()) {
166 APP_LOGE("name empty");
167 return false;
168 }
169 if (!InitDataMgr()) {
170 APP_LOGE("init dataMgr failed");
171 return false;
172 }
173 BundleInfo bundleInfo;
174 auto baseFlag = static_cast<int32_t>(GetBundleInfoFlag::GET_BUNDLE_INFO_WITH_HAP_MODULE) +
175 static_cast<int32_t>(GetBundleInfoFlag::GET_BUNDLE_INFO_WITH_DISABLE);
176 ErrCode ret = dataMgr_->GetBundleInfoV9(bundleName, baseFlag, bundleInfo, Constants::ANY_USERID);
177 if (ret != ERR_OK) {
178 APP_LOGW("%{public}s not found", bundleName.c_str());
179 return false;
180 }
181 for (const auto &hapInfo : bundleInfo.hapModuleInfos) {
182 if (hapInfo.hapPath.size() > HAP_PATH_DATA_AREA.size() &&
183 hapInfo.hapPath.compare(0, HAP_PATH_DATA_AREA.size(), HAP_PATH_DATA_AREA) == 0) {
184 APP_LOGI("%{public}s has been updated by user", hapInfo.name.c_str());
185 return true;
186 }
187 }
188 APP_LOGI("%{public}s has not been updated by user", bundleName.c_str());
189 return false;
190 }
191
RollbackHmpBundle(const std::set<std::string> & systemHspList,const std::set<std::string> & hapList)192 void HmpBundleInstaller::RollbackHmpBundle(const std::set<std::string> &systemHspList,
193 const std::set<std::string> &hapList)
194 {
195 std::set<std::string> rollbackList;
196 for (const auto &bundleName : hapList) {
197 if (!CheckAppIsUpdatedByUser(bundleName)) {
198 rollbackList.insert(bundleName);
199 }
200 }
201 // If the update fails, the information of the application in the database needs to be deleted,
202 // but the user data directory and some settings set by the user,
203 // such as app control rules and default applications, cannot be deleted.
204 std::set<std::string> normalBundleList;
205 std::set_difference(rollbackList.begin(), rollbackList.end(), systemHspList.begin(), systemHspList.end(),
206 std::inserter(normalBundleList, normalBundleList.begin()));
207 for (const auto &bundleName : normalBundleList) {
208 ErrCode ret = RollbackHmpUserInfo(bundleName);
209 if (ret != ERR_OK) {
210 APP_LOGE("RollbackHmpUserInfo %{public}s error with code: %{public}d", bundleName.c_str(), ret);
211 }
212 }
213 std::set<std::string> allBundleList;
214 allBundleList.insert(systemHspList.begin(), systemHspList.end());
215 allBundleList.insert(rollbackList.begin(), rollbackList.end());
216 for (const auto &bundleName : allBundleList) {
217 ErrCode ret = RollbackHmpCommonInfo(bundleName);
218 if (ret != ERR_OK) {
219 APP_LOGE("RollbackHmpCommonInfo %{public}s error with code: %{public}d", bundleName.c_str(), ret);
220 }
221 }
222 }
223
ParseHapFiles(const std::string & hapFilePath,std::unordered_map<std::string,InnerBundleInfo> & infos)224 bool HmpBundleInstaller::ParseHapFiles(
225 const std::string &hapFilePath,
226 std::unordered_map<std::string, InnerBundleInfo> &infos)
227 {
228 std::vector<std::string> hapFilePathVec { hapFilePath };
229 std::vector<std::string> realPaths;
230 auto ret = BundleUtil::CheckFilePath(hapFilePathVec, realPaths);
231 if (ret != ERR_OK) {
232 APP_LOGE("File path %{public}s invalid", hapFilePath.c_str());
233 return false;
234 }
235
236 BundleParser bundleParser;
237 for (auto realPath : realPaths) {
238 InnerBundleInfo innerBundleInfo;
239 ret = bundleParser.Parse(realPath, innerBundleInfo);
240 if (ret != ERR_OK) {
241 APP_LOGE("Parse bundle info failed, error: %{public}d", ret);
242 continue;
243 }
244
245 infos.emplace(realPath, innerBundleInfo);
246 }
247
248 if (infos.empty()) {
249 APP_LOGE("Parse hap(%{public}s) empty ", hapFilePath.c_str());
250 return false;
251 }
252
253 return true;
254 }
255
ParseInfos(const std::string & bundleDir,const std::string & hspDir,std::unordered_map<std::string,InnerBundleInfo> & infos)256 void HmpBundleInstaller::ParseInfos(const std::string &bundleDir, const std::string &hspDir,
257 std::unordered_map<std::string, InnerBundleInfo> &infos)
258 {
259 if (!bundleDir.empty()) {
260 if (!ParseHapFiles(bundleDir, infos) || infos.empty()) {
261 APP_LOGW("obtain bundleinfo failed : %{public}s ", bundleDir.c_str());
262 }
263 }
264 if (!hspDir.empty()) {
265 if (!ParseHapFiles(hspDir, infos) || infos.empty()) {
266 APP_LOGW("obtain appService bundleinfo failed : %{public}s ", hspDir.c_str());
267 }
268 }
269 }
270
UpdateBundleInfo(const std::string & bundleName,const std::string & bundleDir,const std::string & hspDir)271 void HmpBundleInstaller::UpdateBundleInfo(const std::string &bundleName,
272 const std::string &bundleDir, const std::string &hspDir)
273 {
274 std::unordered_map<std::string, InnerBundleInfo> infos;
275 ParseInfos(bundleDir, hspDir, infos);
276 UpdateInnerBundleInfo(bundleName, infos);
277 UpdatePreInfoInDb(bundleName, infos);
278 }
279
UpdateInnerBundleInfo(const std::string & bundleName,const std::unordered_map<std::string,InnerBundleInfo> & infos)280 void HmpBundleInstaller::UpdateInnerBundleInfo(const std::string &bundleName,
281 const std::unordered_map<std::string, InnerBundleInfo> &infos)
282 {
283 if (!InitDataMgr()) {
284 APP_LOGE("InitDataMgr fail");
285 return;
286 }
287 InnerBundleInfo oldBundleInfo;
288 bool hasInstalled = dataMgr_->FetchInnerBundleInfo(bundleName, oldBundleInfo);
289 if (!hasInstalled) {
290 APP_LOGW("app(%{public}s) has been uninstalled", bundleName.c_str());
291 return;
292 }
293 auto innerModuleInfos = oldBundleInfo.GetInnerModuleInfos();
294 std::set<std::string> newModulePackages;
295 for (const auto &item : infos) {
296 newModulePackages.insert(item.second.GetCurrentModulePackage());
297 }
298 for (const auto &item : innerModuleInfos) {
299 if (newModulePackages.find(item.first) == newModulePackages.end()) {
300 APP_LOGI("module package (%{public}s) need to be removed.", item.first.c_str());
301 if (!UninstallSystemBundle(bundleName, item.first)) {
302 APP_LOGW("uninstall module %{public}s for bundle %{public}s failed",
303 item.first.c_str(), bundleName.c_str());
304 }
305 }
306 }
307 }
308
UninstallSystemBundle(const std::string & bundleName,const std::string & modulePackage)309 bool HmpBundleInstaller::UninstallSystemBundle(const std::string &bundleName, const std::string &modulePackage)
310 {
311 if (!InitDataMgr()) {
312 APP_LOGE("InitDataMgr fail");
313 return false;
314 }
315
316 InstallParam installParam;
317 bool uninstallResult = false;
318 for (auto userId : dataMgr_->GetAllUser()) {
319 installParam.userId = userId;
320 installParam.needSavePreInstallInfo = true;
321 installParam.isPreInstallApp = true;
322 installParam.SetKillProcess(false);
323 installParam.needSendEvent = false;
324 MarkPreBundleSyeEventBootTag(false);
325 ErrCode result = UninstallBundle(bundleName, modulePackage, installParam);
326 ResetInstallProperties();
327 if (result != ERR_OK) {
328 APP_LOGW("uninstall system bundle fail for userId %{public}d, error: %{public}d", userId, result);
329 continue;
330 }
331 APP_LOGI("uninstall module %{public}s success", modulePackage.c_str());
332 uninstallResult = true;
333 }
334 CheckUninstallSystemHsp(bundleName);
335
336 return uninstallResult;
337 }
338
CheckUninstallSystemHsp(const std::string & bundleName)339 void HmpBundleInstaller::CheckUninstallSystemHsp(const std::string &bundleName)
340 {
341 if (!InitDataMgr()) {
342 APP_LOGE("InitDataMgr fail");
343 return;
344 }
345 InnerBundleInfo info;
346 if (!(dataMgr_->FetchInnerBundleInfo(bundleName, info))) {
347 APP_LOGD("bundleName %{public}s not existed local", bundleName.c_str());
348 return;
349 }
350 if (info.GetApplicationBundleType() != BundleType::APP_SERVICE_FWK) {
351 APP_LOGD("bundleName %{public}s is not a system hsp", bundleName.c_str());
352 return;
353 }
354 bool isExistHsp = false;
355 for (const auto &item : info.GetInnerModuleInfos()) {
356 if (item.second.distro.moduleType == "shared") {
357 isExistHsp = true;
358 return;
359 }
360 }
361 APP_LOGI("appService %{public}s does not have any hsp, so it need to be uninstalled.", bundleName.c_str());
362 if (!isExistHsp) {
363 InstallParam installParam;
364 installParam.userId = Constants::DEFAULT_USERID;
365 installParam.needSavePreInstallInfo = true;
366 installParam.isPreInstallApp = true;
367 installParam.SetKillProcess(false);
368 installParam.needSendEvent = false;
369 installParam.isKeepData = true;
370 MarkPreBundleSyeEventBootTag(false);
371 ErrCode result = UninstallBundle(bundleName, installParam);
372 if (result != ERR_OK) {
373 APP_LOGW("uninstall system bundle fail, error: %{public}d", result);
374 return;
375 }
376 PreInstallBundleInfo preInstallBundleInfo;
377 if ((dataMgr_->GetPreInstallBundleInfo(bundleName, preInstallBundleInfo))) {
378 dataMgr_->DeletePreInstallBundleInfo(bundleName, preInstallBundleInfo);
379 }
380 }
381 }
382
UpdatePreInfoInDb(const std::string & bundleName,const std::unordered_map<std::string,InnerBundleInfo> & infos)383 void HmpBundleInstaller::UpdatePreInfoInDb(const std::string &bundleName,
384 const std::unordered_map<std::string, InnerBundleInfo> &infos)
385 {
386 if (!InitDataMgr()) {
387 APP_LOGE("InitDataMgr fail");
388 return;
389 }
390 PreInstallBundleInfo preInstallBundleInfo;
391 dataMgr_->GetPreInstallBundleInfo(bundleName, preInstallBundleInfo);
392 auto bundlePathList = preInstallBundleInfo.GetBundlePaths();
393 for (const std::string &bundlePath : bundlePathList) {
394 if (infos.find(bundlePath) == infos.end()) {
395 APP_LOGI("bundlePath %{public}s need to be deleted", bundlePath.c_str());
396 preInstallBundleInfo.DeleteBundlePath(bundlePath);
397 }
398 }
399 if (preInstallBundleInfo.GetBundlePaths().empty()) {
400 dataMgr_->DeletePreInstallBundleInfo(bundleName, preInstallBundleInfo);
401 } else {
402 dataMgr_->SavePreInstallBundleInfo(bundleName, preInstallBundleInfo);
403 }
404 }
405
UpdateBundleInfoForHmp(const std::string & filePath,std::set<std::string> hapList,std::set<std::string> systemHspList)406 void HmpBundleInstaller::UpdateBundleInfoForHmp(const std::string &filePath, std::set<std::string> hapList,
407 std::set<std::string> systemHspList)
408 {
409 std::string appBaseDir = filePath + APP_DIR;
410 std::string appServiceFwkBaseDir = filePath + APP_DIR + ServiceConstants::PATH_SEPARATOR + APP_SERVICE_FWK_DIR;
411 for (const auto &bundleName : hapList) {
412 std::string bundleDir = appBaseDir + ServiceConstants::PATH_SEPARATOR + bundleName;
413 std::string hspDir = "";
414 if (systemHspList.find(bundleName) != systemHspList.end()) {
415 hspDir = appServiceFwkBaseDir + ServiceConstants::PATH_SEPARATOR + bundleName;
416 }
417 UpdateBundleInfo(bundleName, bundleDir, hspDir);
418 }
419
420 for (const auto &bundleName : systemHspList) {
421 if (hapList.find(bundleName) == hapList.end()) {
422 std::string hspDir = appServiceFwkBaseDir + ServiceConstants::PATH_SEPARATOR + bundleName;
423 UpdateBundleInfo(bundleName, "", hspDir);
424 }
425 }
426 }
427
GetIsRemovable(const std::string & bundleName)428 bool HmpBundleInstaller::GetIsRemovable(const std::string &bundleName)
429 {
430 if (!InitDataMgr()) {
431 APP_LOGE("InitDataMgr fail");
432 return true;
433 }
434 InnerBundleInfo info;
435 if (!dataMgr_->FetchInnerBundleInfo(bundleName, info)) {
436 APP_LOGE("get removable failed %{public}s", bundleName.c_str());
437 return true;
438 }
439 return info.IsRemovable();
440 }
441
InitDataMgr()442 bool HmpBundleInstaller::InitDataMgr()
443 {
444 if (dataMgr_ == nullptr) {
445 dataMgr_ = DelayedSingleton<BundleMgrService>::GetInstance()->GetDataMgr();
446 if (dataMgr_ == nullptr) {
447 APP_LOGE("Get dataMgr_ nullptr");
448 return false;
449 }
450 }
451 return true;
452 }
453 } // namespace AppExecFwk
454 } // namespace OHOS
455