1 /*
2  * Copyright (c) 2024 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 "storage/storage_monitor_service.h"
17 
18 #include <cstdlib>
19 #include <cstring>
20 #include <mntent.h>
21 #include <pthread.h>
22 #include <singleton.h>
23 #include <sys/statvfs.h>
24 #include <unordered_set>
25 
26 #include "cJSON.h"
27 #include "common_event_data.h"
28 #include "common_event_manager.h"
29 #include "parameters.h"
30 #include "param_wrapper.h"
31 #include "storage_service_errno.h"
32 #include "storage_service_log.h"
33 #include "storage/bundle_manager_connector.h"
34 #include "storage/storage_total_status_service.h"
35 #include "want.h"
36 
37 namespace OHOS {
38 namespace StorageManager {
39 constexpr int32_t CONST_NUM_TWO = 2;
40 constexpr int32_t CONST_NUM_THREE = 3;
41 constexpr int32_t CONST_NUM_ONE_HUNDRED = 100;
42 constexpr int32_t WAIT_THREAD_TIMEOUT_MS = 5;
43 constexpr int32_t DEFAULT_CHECK_INTERVAL = 60 * 1000; // 60s
44 constexpr int32_t STORAGE_THRESHOLD_PERCENTAGE = 5; // 5%
45 constexpr int64_t STORAGE_THRESHOLD_MAX_BYTES = 500 * 1024 * 1024; // 500M
46 constexpr int64_t STORAGE_THRESHOLD_100M = 100 * 1024 * 1024; // 100M
47 constexpr int64_t STORAGE_THRESHOLD_1G = 1000 * 1024 * 1024; // 1G
48 constexpr int32_t STORAGE_LEFT_SIZE_THRESHOLD = 10; // 10%
49 constexpr int32_t SEND_EVENT_INTERVAL = 24; // day
50 constexpr int32_t CLEAN_CACHE_WEEK = 7 * 24; // week
51 constexpr int32_t SEND_EVENT_INTERVAL_HIGH_FREQ = 5; // 5m
52 const std::string PUBLISH_SYSTEM_COMMON_EVENT = "ohos.permission.PUBLISH_SYSTEM_COMMON_EVENT";
53 const std::string SMART_BUNDLE_NAME = "com.ohos.hmos.hiviewcare";
54 const std::string SMART_ACTION = "hicare.event.SMART_NOTIFICATION";
55 const std::string TIMESTAMP_DAY = "persist.storage_manager.timestamp.day";
56 const std::string TIMESTAMP_WEEK = "persist.storage_manager.timestamp.week";
57 const std::string FAULT_ID_ONE = "845010021";
58 const std::string FAULT_ID_TWO = "845010022";
59 const std::string FAULT_ID_THREE = "845010023";
60 const std::string FAULT_SUGGEST_THREE = "545010023";
61 
StorageMonitorService()62 StorageMonitorService::StorageMonitorService() {}
63 
~StorageMonitorService()64 StorageMonitorService::~StorageMonitorService()
65 {
66     LOGD("StorageMonitorService Destructor.");
67     std::unique_lock<std::mutex> lock(eventMutex_);
68     if ((eventHandler_ != nullptr) && (eventHandler_->GetEventRunner() != nullptr)) {
69         eventHandler_->RemoveAllEvents();
70         eventHandler_->GetEventRunner()->Stop();
71     }
72     if (eventThread_.joinable()) {
73         eventThread_.join();
74     }
75     eventHandler_ = nullptr;
76 }
77 
StartStorageMonitorTask()78 void StorageMonitorService::StartStorageMonitorTask()
79 {
80     LOGI("StorageMonitorService, start deicve storage monitor task.");
81     std::unique_lock<std::mutex> lock(eventMutex_);
82     if (eventHandler_ == nullptr) {
83         eventThread_ = std::thread(&StorageMonitorService::StartEventHandler, this);
84         eventCon_.wait_for(lock, std::chrono::seconds(WAIT_THREAD_TIMEOUT_MS), [this] {
85             return eventHandler_ != nullptr;
86         });
87     }
88 
89     auto executeFunc = [this] { Execute(); };
90     eventHandler_->PostTask(executeFunc, DEFAULT_CHECK_INTERVAL);
91 }
92 
StartEventHandler()93 void StorageMonitorService::StartEventHandler()
94 {
95     pthread_setname_np(pthread_self(), "storage_monitor_task_event");
96     auto runner = AppExecFwk::EventRunner::Create(false);
97     if (runner == nullptr) {
98         LOGE("event runner is nullptr.");
99         return;
100     }
101     {
102         std::lock_guard<std::mutex> lock(eventMutex_);
103         eventHandler_ = std::make_shared<AppExecFwk::EventHandler>(runner);
104     }
105     eventCon_.notify_one();
106     runner->Run();
107 }
108 
Execute()109 void StorageMonitorService::Execute()
110 {
111     if (eventHandler_ == nullptr) {
112         LOGE("event handler is nullptr.");
113         return;
114     }
115     MonitorAndManageStorage();
116     auto executeFunc = [this] { Execute(); };
117     eventHandler_->PostTask(executeFunc, DEFAULT_CHECK_INTERVAL);
118 }
119 
MonitorAndManageStorage()120 void StorageMonitorService::MonitorAndManageStorage()
121 {
122     int64_t totalSize;
123     int32_t err = DelayedSingleton<StorageTotalStatusService>::GetInstance()->GetTotalSize(totalSize);
124     if ((err != E_OK) || (totalSize <= 0)) {
125         LOGE("Get device total size failed.");
126         return;
127     }
128 
129     int64_t freeSize;
130     err = DelayedSingleton<StorageTotalStatusService>::GetInstance()->GetFreeSize(freeSize);
131     if ((err != E_OK) || (freeSize < 0)) {
132         LOGE("Get device free size failed.");
133         return;
134     }
135     if (freeSize < (totalSize * STORAGE_LEFT_SIZE_THRESHOLD) / CONST_NUM_ONE_HUNDRED) {
136         CheckAndEventNotify(freeSize, totalSize);
137         CheckAndCleanCache(freeSize, totalSize);
138     }
139 }
140 
CheckAndCleanCache(int64_t freeSize,int64_t totalSize)141 void StorageMonitorService::CheckAndCleanCache(int64_t freeSize, int64_t totalSize)
142 {
143     int64_t lowThreshold = GetLowerThreshold(totalSize);
144     if (lowThreshold <= 0) {
145         LOGE("Lower threshold value is invalid.");
146         return;
147     }
148 
149     LOGI("Device storage freeSize=%{public}lld, threshold=%{public}lld", static_cast<long long>(freeSize),
150          static_cast<long long>(lowThreshold));
151 
152     if (freeSize < (lowThreshold * CONST_NUM_THREE) / CONST_NUM_TWO) {
153         CleanBundleCache(lowThreshold);
154         return;
155     }
156 
157     if (freeSize > (totalSize * STORAGE_THRESHOLD_PERCENTAGE) / CONST_NUM_ONE_HUNDRED) {
158         CleanBundleCacheByInterval(TIMESTAMP_WEEK, lowThreshold, CLEAN_CACHE_WEEK);
159     } else {
160         CleanBundleCacheByInterval(TIMESTAMP_DAY, lowThreshold, SEND_EVENT_INTERVAL);
161     }
162 }
163 
CleanBundleCacheByInterval(const std::string & timestamp,int64_t lowThreshold,int32_t checkInterval)164 void StorageMonitorService::CleanBundleCacheByInterval(const std::string &timestamp,
165                                                        int64_t lowThreshold, int32_t checkInterval)
166 {
167     auto currentTime = std::chrono::system_clock::now();
168     auto curTimePoint =
169             std::chrono::time_point_cast<std::chrono::hours>(currentTime).time_since_epoch().count();
170     std::string param = system::GetParameter(timestamp, "");
171     if (param.empty()) {
172         LOGI("Not found timestamp from system parameter");
173         return;
174     }
175     uint64_t lastCleanCacheTime = std::stoull(param);
176     auto duration = std::chrono::duration_cast<std::chrono::hours>(currentTime -
177             std::chrono::system_clock::time_point(std::chrono::hours(lastCleanCacheTime))).count();
178     LOGI("CleanBundleCache timestamp is %{public}s, duration is %{public}ld", timestamp.c_str(), duration);
179     if (duration >= checkInterval) {
180         CleanBundleCache(lowThreshold);
181         system::SetParameter(timestamp, std::to_string(curTimePoint));
182     }
183 }
184 
CleanBundleCache(int64_t lowThreshold)185 void StorageMonitorService::CleanBundleCache(int64_t lowThreshold)
186 {
187     auto bundleMgr = DelayedSingleton<BundleMgrConnector>::GetInstance()->GetBundleMgrProxy();
188     if (bundleMgr == nullptr) {
189         LOGE("Connect bundle manager sa proxy failed.");
190         return;
191     }
192     LOGI("Device storage free size not enough, start clean bundle cache files automatic.");
193     auto ret = bundleMgr->CleanBundleCacheFilesAutomatic(lowThreshold * CONST_NUM_TWO);
194     if (ret != ERR_OK) {
195         LOGE("Invoke bundleMgr interface to clean bundle cache files automatic failed.");
196     }
197 }
198 
GetLowerThreshold(int64_t totalSize)199 int64_t StorageMonitorService::GetLowerThreshold(int64_t totalSize)
200 {
201     int64_t lowBytes = (totalSize * STORAGE_THRESHOLD_PERCENTAGE) / CONST_NUM_ONE_HUNDRED;
202     return (lowBytes < STORAGE_THRESHOLD_MAX_BYTES) ? lowBytes : STORAGE_THRESHOLD_MAX_BYTES;
203 }
204 
CheckAndEventNotify(int64_t freeSize,int64_t totalSize)205 void StorageMonitorService::CheckAndEventNotify(int64_t freeSize, int64_t totalSize)
206 {
207     LOGI("StorageMonitorService, start CheckAndEventNotify.");
208     if (freeSize < STORAGE_THRESHOLD_100M) {
209         EventNotifyHighFreqHandler();
210         return;
211     }
212     auto currentTime = std::chrono::steady_clock::now();
213     int32_t duration = static_cast<int32_t>(std::chrono::duration_cast<std::chrono::hours>
214             (currentTime - lastNotificationTime_).count());
215     LOGI("StorageMonitorService, duration is %{public}d", duration);
216     if (duration >= SEND_EVENT_INTERVAL) {
217         if (freeSize >= STORAGE_THRESHOLD_1G) {
218             SendSmartNotificationEvent(FAULT_ID_ONE, FAULT_ID_ONE, false);
219         } else {
220             SendSmartNotificationEvent(FAULT_ID_TWO, FAULT_ID_TWO, false);
221         }
222         lastNotificationTime_ = currentTime;
223     }
224 }
225 
SendSmartNotificationEvent(const std::string & faultDesc,const std::string & faultSuggest,bool isHighFreq)226 void StorageMonitorService::SendSmartNotificationEvent(const std::string &faultDesc,
227                                                        const std::string &faultSuggest,
228                                                        bool isHighFreq)
229 {
230     LOGI("StorageMonitorService, start SendSmartNotificationEvent.");
231     EventFwk::CommonEventPublishInfo publishInfo;
232     const std::string permission = PUBLISH_SYSTEM_COMMON_EVENT;
233     std::vector<std::string> permissions;
234     permissions.emplace_back(permission);
235     publishInfo.SetSubscriberPermissions(permissions);
236     publishInfo.SetOrdered(false);
237     publishInfo.SetSticky(false);
238     publishInfo.SetBundleName(SMART_BUNDLE_NAME);
239 
240     AAFwk::Want want;
241     want.SetAction(SMART_ACTION);
242     EventFwk::CommonEventData eventData;
243     eventData.SetWant(want);
244 
245     cJSON *root = cJSON_CreateObject();
246     cJSON_AddStringToObject(root, "faultDescription", faultDesc.c_str());
247     cJSON_AddStringToObject(root, "faultSuggestion", faultSuggest.c_str());
248     if (isHighFreq) {
249         cJSON *faultSuggestionParam = cJSON_CreateString("100M");
250         cJSON *faultSuggestionArray = cJSON_CreateArray();
251         cJSON_AddItemToArray(faultSuggestionArray, faultSuggestionParam);
252         cJSON_AddItemToObject(root, "faultSuggestionParams", faultSuggestionArray);
253     }
254     char *json_string = cJSON_Print(root);
255     std::string eventDataStr(json_string);
256     eventDataStr.erase(remove(eventDataStr.begin(), eventDataStr.end(), '\n'), eventDataStr.end());
257     eventDataStr.erase(remove(eventDataStr.begin(), eventDataStr.end(), '\t'), eventDataStr.end());
258 
259     LOGI("send message is %{public}s", eventDataStr.c_str());
260     eventData.SetData(eventDataStr);
261     cJSON_Delete(root);
262     EventFwk::CommonEventManager::PublishCommonEvent(eventData, publishInfo, nullptr);
263 }
264 
EventNotifyHighFreqHandler()265 void StorageMonitorService::EventNotifyHighFreqHandler()
266 {
267     auto currentTime = std::chrono::steady_clock::now();
268     int32_t duration = static_cast<int32_t>(std::chrono::duration_cast<std::chrono::minutes>
269             (currentTime - lastNotificationTimeHighFreq_).count());
270     LOGI("StorageMonitorService high frequency, duration is %{public}d", duration);
271     if (duration >= SEND_EVENT_INTERVAL_HIGH_FREQ) {
272         SendSmartNotificationEvent(FAULT_ID_THREE, FAULT_SUGGEST_THREE, true);
273         lastNotificationTimeHighFreq_ = currentTime;
274     }
275 }
276 } // StorageManager
277 } // OHOS
278