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