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