• 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 <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