1 /*
2 * Copyright (c) 2025 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 "install_exception_mgr.h"
17
18 #include "app_log_wrapper.h"
19 #include "appexecfwk_errors.h"
20 #include "bundle_mgr_service.h"
21 #include "bundle_service_constants.h"
22 #include "bundle_constants.h"
23 #include "installd_client.h"
24
25 namespace OHOS {
26 namespace AppExecFwk {
27
InstallExceptionMgr()28 InstallExceptionMgr::InstallExceptionMgr()
29 {
30 installExceptionMgr_ = std::make_shared<InstallExceptionMgrRdb>();
31 }
32
~InstallExceptionMgr()33 InstallExceptionMgr::~InstallExceptionMgr()
34 {
35 }
36
SaveBundleExceptionInfo(const std::string & bundleName,const InstallExceptionInfo & installExceptionInfo)37 ErrCode InstallExceptionMgr::SaveBundleExceptionInfo(
38 const std::string &bundleName, const InstallExceptionInfo &installExceptionInfo)
39 {
40 if (installExceptionMgr_ == nullptr) {
41 APP_LOGE("installExceptionMgr_ is null");
42 return ERR_APPEXECFWK_NULL_PTR;
43 }
44 return installExceptionMgr_->SaveBundleExceptionInfo(bundleName, installExceptionInfo);
45 }
46
DeleteBundleExceptionInfo(const std::string & bundleName)47 ErrCode InstallExceptionMgr::DeleteBundleExceptionInfo(const std::string &bundleName)
48 {
49 if (installExceptionMgr_ == nullptr) {
50 APP_LOGE("installExceptionMgr_ is null");
51 return ERR_APPEXECFWK_NULL_PTR;
52 }
53 return installExceptionMgr_->DeleteBundleExceptionInfo(bundleName);
54 }
55
HandleBundleExceptionInfo(const std::string & bundleName,const InstallExceptionInfo & installExceptionInfo)56 void InstallExceptionMgr::HandleBundleExceptionInfo(
57 const std::string &bundleName, const InstallExceptionInfo &installExceptionInfo)
58 {
59 APP_LOGI("bundle %{public}s install exception status %{public}d", bundleName.c_str(),
60 static_cast<int32_t>(installExceptionInfo.status));
61 switch (installExceptionInfo.status) {
62 case InstallRenameExceptionStatus::RENAME_RELA_TO_OLD_PATH :
63 case InstallRenameExceptionStatus::RENAME_NEW_TO_RELA_PATH : {
64 InnerBundleInfo bundleInfo;
65 auto dataMgr = DelayedSingleton<BundleMgrService>::GetInstance()->GetDataMgr();
66 if ((dataMgr != nullptr) && (!dataMgr->FetchInnerBundleInfo(bundleName, bundleInfo))) {
67 APP_LOGW("bundle %{public}s not exist", bundleName.c_str());
68 }
69 if (bundleInfo.GetVersionCode() <= installExceptionInfo.versionCode) {
70 std::string realPath = std::string(Constants::BUNDLE_CODE_DIR) + ServiceConstants::PATH_SEPARATOR +
71 bundleName;
72 std::string oldPath = std::string(Constants::BUNDLE_CODE_DIR) + ServiceConstants::PATH_SEPARATOR +
73 std::string(ServiceConstants::BUNDLE_OLD_CODE_DIR) + bundleName;
74 ErrCode result = InstalldClient::GetInstance()->RenameModuleDir(oldPath, realPath);
75 if (result == ERR_OK) {
76 (void)DeleteBundleExceptionInfo(bundleName);
77 } else {
78 APP_LOGE("rename module dir failed, error is %{public}d, errno %{public}d", result, errno);
79 }
80 std::string newPath = std::string(Constants::BUNDLE_CODE_DIR) + ServiceConstants::PATH_SEPARATOR +
81 std::string(ServiceConstants::BUNDLE_NEW_CODE_DIR) + bundleName;
82 result = InstalldClient::GetInstance()->RemoveDir(newPath);
83 if (result != ERR_OK) {
84 APP_LOGE("remove dir failed, error is %{public}d, errno %{public}d", result, errno);
85 }
86 return;
87 }
88 }
89 case InstallRenameExceptionStatus::DELETE_OLD_PATH : {
90 std::string oldPath = std::string(Constants::BUNDLE_CODE_DIR) + ServiceConstants::PATH_SEPARATOR +
91 std::string(ServiceConstants::BUNDLE_OLD_CODE_DIR) + bundleName;
92 ErrCode result = InstalldClient::GetInstance()->RemoveDir(oldPath);
93 if (result == ERR_OK) {
94 (void)DeleteBundleExceptionInfo(bundleName);
95 } else {
96 APP_LOGE("remove dir failed, error is %{public}d, errno %{public}d", result, errno);
97 }
98 break;
99 }
100 default :
101 APP_LOGE("bundle %{public}s install unknown exception status %{public}d",
102 bundleName.c_str(), static_cast<int32_t>(installExceptionInfo.status));
103 (void)DeleteBundleExceptionInfo(bundleName);
104 }
105 }
106
HandleAllBundleExceptionInfo()107 void InstallExceptionMgr::HandleAllBundleExceptionInfo()
108 {
109 APP_LOGI("handle exception start");
110 if (installExceptionMgr_ == nullptr) {
111 APP_LOGE("installExceptionMgr_ is null");
112 return;
113 }
114 std::map<std::string, InstallExceptionInfo> bundleExceptionInfos;
115 installExceptionMgr_->GetAllBundleExceptionInfo(bundleExceptionInfos);
116 for (const auto &exceptionInfo : bundleExceptionInfos) {
117 HandleBundleExceptionInfo(exceptionInfo.first, exceptionInfo.second);
118 }
119 // process +old- +new- path throw scan code path
120 std::vector<std::string> allCodePath;
121 ErrCode result = InstalldClient::GetInstance()->ScanDir(Constants::BUNDLE_CODE_DIR,
122 ScanMode::SUB_FILE_DIR, ResultMode::RELATIVE_PATH, allCodePath);
123 if (result != ERR_OK) {
124 APP_LOGW("ScanDir code path failed");
125 return;
126 }
127 for (const auto &codePath : allCodePath) {
128 if (codePath.find(ServiceConstants::BUNDLE_OLD_CODE_DIR) == 0) {
129 APP_LOGI("+old- code path %{public}s", codePath.c_str());
130 std::string bundleName = codePath.substr(std::string(ServiceConstants::BUNDLE_OLD_CODE_DIR).size());
131 if (bundleName.empty()) {
132 continue;
133 }
134 std::string oldCodePath = std::string(Constants::BUNDLE_CODE_DIR) +
135 ServiceConstants::PATH_SEPARATOR + codePath;
136 std::string realCodePath = std::string(Constants::BUNDLE_CODE_DIR) +
137 ServiceConstants::PATH_SEPARATOR + bundleName;
138 ErrCode result = InstalldClient::GetInstance()->RenameModuleDir(oldCodePath, realCodePath);
139 if (result != ERR_OK) {
140 APP_LOGW("rename +old- to real code path failed, error is %{public}d", result);
141 }
142 continue;
143 }
144 if (codePath.find(ServiceConstants::BUNDLE_NEW_CODE_DIR) == 0) {
145 APP_LOGI("+new- code path %{public}s", codePath.c_str());
146 std::string newCodePath = std::string(Constants::BUNDLE_CODE_DIR) +
147 ServiceConstants::PATH_SEPARATOR + codePath;
148 (void)InstalldClient::GetInstance()->RemoveDir(newCodePath);
149 }
150 }
151 APP_LOGI("handle exception end");
152 }
153 } // AppExecFwk
154 } // OHOS
155