1 /*
2  * Copyright (c) 2021-2022 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_exception_handler.h"
17 
18 #include "installd_client.h"
19 
20 namespace OHOS {
21 namespace AppExecFwk {
BundleExceptionHandler(const std::shared_ptr<IBundleDataStorage> & dataStorage)22 BundleExceptionHandler::BundleExceptionHandler(const std::shared_ptr<IBundleDataStorage> &dataStorage)
23     : dataStorage_(dataStorage)
24 {
25     APP_LOGD("create bundle excepetion handler instance");
26 }
27 
~BundleExceptionHandler()28 BundleExceptionHandler::~BundleExceptionHandler()
29 {
30     APP_LOGD("destroy bundle excepetion handler instance");
31 }
32 
33 
HandleInvalidBundle(InnerBundleInfo & info,bool & isBundleValid)34 void BundleExceptionHandler::HandleInvalidBundle(InnerBundleInfo &info, bool &isBundleValid)
35 {
36     std::string appCodePath = Constants::BUNDLE_CODE_DIR + ServiceConstants::PATH_SEPARATOR + info.GetBundleName();
37     if (!IsBundleHapPathExist(info)) {
38         RemoveBundleAndDataDir(appCodePath, info.GetBundleName(), info.GetUserId());
39         DeleteBundleInfoFromStorage(info);
40         isBundleValid = false;
41         return;
42     }
43     InnerHandleInvalidBundle(info, isBundleValid);
44 }
45 
RemoveBundleAndDataDir(const std::string & bundleDir,const std::string & bundleOrMoudleDir,int32_t userId) const46 bool BundleExceptionHandler::RemoveBundleAndDataDir(const std::string &bundleDir,
47     const std::string &bundleOrMoudleDir, int32_t userId) const
48 {
49     ErrCode result = InstalldClient::GetInstance()->RemoveDir(bundleDir);
50     if (result != ERR_OK) {
51         APP_LOGE("fail to remove bundle dir %{public}s, error is %{public}d", bundleDir.c_str(), result);
52         return false;
53     }
54 
55     if (bundleOrMoudleDir.find(ServiceConstants::HAPS) != std::string::npos) {
56         result = InstalldClient::GetInstance()->RemoveModuleDataDir(bundleOrMoudleDir, userId);
57         if (result != ERR_OK) {
58             APP_LOGE("fail to remove module data dir %{public}s, error is %{public}d", bundleOrMoudleDir.c_str(),
59                 result);
60             return false;
61         }
62     } else {
63         result = InstalldClient::GetInstance()->RemoveBundleDataDir(bundleOrMoudleDir, userId);
64         if (result != ERR_OK) {
65             APP_LOGE("fail to remove bundle data dir %{public}s, error is %{public}d", bundleOrMoudleDir.c_str(),
66                 result);
67             return false;
68         }
69     }
70     return true;
71 }
72 
DeleteBundleInfoFromStorage(const InnerBundleInfo & info)73 void BundleExceptionHandler::DeleteBundleInfoFromStorage(const InnerBundleInfo &info)
74 {
75     auto storage = dataStorage_.lock();
76     if (storage) {
77         APP_LOGD("remove bundle info of %{public}s from the storage", info.GetBundleName().c_str());
78         storage->DeleteStorageBundleInfo(info);
79     } else {
80         APP_LOGE(" fail to remove bundle info of %{public}s from the storage", info.GetBundleName().c_str());
81     }
82 }
83 
IsBundleHapPathExist(const InnerBundleInfo & info)84 bool BundleExceptionHandler::IsBundleHapPathExist(const InnerBundleInfo &info)
85 {
86     if (info.IsPreInstallApp() || (info.GetApplicationBundleType() != BundleType::APP)) {
87         APP_LOGD("bundleName:%{public}s no need to check", info.GetBundleName().c_str());
88         return true;
89     }
90     APP_LOGD("start, need to check bundleName:%{public}s hap file", info.GetBundleName().c_str());
91     const auto innerModuleInfos = info.GetInnerModuleInfos();
92     for (const auto &item : innerModuleInfos) {
93         if (!item.second.hapPath.empty()) {
94             bool isExist = false;
95             if (InstalldClient::GetInstance()->IsExistFile(item.second.hapPath, isExist) != ERR_OK) {
96                 APP_LOGW("bundleName:%{public}s check hap path failed", info.GetBundleName().c_str());
97                 continue;
98             }
99             if (!isExist) {
100                 APP_LOGE("bundleName:%{public}s hap Path is not exist", info.GetBundleName().c_str());
101                 return false;
102             }
103         }
104     }
105     return true;
106 }
107 
InnerHandleInvalidBundle(InnerBundleInfo & info,bool & isBundleValid)108 void BundleExceptionHandler::InnerHandleInvalidBundle(InnerBundleInfo &info, bool &isBundleValid)
109 {
110     auto mark = info.GetInstallMark();
111     if (mark.status == InstallExceptionStatus::INSTALL_FINISH) {
112         return;
113     }
114     APP_LOGI_NOFUNC("handle -n %{public}s status is %{public}d", info.GetBundleName().c_str(), mark.status);
115     std::string appCodePath = Constants::BUNDLE_CODE_DIR + ServiceConstants::PATH_SEPARATOR + info.GetBundleName();
116     auto moduleDir = appCodePath + ServiceConstants::PATH_SEPARATOR + mark.packageName;
117     auto moduleDataDir = info.GetBundleName() + ServiceConstants::HAPS + mark.packageName;
118 
119     // install and update failed before service restart
120     if (mark.status == InstallExceptionStatus::INSTALL_START) {
121         // unable to distinguish which user failed the installation
122         (void)RemoveBundleAndDataDir(appCodePath, info.GetBundleName(), info.GetUserId());
123         DeleteBundleInfoFromStorage(info);
124         isBundleValid = false;
125     } else if (mark.status == InstallExceptionStatus::UPDATING_EXISTED_START) {
126         if (InstalldClient::GetInstance()->RemoveDir(moduleDir + ServiceConstants::TMP_SUFFIX) == ERR_OK) {
127             info.SetBundleStatus(InnerBundleInfo::BundleStatus::ENABLED);
128         }
129     } else if (mark.status == InstallExceptionStatus::UPDATING_NEW_START &&
130         RemoveBundleAndDataDir(moduleDir, moduleDataDir, info.GetUserId())) {
131         info.SetBundleStatus(InnerBundleInfo::BundleStatus::ENABLED);
132     } else if (mark.status == InstallExceptionStatus::UNINSTALL_BUNDLE_START &&
133         RemoveBundleAndDataDir(appCodePath, info.GetBundleName(), info.GetUserId())) {  // continue to uninstall
134         DeleteBundleInfoFromStorage(info);
135         isBundleValid = false;
136     } else if (mark.status == InstallExceptionStatus::UNINSTALL_PACKAGE_START) {
137         if (info.IsOnlyModule(mark.packageName) &&
138             RemoveBundleAndDataDir(appCodePath, info.GetBundleName(), info.GetUserId())) {
139             DeleteBundleInfoFromStorage(info);
140             isBundleValid = false;
141             return;
142         }
143         if (RemoveBundleAndDataDir(moduleDir, moduleDataDir, info.GetUserId())) {
144             info.RemoveModuleInfo(mark.packageName);
145             info.SetBundleStatus(InnerBundleInfo::BundleStatus::ENABLED);
146         }
147     } else if (mark.status == InstallExceptionStatus::UPDATING_FINISH) {
148         if (InstalldClient::GetInstance()->RenameModuleDir(moduleDir + ServiceConstants::TMP_SUFFIX, moduleDir) !=
149             ERR_OK) {
150             APP_LOGI_NOFUNC("%{public}s rename module failed, may not exist", info.GetBundleName().c_str());
151         }
152     }
153 }
154 }  // namespace AppExecFwkConstants
155 }  // namespace OHOS