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