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