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