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 ×tamp,
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