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         return ERR_APPEXECFWK_INSTALL_BUNDLE_MGR_SERVICE_ERROR;
113     }
114     if (dataMgr_->IsSystemHsp(bundleName)) {
115         APP_LOGE("install hmp system hsp %{public}s error with code: %{public}d", bundleDir.c_str(), ret);
116         return ret;
117     }
118     bool installSuccess = false;
119     for (auto userId : requiredUserIds) {
120         if (userId == Constants::DEFAULT_USERID) {
121             continue;
122         }
123         installParam.userId = userId;
124         ret = InstallBundle(bundleDir, installParam, Constants::AppType::SYSTEM_APP);
125         ResetInstallProperties();
126         APP_LOGI("install hmp bundleName: %{public}s, userId: %{public}d, result: %{public}d",
127             bundleName.c_str(), userId, ret);
128         if (ret != ERR_OK) {
129             APP_LOGE("install hmp normal app %{public}s error with code: %{public}d", bundleDir.c_str(), ret);
130             return ret;
131         }
132         installSuccess = true;
133     }
134     return installSuccess ? ERR_OK : ERR_APPEXECFWK_INSTALL_INTERNAL_ERROR;
135 }
136 
GetRequiredUserIds(std::string bundleName, std::set<int32_t> &userIds)137 bool HmpBundleInstaller::GetRequiredUserIds(std::string bundleName, std::set<int32_t> &userIds)
138 {
139     if (!InitDataMgr()) {
140         return false;
141     }
142     // if bundle exists, return the set of user ids that have installed the bundle
143     if (dataMgr_->GetInnerBundleInfoUsers(bundleName, userIds)) {
144         return true;
145     }
146     // if bundle does not exist, check whether the bundle is pre-installed
147     // if so, it means the bundle is uninstalled by all users, return empty set
148     PreInstallBundleInfo preInfo;
149     if (dataMgr_->GetPreInstallBundleInfo(bundleName, preInfo)) {
150         return false;
151     }
152     // if bundle does not exist and is not pre-installed, it means the bundle is new, return all user ids
153     for (auto userId : dataMgr_->GetAllUser()) {
154         if (userId >= Constants::START_USERID) {
155             userIds.insert(userId);
156         }
157     }
158     return true;
159 }
160 
CheckAppIsUpdatedByUser(const std::string &bundleName)161 bool HmpBundleInstaller::CheckAppIsUpdatedByUser(const std::string &bundleName)
162 {
163     if (bundleName.empty()) {
164         APP_LOGE("name empty");
165         return false;
166     }
167     if (!InitDataMgr()) {
168         APP_LOGE("init dataMgr failed");
169         return false;
170     }
171     BundleInfo bundleInfo;
172     auto baseFlag = static_cast<int32_t>(GetBundleInfoFlag::GET_BUNDLE_INFO_WITH_HAP_MODULE) +
173         static_cast<int32_t>(GetBundleInfoFlag::GET_BUNDLE_INFO_WITH_DISABLE);
174     ErrCode ret = dataMgr_->GetBundleInfoV9(bundleName, baseFlag, bundleInfo, Constants::ANY_USERID);
175     if (ret != ERR_OK) {
176         APP_LOGW("%{public}s not found", bundleName.c_str());
177         return false;
178     }
179     for (const auto &hapInfo : bundleInfo.hapModuleInfos) {
180         if (hapInfo.hapPath.size() > HAP_PATH_DATA_AREA.size() &&
181             hapInfo.hapPath.compare(0, HAP_PATH_DATA_AREA.size(), HAP_PATH_DATA_AREA) == 0) {
182             APP_LOGI("%{public}s has been updated by user", hapInfo.name.c_str());
183             return true;
184         }
185     }
186     APP_LOGI("%{public}s has not been updated by user", bundleName.c_str());
187     return false;
188 }
189 
RollbackHmpBundle(const std::set<std::string> &systemHspList, const std::set<std::string> &hapList)190 void HmpBundleInstaller::RollbackHmpBundle(const std::set<std::string> &systemHspList,
191     const std::set<std::string> &hapList)
192 {
193     std::set<std::string> rollbackList;
194     for (const auto &bundleName : hapList) {
195         if (!CheckAppIsUpdatedByUser(bundleName)) {
196             rollbackList.insert(bundleName);
197         }
198     }
199     // If the update fails, the information of the application in the database needs to be deleted,
200     // but the user data directory and some settings set by the user,
201     // such as app control rules and default applications, cannot be deleted.
202     std::set<std::string> normalBundleList;
203     std::set_difference(rollbackList.begin(), rollbackList.end(), systemHspList.begin(), systemHspList.end(),
204         std::inserter(normalBundleList, normalBundleList.begin()));
205     for (const auto &bundleName : normalBundleList) {
206         ErrCode ret = RollbackHmpUserInfo(bundleName);
207         if (ret != ERR_OK) {
208             APP_LOGE("RollbackHmpUserInfo %{public}s error with code: %{public}d", bundleName.c_str(), ret);
209         }
210     }
211     std::set<std::string> allBundleList;
212     allBundleList.insert(systemHspList.begin(), systemHspList.end());
213     allBundleList.insert(rollbackList.begin(), rollbackList.end());
214     for (const auto &bundleName : allBundleList) {
215         ErrCode ret = RollbackHmpCommonInfo(bundleName);
216         if (ret != ERR_OK) {
217             APP_LOGE("RollbackHmpCommonInfo %{public}s error with code: %{public}d", bundleName.c_str(), ret);
218         }
219     }
220 }
221 
ParseHapFiles( const std::string &hapFilePath, std::unordered_map<std::string, InnerBundleInfo> &infos)222 bool HmpBundleInstaller::ParseHapFiles(
223     const std::string &hapFilePath,
224     std::unordered_map<std::string, InnerBundleInfo> &infos)
225 {
226     std::vector<std::string> hapFilePathVec { hapFilePath };
227     std::vector<std::string> realPaths;
228     auto ret = BundleUtil::CheckFilePath(hapFilePathVec, realPaths);
229     if (ret != ERR_OK) {
230         APP_LOGE("File path %{public}s invalid", hapFilePath.c_str());
231         return false;
232     }
233 
234     BundleParser bundleParser;
235     for (auto realPath : realPaths) {
236         InnerBundleInfo innerBundleInfo;
237         ret = bundleParser.Parse(realPath, innerBundleInfo);
238         if (ret != ERR_OK) {
239             APP_LOGE("Parse bundle info failed, error: %{public}d", ret);
240             continue;
241         }
242 
243         infos.emplace(realPath, innerBundleInfo);
244     }
245 
246     if (infos.empty()) {
247         APP_LOGE("Parse hap(%{public}s) empty ", hapFilePath.c_str());
248         return false;
249     }
250 
251     return true;
252 }
253 
ParseInfos(const std::string &bundleDir, const std::string &hspDir, std::unordered_map<std::string, InnerBundleInfo> &infos)254 void HmpBundleInstaller::ParseInfos(const std::string &bundleDir, const std::string &hspDir,
255     std::unordered_map<std::string, InnerBundleInfo> &infos)
256 {
257     if (!bundleDir.empty()) {
258         if (!ParseHapFiles(bundleDir, infos) || infos.empty()) {
259             APP_LOGW("obtain bundleinfo failed : %{public}s ", bundleDir.c_str());
260         }
261     }
262     if (!hspDir.empty()) {
263         if (!ParseHapFiles(hspDir, infos) || infos.empty()) {
264             APP_LOGW("obtain appService bundleinfo failed : %{public}s ", hspDir.c_str());
265         }
266     }
267 }
268 
UpdateBundleInfo(const std::string &bundleName, const std::string &bundleDir, const std::string &hspDir)269 void HmpBundleInstaller::UpdateBundleInfo(const std::string &bundleName,
270     const std::string &bundleDir, const std::string &hspDir)
271 {
272     std::unordered_map<std::string, InnerBundleInfo> infos;
273     ParseInfos(bundleDir, hspDir, infos);
274     UpdateInnerBundleInfo(bundleName, infos);
275     UpdatePreInfoInDb(bundleName, infos);
276 }
277 
UpdateInnerBundleInfo(const std::string &bundleName, const std::unordered_map<std::string, InnerBundleInfo> &infos)278 void HmpBundleInstaller::UpdateInnerBundleInfo(const std::string &bundleName,
279     const std::unordered_map<std::string, InnerBundleInfo> &infos)
280 {
281     if (!InitDataMgr()) {
282         return;
283     }
284     InnerBundleInfo oldBundleInfo;
285     bool hasInstalled = dataMgr_->FetchInnerBundleInfo(bundleName, oldBundleInfo);
286     if (!hasInstalled) {
287         APP_LOGW("app(%{public}s) has been uninstalled", bundleName.c_str());
288         return;
289     }
290     auto innerModuleInfos = oldBundleInfo.GetInnerModuleInfos();
291     std::set<std::string> newModulePackages;
292     for (const auto &item : infos) {
293         newModulePackages.insert(item.second.GetCurrentModulePackage());
294     }
295     for (const auto &item : innerModuleInfos) {
296         if (newModulePackages.find(item.first) == newModulePackages.end()) {
297             APP_LOGI("module package (%{public}s) need to be removed.", item.first.c_str());
298             if (!UninstallSystemBundle(bundleName, item.first)) {
299                 APP_LOGW("uninstall module %{public}s for bundle %{public}s failed",
300                     item.first.c_str(), bundleName.c_str());
301             }
302         }
303     }
304 }
305 
UninstallSystemBundle(const std::string &bundleName, const std::string &modulePackage)306 bool HmpBundleInstaller::UninstallSystemBundle(const std::string &bundleName, const std::string &modulePackage)
307 {
308     if (!InitDataMgr()) {
309         return false;
310     }
311 
312     InstallParam installParam;
313     bool uninstallResult = false;
314     for (auto userId : dataMgr_->GetAllUser()) {
315         installParam.userId = userId;
316         installParam.needSavePreInstallInfo = true;
317         installParam.isPreInstallApp = true;
318         installParam.SetKillProcess(false);
319         installParam.needSendEvent = false;
320         MarkPreBundleSyeEventBootTag(false);
321         ErrCode result = UninstallBundle(bundleName, modulePackage, installParam);
322         ResetInstallProperties();
323         if (result != ERR_OK) {
324             APP_LOGW("uninstall system bundle fail for userId %{public}d, error: %{public}d", userId, result);
325             continue;
326         }
327         APP_LOGI("uninstall module %{public}s success", modulePackage.c_str());
328         uninstallResult = true;
329     }
330     CheckUninstallSystemHsp(bundleName);
331 
332     return uninstallResult;
333 }
334 
CheckUninstallSystemHsp(const std::string &bundleName)335 void HmpBundleInstaller::CheckUninstallSystemHsp(const std::string &bundleName)
336 {
337     if (!InitDataMgr()) {
338         return;
339     }
340     InnerBundleInfo info;
341     if (!(dataMgr_->FetchInnerBundleInfo(bundleName, info))) {
342         APP_LOGD("bundleName %{public}s not existed local", bundleName.c_str());
343         return;
344     }
345     if (info.GetApplicationBundleType() != BundleType::APP_SERVICE_FWK) {
346         APP_LOGD("bundleName %{public}s is not a system hsp", bundleName.c_str());
347         return;
348     }
349     bool isExistHsp = false;
350     for (const auto &item : info.GetInnerModuleInfos()) {
351         if (item.second.distro.moduleType == "shared") {
352             isExistHsp = true;
353             return;
354         }
355     }
356     APP_LOGI("appService %{public}s does not have any hsp, so it need to be uninstalled.", bundleName.c_str());
357     if (!isExistHsp) {
358         InstallParam installParam;
359         installParam.userId = Constants::DEFAULT_USERID;
360         installParam.needSavePreInstallInfo = true;
361         installParam.isPreInstallApp = true;
362         installParam.SetKillProcess(false);
363         installParam.needSendEvent = false;
364         installParam.isKeepData = true;
365         MarkPreBundleSyeEventBootTag(false);
366         ErrCode result = UninstallBundle(bundleName, installParam);
367         if (result != ERR_OK) {
368             APP_LOGW("uninstall system bundle fail, error: %{public}d", result);
369             return;
370         }
371         PreInstallBundleInfo preInstallBundleInfo;
372         if ((dataMgr_->GetPreInstallBundleInfo(bundleName, preInstallBundleInfo))) {
373             dataMgr_->DeletePreInstallBundleInfo(bundleName, preInstallBundleInfo);
374         }
375     }
376 }
377 
UpdatePreInfoInDb(const std::string &bundleName, const std::unordered_map<std::string, InnerBundleInfo> &infos)378 void HmpBundleInstaller::UpdatePreInfoInDb(const std::string &bundleName,
379     const std::unordered_map<std::string, InnerBundleInfo> &infos)
380 {
381     if (!InitDataMgr()) {
382         return;
383     }
384     PreInstallBundleInfo preInstallBundleInfo;
385     dataMgr_->GetPreInstallBundleInfo(bundleName, preInstallBundleInfo);
386     auto bundlePathList = preInstallBundleInfo.GetBundlePaths();
387     for (const std::string &bundlePath : bundlePathList) {
388         if (infos.find(bundlePath) == infos.end()) {
389             APP_LOGI("bundlePath %{public}s need to be deleted", bundlePath.c_str());
390             preInstallBundleInfo.DeleteBundlePath(bundlePath);
391         }
392     }
393     if (preInstallBundleInfo.GetBundlePaths().empty()) {
394         dataMgr_->DeletePreInstallBundleInfo(bundleName, preInstallBundleInfo);
395     } else {
396         dataMgr_->SavePreInstallBundleInfo(bundleName, preInstallBundleInfo);
397     }
398 }
399 
UpdateBundleInfoForHmp(const std::string &filePath, std::set<std::string> hapList, std::set<std::string> systemHspList)400 void HmpBundleInstaller::UpdateBundleInfoForHmp(const std::string &filePath, std::set<std::string> hapList,
401     std::set<std::string> systemHspList)
402 {
403     std::string appBaseDir = filePath + APP_DIR;
404     std::string appServiceFwkBaseDir = filePath + APP_DIR + ServiceConstants::PATH_SEPARATOR + APP_SERVICE_FWK_DIR;
405     for (const auto &bundleName : hapList) {
406         std::string bundleDir = appBaseDir + ServiceConstants::PATH_SEPARATOR + bundleName;
407         std::string hspDir = "";
408         if (systemHspList.find(bundleName) != systemHspList.end()) {
409             hspDir = appServiceFwkBaseDir + ServiceConstants::PATH_SEPARATOR + bundleName;
410         }
411         UpdateBundleInfo(bundleName, bundleDir, hspDir);
412     }
413 
414     for (const auto &bundleName : systemHspList) {
415         if (hapList.find(bundleName) == hapList.end()) {
416             std::string hspDir = appServiceFwkBaseDir + ServiceConstants::PATH_SEPARATOR + bundleName;
417             UpdateBundleInfo(bundleName, "", hspDir);
418         }
419     }
420 }
421 
GetIsRemovable(const std::string &bundleName)422 bool HmpBundleInstaller::GetIsRemovable(const std::string &bundleName)
423 {
424     if (!InitDataMgr()) {
425         return true;
426     }
427     InnerBundleInfo info;
428     if (!dataMgr_->FetchInnerBundleInfo(bundleName, info)) {
429         APP_LOGE("get removable failed %{public}s", bundleName.c_str());
430         return true;
431     }
432     return info.IsRemovable();
433 }
434 
InitDataMgr()435 bool HmpBundleInstaller::InitDataMgr()
436 {
437     if (dataMgr_ == nullptr) {
438         dataMgr_ = DelayedSingleton<BundleMgrService>::GetInstance()->GetDataMgr();
439         if (dataMgr_ == nullptr) {
440             APP_LOGE("Get dataMgr_ nullptr");
441             return false;
442         }
443     }
444     return true;
445 }
446 }  // namespace AppExecFwk
447 }  // namespace OHOS
448