1 /*
2 * Copyright (c) 2022-2023 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 <cinttypes>
17 #include <mutex>
18
19 #include "ability_manager_helper.h"
20 #include "account_helper.h"
21 #include "aging/aging_handler.h"
22 #include "app_log_wrapper.h"
23 #include "bundle_data_mgr.h"
24 #include "bundle_mgr_service.h"
25 #include "bundle_promise.h"
26 #include "event_report.h"
27 #include "install_param.h"
28 #include "installd_client.h"
29
30 namespace OHOS {
31 namespace AppExecFwk {
32 namespace {
33 class AgingUninstallReceiveImpl : public StatusReceiverHost {
34 public:
35 AgingUninstallReceiveImpl() = default;
36 virtual ~AgingUninstallReceiveImpl() override = default;
37
IsRunning()38 bool IsRunning()
39 {
40 std::lock_guard<std::mutex> lock(stateMutex_);
41 return isRunning_;
42 }
43
MarkRunning()44 void MarkRunning()
45 {
46 std::lock_guard<std::mutex> lock(stateMutex_);
47 isRunning_ = true;
48 }
49
SetAgingPromise(const std::shared_ptr<BundlePromise> & agingPromise)50 void SetAgingPromise(const std::shared_ptr<BundlePromise>& agingPromise)
51 {
52 agingPromise_ = agingPromise;
53 }
54
OnStatusNotify(const int progress)55 virtual void OnStatusNotify(const int progress) override
56 {}
57
OnFinished(const int32_t resultCode,const std::string & resultMsg)58 virtual void OnFinished(const int32_t resultCode, const std::string &resultMsg) override
59 {
60 std::lock_guard<std::mutex> lock(stateMutex_);
61 isRunning_ = false;
62 if (agingPromise_) {
63 APP_LOGD("Notify task end.");
64 agingPromise_->NotifyAllTasksExecuteFinished();
65 }
66 }
67
68 private:
69 std::mutex stateMutex_;
70 bool isRunning_ = false;
71 std::shared_ptr<BundlePromise> agingPromise_ = nullptr;
72 };
73 }
74
Process(AgingRequest & request) const75 bool RecentlyUnuseBundleAgingHandler::Process(AgingRequest &request) const
76 {
77 return ProcessBundle(request);
78 }
79
ProcessBundle(AgingRequest & request) const80 bool RecentlyUnuseBundleAgingHandler::ProcessBundle(AgingRequest &request) const
81 {
82 APP_LOGD("aging handler start: cleanType: %{public}d, totalDataBytes: %{public}" PRId64,
83 static_cast<int32_t>(request.GetAgingCleanType()), request.GetTotalDataBytes());
84 for (const auto &agingBundle : request.GetAgingBundles()) {
85 bool isBundleRunning = AbilityManagerHelper::IsRunning(agingBundle.GetBundleName());
86 APP_LOGD("found matching bundle: %{public}s, isRunning: %{public}d.",
87 agingBundle.GetBundleName().c_str(), isBundleRunning);
88 if (isBundleRunning != AbilityManagerHelper::NOT_RUNNING) {
89 continue;
90 }
91
92 bool result = AgingClean(agingBundle, request);
93 if (!result) {
94 continue;
95 }
96
97 UpdateUsedTotalDataBytes(request);
98 if (!NeedContinue(request)) {
99 APP_LOGD("there is no need to continue now.");
100 return false;
101 }
102 }
103
104 UpdateUsedTotalDataBytes(request);
105 return NeedContinue(request);
106 }
107
NeedContinue(const AgingRequest & request) const108 bool RecentlyUnuseBundleAgingHandler::NeedContinue(const AgingRequest &request) const
109 {
110 return !request.IsReachEndAgingThreshold();
111 }
112
UpdateUsedTotalDataBytes(AgingRequest & request) const113 bool RecentlyUnuseBundleAgingHandler::UpdateUsedTotalDataBytes(AgingRequest &request) const
114 {
115 auto dataMgr = OHOS::DelayedSingleton<BundleMgrService>::GetInstance()->GetDataMgr();
116 if (dataMgr == nullptr) {
117 APP_LOGE("dataMgr is null");
118 return false;
119 }
120
121 request.SetTotalDataBytes(dataMgr->GetAllFreeInstallBundleSpaceSize());
122 return true;
123 }
124
AgingClean(const AgingBundleInfo & agingBundleInfo,AgingRequest & request) const125 bool RecentlyUnuseBundleAgingHandler::AgingClean(
126 const AgingBundleInfo &agingBundleInfo, AgingRequest &request) const
127 {
128 if (request.GetAgingCleanType() == AgingCleanType::CLEAN_CACHE) {
129 return CleanCache(agingBundleInfo);
130 }
131
132 return UnInstallBundle(agingBundleInfo.GetBundleName());
133 }
134
CleanCache(const AgingBundleInfo & agingBundle) const135 bool RecentlyUnuseBundleAgingHandler::CleanCache(const AgingBundleInfo &agingBundle) const
136 {
137 std::vector<std::string> caches;
138 if (!GetCachePath(agingBundle, caches)) {
139 APP_LOGW("Get cache path failed: %{public}s", agingBundle.GetBundleName().c_str());
140 EventReport::SendCleanCacheSysEvent(
141 agingBundle.GetBundleName(), Constants::ALL_USERID, true, true);
142 return false;
143 }
144
145 bool hasCleanCache = false;
146 for (const auto &cache : caches) {
147 APP_LOGD("cache path: %{public}s", cache.c_str());
148 ErrCode ret = InstalldClient::GetInstance()->CleanBundleDataDir(cache);
149 if (ret != ERR_OK) {
150 APP_LOGE("CleanBundleDataDir failed, path: %{private}s", cache.c_str());
151 continue;
152 }
153
154 hasCleanCache = true;
155 }
156
157 EventReport::SendCleanCacheSysEvent(
158 agingBundle.GetBundleName(), Constants::ALL_USERID, true, !hasCleanCache);
159 return hasCleanCache;
160 }
161
GetCachePath(const AgingBundleInfo & agingBundle,std::vector<std::string> & caches) const162 bool RecentlyUnuseBundleAgingHandler::GetCachePath(
163 const AgingBundleInfo &agingBundle, std::vector<std::string> &caches) const
164 {
165 auto dataMgr = OHOS::DelayedSingleton<BundleMgrService>::GetInstance()->GetDataMgr();
166 if (dataMgr == nullptr) {
167 APP_LOGE("dataMgr is null");
168 return false;
169 }
170
171 std::vector<InnerBundleUserInfo> innerBundleUserInfos;
172 if (!dataMgr->GetInnerBundleUserInfos(agingBundle.GetBundleName(), innerBundleUserInfos)) {
173 APP_LOGE("GetInnerBundleUserInfos failed bundle: %{public}s",
174 agingBundle.GetBundleName().c_str());
175 return false;
176 }
177
178 std::vector<std::string> rootDir;
179 for (const auto &innerBundleUserInfo : innerBundleUserInfos) {
180 int32_t userId = innerBundleUserInfo.bundleUserInfo.userId;
181 for (const auto &el : Constants::BUNDLE_EL) {
182 std::string dataDir =
183 Constants::BUNDLE_APP_DATA_BASE_DIR + el +
184 Constants::PATH_SEPARATOR + std::to_string(userId) +
185 Constants::BASE + agingBundle.GetBundleName();
186 rootDir.emplace_back(dataDir);
187 }
188 }
189
190 for (const auto &st : rootDir) {
191 std::vector<std::string> cache;
192 if (InstalldClient::GetInstance()->GetBundleCachePath(st, cache) != ERR_OK) {
193 APP_LOGW("GetBundleCachePath failed, path: %{public}s", st.c_str());
194 continue;
195 }
196
197 std::copy(cache.begin(), cache.end(), std::back_inserter(caches));
198 }
199
200 return !caches.empty();
201 }
202
UnInstallBundle(const std::string & bundleName) const203 bool RecentlyUnuseBundleAgingHandler::UnInstallBundle(const std::string &bundleName) const
204 {
205 auto bms = DelayedSingleton<BundleMgrService>::GetInstance();
206 if (bms == nullptr) {
207 return false;
208 }
209
210 auto bundleInstaller = bms->GetBundleInstaller();
211 if (bundleInstaller == nullptr) {
212 APP_LOGE("bundleInstaller is null.");
213 return false;
214 }
215
216 sptr<AgingUninstallReceiveImpl> unInstallReceiverImpl(new (std::nothrow) AgingUninstallReceiveImpl());
217 if (unInstallReceiverImpl == nullptr) {
218 return false;
219 }
220
221 std::shared_ptr<BundlePromise> agingPromise = std::make_shared<BundlePromise>();
222 unInstallReceiverImpl->SetAgingPromise(agingPromise);
223 unInstallReceiverImpl->MarkRunning();
224 InstallParam installParam;
225 installParam.userId = Constants::ALL_USERID;
226 installParam.installFlag = InstallFlag::FREE_INSTALL;
227 installParam.isAgingUninstall = true;
228 installParam.noSkipsKill = false;
229 bundleInstaller->Uninstall(bundleName, installParam, unInstallReceiverImpl);
230 if (unInstallReceiverImpl->IsRunning()) {
231 APP_LOGD("Wait for UnInstallBundle end %{public}s.", bundleName.c_str());
232 agingPromise->WaitForAllTasksExecute();
233 }
234
235 return true;
236 }
237 } // namespace AppExecFwk
238 } // namespace OHOS
239