• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <string>
19 #include <sstream>
20 
21 #include "cJSON.h"
22 #include "common_event_manager.h"
23 #include "init_param.h"
24 #include "parameters.h"
25 #include "storage_service_errno.h"
26 #include "storage_service_log.h"
27 #include "storage/bundle_manager_connector.h"
28 #include "storage/storage_total_status_service.h"
29 
30 using namespace OHOS::StorageService;
31 namespace OHOS {
32 namespace StorageManager {
33 constexpr int32_t ONE_MB = 1024 * 1024;
34 constexpr int32_t ONE_GB = 1024 * 1024 * 1024;
35 constexpr int32_t CONST_NUM_TWO = 2;
36 constexpr int32_t CONST_NUM_ONE_HUNDRED = 100;
37 constexpr int32_t CLEAN_CACHE_WEEK = 7 * 24; // week
38 constexpr int32_t WAIT_THREAD_TIMEOUT_MS = 5;
39 constexpr int32_t DEFAULT_CHECK_INTERVAL = 60 * 1000; // 60s
40 constexpr int32_t SEND_EVENT_INTERVAL = 24; // day
41 constexpr int32_t SEND_EVENT_INTERVAL_HIGH_FREQ = 5; // 5m
42 constexpr int32_t MEMORY_PARAMS_PATH_LEN = 128;
43 constexpr const char *DEFAULT_PARAMS = "notify_l:500M/notify_m:2G/notify_h:10%/clean_l:750M/clean_m:5%/clean_h:10%";
44 const std::string PUBLISH_SYSTEM_COMMON_EVENT = "ohos.permission.PUBLISH_SYSTEM_COMMON_EVENT";
45 const std::string SMART_ACTION = "hicare.event.SMART_NOTIFICATION";
46 const std::string TIMESTAMP_DAY = "persist.storage_manager.timestamp.day";
47 const std::string TIMESTAMP_WEEK = "persist.storage_manager.timestamp.week";
48 const std::string FAULT_ID_ONE = "845010021";
49 const std::string FAULT_ID_TWO = "845010022";
50 const std::string FAULT_ID_THREE = "845010023";
51 const std::string FAULT_SUGGEST_THREE = "545010023";
52 constexpr int RETRY_MAX_TIMES = 3;
53 
StorageMonitorService()54 StorageMonitorService::StorageMonitorService() {}
55 
~StorageMonitorService()56 StorageMonitorService::~StorageMonitorService()
57 {
58     LOGI("StorageMonitorService Destructor.");
59     std::unique_lock<std::mutex> lock(eventMutex_);
60     if ((eventHandler_ != nullptr) && (eventHandler_->GetEventRunner() != nullptr)) {
61         eventHandler_->RemoveAllEvents();
62         eventHandler_->GetEventRunner()->Stop();
63     }
64     if (eventThread_.joinable()) {
65         eventThread_.join();
66     }
67     eventHandler_ = nullptr;
68 }
69 
StartStorageMonitorTask()70 void StorageMonitorService::StartStorageMonitorTask()
71 {
72     LOGI("StorageMonitorService, start deicve storage monitor task.");
73     std::unique_lock<std::mutex> lock(eventMutex_);
74     if (eventHandler_ == nullptr) {
75         eventThread_ = std::thread(&StorageMonitorService::StartEventHandler, this);
76         eventCon_.wait_for(lock, std::chrono::seconds(WAIT_THREAD_TIMEOUT_MS), [this] {
77             return eventHandler_ != nullptr;
78         });
79     }
80 
81     auto executeFunc = [this] { Execute(); };
82     eventHandler_->PostTask(executeFunc, DEFAULT_CHECK_INTERVAL);
83 }
84 
StartEventHandler()85 void StorageMonitorService::StartEventHandler()
86 {
87     pthread_setname_np(pthread_self(), "storage_monitor_task_event");
88     auto runner = AppExecFwk::EventRunner::Create(false);
89     if (runner == nullptr) {
90         LOGE("event runner is nullptr.");
91         return;
92     }
93     {
94         std::lock_guard<std::mutex> lock(eventMutex_);
95         eventHandler_ = std::make_shared<AppExecFwk::EventHandler>(runner);
96     }
97     eventCon_.notify_one();
98     runner->Run();
99 }
100 
Execute()101 void StorageMonitorService::Execute()
102 {
103     if (eventHandler_ == nullptr) {
104         LOGE("event handler is nullptr.");
105         return;
106     }
107     MonitorAndManageStorage();
108     auto executeFunc = [this] { Execute(); };
109     eventHandler_->PostTask(executeFunc, DEFAULT_CHECK_INTERVAL);
110 }
111 
MonitorAndManageStorage()112 void StorageMonitorService::MonitorAndManageStorage()
113 {
114     int64_t totalSize;
115     int32_t err = StorageTotalStatusService::GetInstance().GetTotalSize(totalSize);
116     if ((err != E_OK) || (totalSize <= 0)) {
117         LOGE("Get device total size failed.");
118         return;
119     }
120 
121     int64_t freeSize;
122     err = StorageTotalStatusService::GetInstance().GetFreeSize(freeSize);
123     if ((err != E_OK) || (freeSize < 0)) {
124         LOGE("Get device free size failed.");
125         return;
126     }
127     ParseMemoryParameters(totalSize);
128 
129     LOGI("clean_l, size=%{public}lld, clean_m, size=%{public}lld, clean_h, size=%{public}lld",
130          static_cast<long long>(thresholds["clean_l"]), static_cast<long long>(thresholds["clean_m"]),
131          static_cast<long long>(thresholds["clean_h"]));
132     if (freeSize < thresholds["clean_h"]) {
133         CheckAndCleanCache(freeSize, totalSize);
134     }
135 
136     LOGI("notify_l, size=%{public}lld, notify_m, size=%{public}lld, notify_h, size=%{public}lld",
137         static_cast<long long>(thresholds["notify_l"]), static_cast<long long>(thresholds["notify_m"]),
138         static_cast<long long>(thresholds["notify_h"]));
139     if (freeSize < thresholds["notify_h"]) {
140         CheckAndEventNotify(freeSize, totalSize);
141         hasNotifiedStorageEvent_ = true;
142     } else if (hasNotifiedStorageEvent_) {
143         RefreshAllNotificationTimeStamp();
144         hasNotifiedStorageEvent_ = false;
145     }
146 }
147 
GetMemoryAlertCleanupParams()148 std::string StorageMonitorService::GetMemoryAlertCleanupParams()
149 {
150     std::string memoryParams;
151     char tmpBuffer[MEMORY_PARAMS_PATH_LEN] = {0};
152     uint32_t tmpLen = MEMORY_PARAMS_PATH_LEN;
153 
154     if (SystemGetParameter("memory.alert.cleanup", tmpBuffer, &tmpLen) == 0) {
155         memoryParams = tmpBuffer;
156     } else {
157         LOGE("Failed to read memory.alert.cleanup, using default");
158         memoryParams = DEFAULT_PARAMS;
159     }
160 
161     return memoryParams;
162 }
163 
ParseMemoryParameters(int64_t totalSize)164 void StorageMonitorService::ParseMemoryParameters(int64_t totalSize)
165 {
166     std::string memoryParams = GetMemoryAlertCleanupParams();
167     std::istringstream memoryParamsStream(memoryParams);
168     std::string item;
169     while (std::getline(memoryParamsStream, item, '/')) {
170         std::string key;
171         std::string value;
172 
173         size_t pos = item.find(':');
174         if (pos != std::string::npos) {
175             key = item.substr(0, pos);
176             value = item.substr(pos + 1);
177         } else {
178             LOGE("Invalid parameter format");
179             continue;
180         }
181 
182         if (value.length() > 1 && value.substr(value.length() - 1) == "%") {
183             int percentage = std::atoi(value.substr(0, value.length() - 1).c_str());
184             if (percentage < 0 || percentage > CONST_NUM_ONE_HUNDRED) {
185                 LOGE("Invalid percentage value");
186             } else {
187                 int64_t size = (totalSize * percentage) / CONST_NUM_ONE_HUNDRED;
188                 thresholds[key] = static_cast<int64_t>(size);
189             }
190         } else if (value.length() > 1 && value.substr(value.length() - 1) == "G") {
191             int gigabytes = std::atoi(value.substr(0, value.length() - 1).c_str());
192             if (gigabytes < 0) {
193                 LOGE("Memory value cannot be negative: %{public}d G", gigabytes);
194             } else {
195                 int64_t size = static_cast<int64_t>(gigabytes) * ONE_GB;
196                 thresholds[key] = static_cast<int64_t>(size);
197             }
198         } else if (value.length() > 1 && value.substr(value.length() - 1) == "M") {
199             int megabytes = std::atoi(value.substr(0, value.length() - 1).c_str());
200             if (megabytes < 0) {
201                 LOGE("Memory value cannot be negative: %{public}d M", megabytes);
202             } else {
203                 int64_t size = static_cast<int64_t>(megabytes) * ONE_MB;
204                 thresholds[key] = static_cast<int64_t>(size);
205             }
206         } else {
207             LOGE("parameter value format is invalid");
208         }
209     }
210 }
211 
CheckAndCleanCache(int64_t freeSize,int64_t totalSize)212 void StorageMonitorService::CheckAndCleanCache(int64_t freeSize, int64_t totalSize)
213 {
214     int64_t lowThreshold = thresholds["clean_l"];
215     if (lowThreshold <= 0) {
216         LOGE("Lower threshold value is invalid.");
217         return;
218     }
219 
220     LOGI("Device storage freeSize=%{public}lld, threshold=%{public}lld", static_cast<long long>(freeSize),
221          static_cast<long long>(lowThreshold));
222 
223     std::string freeSizeStr = std::to_string(freeSize);
224     std::string totalSizeStr = std::to_string(totalSize);
225     std::string lowThresholdStr = std::to_string(lowThreshold);
226     std::string storageUsage = "storage usage not enough:freeSize = " + freeSizeStr + ", totalSize = " + totalSizeStr +
227                                ", lowThreshold = " + lowThresholdStr;
228     if (freeSize < lowThreshold) {
229         CleanBundleCache(lowThreshold);
230         ReportRadarStorageUsage(StorageService::BizStage::BIZ_STAGE_THRESHOLD_CLEAN_LOW, storageUsage);
231         LOGI("Device running out of memory");
232         return;
233     }
234 
235     if (freeSize > thresholds["clean_m"]) {
236         CleanBundleCacheByInterval(TIMESTAMP_WEEK, lowThreshold, CLEAN_CACHE_WEEK);
237         ReportRadarStorageUsage(StorageService::BizStage::BIZ_STAGE_THRESHOLD_CLEAN_HIGH, storageUsage);
238     } else {
239         CleanBundleCacheByInterval(TIMESTAMP_DAY, lowThreshold, SEND_EVENT_INTERVAL);
240         ReportRadarStorageUsage(StorageService::BizStage::BIZ_STAGE_THRESHOLD_CLEAN_MEDIUM, storageUsage);
241     }
242 }
243 
CleanBundleCacheByInterval(const std::string & timestamp,int64_t lowThreshold,int32_t checkInterval)244 void StorageMonitorService::CleanBundleCacheByInterval(const std::string &timestamp,
245                                                        int64_t lowThreshold, int32_t checkInterval)
246 {
247     auto currentTime = std::chrono::system_clock::now();
248     auto curTimePoint =
249             std::chrono::time_point_cast<std::chrono::hours>(currentTime).time_since_epoch().count();
250     std::string param = system::GetParameter(timestamp, "");
251     if (param.empty()) {
252         LOGI("Not found timestamp from system parameter");
253         return;
254     }
255     uint64_t lastCleanCacheTime = static_cast<uint64_t>(std::atoll(param.c_str()));
256     auto duration = std::chrono::duration_cast<std::chrono::hours>(currentTime -
257             std::chrono::system_clock::time_point(std::chrono::hours(lastCleanCacheTime))).count();
258     LOGI("CleanBundleCache timestamp is %{public}s, duration is %{public}ld", timestamp.c_str(), duration);
259     if (duration >= checkInterval) {
260         CleanBundleCache(lowThreshold);
261         system::SetParameter(timestamp, std::to_string(curTimePoint));
262     }
263 }
264 
ReportRadarStorageUsage(enum StorageService::BizStage stage,const std::string & extraData)265 void StorageMonitorService::ReportRadarStorageUsage(enum StorageService::BizStage stage, const std::string &extraData)
266 {
267     LOGI("storage monitor service report radar storage usage start");
268     StorageService::StorageRadar::ReportStorageUsage(stage, extraData);
269 }
270 
CleanBundleCache(int64_t lowThreshold)271 void StorageMonitorService::CleanBundleCache(int64_t lowThreshold)
272 {
273     auto bundleMgr = BundleMgrConnector::GetInstance().GetBundleMgrProxy();
274     if (bundleMgr == nullptr) {
275         LOGE("Connect bundle manager sa proxy failed.");
276         return;
277     }
278     LOGI("Device storage free size not enough, start clean bundle cache files automatic.");
279     int32_t ret = E_OK;
280     int retryCount = 0;
281     do {
282         ret = bundleMgr->CleanBundleCacheFilesAutomatic(lowThreshold * CONST_NUM_TWO);
283         if (ret == ERR_OK) {
284             LOGI("Invoke bundleMgr interface to clean bundle cache files automatic success.");
285             return;
286         }
287         retryCount ++;
288         LOGE("Invoke bundleMgr interface to clean bundle cache files automatic failed. Retry.");
289     } while (retryCount < RETRY_MAX_TIMES);
290     StorageRadar::ReportBundleMgrResult("CleanBundleCacheFilesAutomatic", ret, DEFAULT_USERID, "");
291 }
292 
CheckAndEventNotify(int64_t freeSize,int64_t totalSize)293 void StorageMonitorService::CheckAndEventNotify(int64_t freeSize, int64_t totalSize)
294 {
295     LOGI("StorageMonitorService, start CheckAndEventNotify.");
296     std::string freeSizeStr = std::to_string(freeSize);
297     std::string totalSizeStr = std::to_string(totalSize);
298     std::string storageUsage = "storage usage not enough event notify freeSize = " + freeSizeStr + ", totalSize = " +
299                                totalSizeStr;
300     if (freeSize < thresholds["notify_l"]) {
301         EventNotifyFreqHandlerForLow();
302         storageUsage += ", freeSize < " + std::to_string(thresholds["notify_l"]) + ", success notify event";
303         ReportRadarStorageUsage(StorageService::BizStage::BIZ_STAGE_THRESHOLD_NOTIFY_LOW, storageUsage);
304         return;
305     }
306     if (freeSize < thresholds["notify_m"]) {
307         EventNotifyFreqHandlerForMedium();
308         storageUsage += ", freeSize < " + std::to_string(thresholds["notify_m"]) + ", success notify event";
309         ReportRadarStorageUsage(StorageService::BizStage::BIZ_STAGE_THRESHOLD_NOTIFY_MEDIUM, storageUsage);
310         return;
311     }
312     EventNotifyFreqHandlerForHigh();
313 }
314 
SendSmartNotificationEvent(const std::string & faultDesc,const std::string & faultSuggest,bool isHighFreq)315 void StorageMonitorService::SendSmartNotificationEvent(const std::string &faultDesc,
316                                                        const std::string &faultSuggest,
317                                                        bool isHighFreq)
318 {
319     LOGI("StorageMonitorService, start SendSmartNotificationEvent.");
320     EventFwk::CommonEventPublishInfo publishInfo;
321     const std::string permission = PUBLISH_SYSTEM_COMMON_EVENT;
322     std::vector<std::string> permissions;
323     permissions.emplace_back(permission);
324     publishInfo.SetSubscriberPermissions(permissions);
325     publishInfo.SetOrdered(false);
326     publishInfo.SetSticky(false);
327 
328     AAFwk::Want want;
329     want.SetAction(SMART_ACTION);
330     EventFwk::CommonEventData eventData;
331     eventData.SetWant(want);
332 
333     cJSON *root = cJSON_CreateObject();
334     cJSON_AddStringToObject(root, "faultDescription", faultDesc.c_str());
335     cJSON_AddStringToObject(root, "faultSuggestion", faultSuggest.c_str());
336     if (isHighFreq) {
337         cJSON *faultSuggestionParam = cJSON_CreateString("500M");
338         cJSON *faultSuggestionArray = cJSON_CreateArray();
339         cJSON_AddItemToArray(faultSuggestionArray, faultSuggestionParam);
340         cJSON_AddItemToObject(root, "faultSuggestionParams", faultSuggestionArray);
341     }
342     char *json_string = cJSON_Print(root);
343     std::string eventDataStr(json_string);
344     eventDataStr.erase(remove(eventDataStr.begin(), eventDataStr.end(), '\n'), eventDataStr.end());
345     eventDataStr.erase(remove(eventDataStr.begin(), eventDataStr.end(), '\t'), eventDataStr.end());
346 
347     LOGI("send message is %{public}s", eventDataStr.c_str());
348     eventData.SetData(eventDataStr);
349     free(json_string);
350     cJSON_Delete(root);
351     EventFwk::CommonEventManager::PublishCommonEvent(eventData, publishInfo, nullptr);
352 }
353 
EventNotifyFreqHandlerForLow()354 void StorageMonitorService::EventNotifyFreqHandlerForLow()
355 {
356     auto currentTime = std::chrono::system_clock::now();
357     int32_t duration = static_cast<int32_t>(std::chrono::duration_cast<std::chrono::minutes>
358             (currentTime - lastNotificationTimeHighFreq_).count());
359     LOGW("StorageMonitorService left Storage Size < Low, duration is %{public}d", duration);
360     if (duration >= SEND_EVENT_INTERVAL_HIGH_FREQ) {
361         lastNotificationTimeHighFreq_ = currentTime;
362         lastNotificationTime_ =
363                 std::chrono::time_point_cast<std::chrono::system_clock::duration>(
364                         std::chrono::system_clock::now()) - std::chrono::hours(SEND_EVENT_INTERVAL);
365         lastNotificationTimeMedium_ =
366                 std::chrono::time_point_cast<std::chrono::system_clock::duration>(
367                         std::chrono::system_clock::now()) - std::chrono::hours(SEND_EVENT_INTERVAL);
368     }
369 }
370 
EventNotifyFreqHandlerForMedium()371 void StorageMonitorService::EventNotifyFreqHandlerForMedium()
372 {
373     auto currentTime = std::chrono::system_clock::now();
374     int32_t duration = static_cast<int32_t>(std::chrono::duration_cast<std::chrono::hours>
375             (currentTime - lastNotificationTimeMedium_).count());
376     LOGW("StorageMonitorService left Storage Size < Medium, duration is %{public}d", duration);
377     if (duration >= SEND_EVENT_INTERVAL) {
378         lastNotificationTimeMedium_ = currentTime;
379         lastNotificationTime_ =
380                 std::chrono::time_point_cast<std::chrono::system_clock::duration>(
381                         std::chrono::system_clock::now()) - std::chrono::hours(SEND_EVENT_INTERVAL);
382         lastNotificationTimeHighFreq_ =
383                 std::chrono::time_point_cast<std::chrono::system_clock::duration>(
384                         std::chrono::system_clock::now()) - std::chrono::minutes(SMART_EVENT_INTERVAL_HIGH_FREQ);
385     }
386 }
387 
EventNotifyFreqHandlerForHigh()388 void StorageMonitorService::EventNotifyFreqHandlerForHigh()
389 {
390     auto currentTime = std::chrono::system_clock::now();
391     int32_t duration = static_cast<int32_t>(std::chrono::duration_cast<std::chrono::hours>
392             (currentTime - lastNotificationTime_).count());
393     LOGW("StorageMonitorService left Storage Size < High, duration is %{public}d", duration);
394     if (duration >= SEND_EVENT_INTERVAL) {
395         lastNotificationTime_ = currentTime;
396         lastNotificationTimeMedium_ =
397                 std::chrono::time_point_cast<std::chrono::system_clock::duration>(
398                         std::chrono::system_clock::now()) - std::chrono::hours(SEND_EVENT_INTERVAL);
399         lastNotificationTimeHighFreq_ =
400                 std::chrono::time_point_cast<std::chrono::system_clock::duration>(
401                         std::chrono::system_clock::now()) - std::chrono::minutes(SMART_EVENT_INTERVAL_HIGH_FREQ);
402     }
403 }
404 
RefreshAllNotificationTimeStamp()405 void StorageMonitorService::RefreshAllNotificationTimeStamp()
406 {
407     lastNotificationTime_ =
408             std::chrono::time_point_cast<std::chrono::system_clock::duration>(
409                     std::chrono::system_clock::now()) - std::chrono::hours(SEND_EVENT_INTERVAL);
410 
411     lastNotificationTimeMedium_ =
412             std::chrono::time_point_cast<std::chrono::system_clock::duration>(
413                     std::chrono::system_clock::now()) - std::chrono::hours(SEND_EVENT_INTERVAL);
414 
415     lastNotificationTimeHighFreq_ =
416             std::chrono::time_point_cast<std::chrono::system_clock::duration>(
417                     std::chrono::system_clock::now()) - std::chrono::minutes(SMART_EVENT_INTERVAL_HIGH_FREQ);
418 }
419 } // StorageManager
420 } // OHOS