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