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 "cloud_daemon_statistic.h"
17
18 #include <fcntl.h>
19 #include <fstream>
20 #include <sys/stat.h>
21 #include <unistd.h>
22
23 #include "dfs_error.h"
24 #include "meta_file.h"
25 #include "hisysevent.h"
26 #include "utils_log.h"
27
28 namespace OHOS {
29 namespace FileManagement {
30 namespace CloudFile {
31 using namespace std;
32
33 #define FILE_SIZE_BYTE_TO_KB 1024
34 #define FILE_SIZE_KB_TO_MB 1024
35 #define STAT_TIME_MS_TO_S 1000
36 #define CLOUD_FILE_DIR_MOD 0770
37 #define CLOUD_FILE_MOD 0660
38 #define CLOUD_SYNC_SYS_EVENT(eventName, type, ...) \
39 HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::FILEMANAGEMENT, eventName, \
40 type, ##__VA_ARGS__) \
41
42 static const string STAT_DATA_DIR_NAME = "/data/service/el1/public/cloudfile/cloud_data_statistic";
43 static const string STAT_DATA_FILE_NAME = "cloud_sync_read_file_stat";
44 static const vector<uint64_t> OPEN_SIZE_RANGE_VECTOR = { 256, 512, 1 * FILE_SIZE_KB_TO_MB, 2 * FILE_SIZE_KB_TO_MB,
45 4 * FILE_SIZE_KB_TO_MB, 6 * FILE_SIZE_KB_TO_MB, 8 * FILE_SIZE_KB_TO_MB, 15 * FILE_SIZE_KB_TO_MB };
46 static const vector<uint64_t> OPEN_TIME_RANGE_VECTOR = { 250, 500, 1000, 1500, 2000, 5000 };
47 static const vector<uint64_t> READ_SIZE_RANGE_VECTOR = { 128, 256, 512, 1 * FILE_SIZE_KB_TO_MB, 2 * FILE_SIZE_KB_TO_MB,
48 4 * FILE_SIZE_KB_TO_MB };
49 static const vector<uint64_t> READ_TIME_RANGE_VECTOR = { 300, 600, 900, 1200, 1500, 2000, 3000, 5000, 8000 };
50
GetRangeIndex(uint64_t value,const vector<uint64_t> rangeVector)51 static uint32_t GetRangeIndex(uint64_t value, const vector<uint64_t> rangeVector)
52 {
53 uint32_t index = 0;
54 for (; index < rangeVector.size(); index++) {
55 if (value <= rangeVector[index]) {
56 break;
57 }
58 }
59 return index;
60 }
61
CheckOverflow(uint64_t & data,uint64_t addValue)62 static void CheckOverflow(uint64_t &data, uint64_t addValue)
63 {
64 if (data >= UINT64_MAX - addValue) {
65 LOGE("update fail, overflow, data = %{public}llu, addValue = %{public}llu",
66 static_cast<unsigned long long>(data),
67 static_cast<unsigned long long>(addValue));
68 data = 0;
69 } else {
70 data += addValue;
71 }
72 }
73
CheckOverflow(uint32_t & data,uint32_t addValue)74 static void CheckOverflow(uint32_t &data, uint32_t addValue)
75 {
76 if (data > UINT32_MAX - addValue) {
77 LOGE("update fail, overflow, data = %{public}d, addValue = %{public}d",
78 data, addValue);
79 data = UINT32_MAX;
80 } else {
81 data += addValue;
82 }
83 }
84
UpdateOpenSizeStat(uint64_t size)85 void CloudDaemonStatistic::UpdateOpenSizeStat(uint64_t size)
86 {
87 uint32_t index = GetRangeIndex(size / FILE_SIZE_BYTE_TO_KB, OPEN_SIZE_RANGE_VECTOR);
88 if (index >= OPEN_SIZE_MAX) {
89 LOGE("update open size stat fail, index overflow, index = %{public}u.", index);
90 return;
91 }
92 CheckOverflow(openSizeStat_[index], 1);
93 }
94
UpdateOpenTimeStat(uint32_t type,uint64_t time)95 void CloudDaemonStatistic::UpdateOpenTimeStat(uint32_t type, uint64_t time)
96 {
97 uint32_t index = GetRangeIndex(time, OPEN_TIME_RANGE_VECTOR);
98 if (index >= OPEN_TIME_MAX) {
99 LOGE("update open time stat fail, index overflow, index = %{public}u.", index);
100 return;
101 }
102 CheckOverflow(openTimeStat_[type][index], 1);
103 }
104
UpdateReadSizeStat(uint64_t size)105 void CloudDaemonStatistic::UpdateReadSizeStat(uint64_t size)
106 {
107 uint32_t index = GetRangeIndex(size / FILE_SIZE_BYTE_TO_KB, READ_SIZE_RANGE_VECTOR);
108 if (index >= READ_SIZE_MAX) {
109 LOGE("update read size stat fail, index overflow, index = %{public}u.", index);
110 return;
111 }
112 CheckOverflow(readSizeStat_[index], 1);
113 }
114
UpdateReadTimeStat(uint64_t size,uint64_t time)115 void CloudDaemonStatistic::UpdateReadTimeStat(uint64_t size, uint64_t time)
116 {
117 uint32_t indexSize = GetRangeIndex(size / FILE_SIZE_BYTE_TO_KB, READ_SIZE_RANGE_VECTOR);
118 uint32_t indexTime = GetRangeIndex(time, READ_TIME_RANGE_VECTOR);
119 if (indexSize >= READ_SIZE_MAX || indexTime >= READ_TIME_MAX) {
120 LOGE("update read time stat fail, index overflow, indexSize = %{public}u, indexTime = %{public}u.",
121 indexSize, indexTime);
122 return;
123 }
124 CheckOverflow(readTimeStat_[indexSize][indexTime], 1);
125 }
126
UpdateReadInfo(uint32_t index)127 void CloudDaemonStatistic::UpdateReadInfo(uint32_t index)
128 {
129 if (index >= VIDEO_READ_INFO) {
130 return;
131 }
132 CheckOverflow(videoReadInfo_[index], 1);
133 }
134
UpdateBundleName(const std::string & bundleName)135 void CloudDaemonStatistic::UpdateBundleName(const std::string &bundleName)
136 {
137 bundleName_ = bundleName;
138 }
139
AddFileData(CloudDaemonStatisticInfo & info)140 void CloudDaemonStatistic::AddFileData(CloudDaemonStatisticInfo &info)
141 {
142 /* file not exist means first time, no former data, normal case */
143 auto ret = access(STAT_DATA_DIR_NAME.c_str(), F_OK);
144 if (ret != 0) {
145 LOGI("dir cloud_data_statistic not exist, ret = %{public}d.", ret);
146 return;
147 }
148 std::ifstream statDataFile(STAT_DATA_DIR_NAME + "/" + STAT_DATA_FILE_NAME);
149 if (!statDataFile) {
150 LOGI("file cloud_sync_read_file_stat not exist.");
151 return;
152 }
153
154 for (uint32_t i = 0; i < OPEN_SIZE_MAX; i++) {
155 statDataFile >> info.openSizeStat[i];
156 }
157 for (uint32_t i = 0; i < FILE_TYPE_MAX; i++) {
158 for (uint32_t j = 0; j < OPEN_TIME_MAX; j++) {
159 statDataFile >> info.openTimeStat[i][j];
160 }
161 }
162 for (uint32_t i = 0; i < READ_SIZE_MAX; i++) {
163 statDataFile >> info.readSizeStat[i];
164 }
165 for (uint32_t i = 0; i < READ_SIZE_MAX; i++) {
166 for (uint32_t j = 0; j < READ_TIME_MAX; j++) {
167 statDataFile >> info.readTimeStat[i][j];
168 }
169 }
170 for (uint32_t i = 0; i < VIDEO_READ_INFO; i++) {
171 statDataFile >> info.videoReadInfo[i];
172 }
173 statDataFile >> info.bundleName;
174 statDataFile.close();
175 }
176
CheckFileStat()177 int32_t CloudDaemonStatistic::CheckFileStat()
178 {
179 if (access(STAT_DATA_DIR_NAME.c_str(), F_OK) != 0) {
180 auto ret = mkdir(STAT_DATA_DIR_NAME.c_str(), CLOUD_FILE_DIR_MOD);
181 if (ret != 0) {
182 LOGE("mkdir cloud_data_statistic fail, ret = %{public}d.", ret);
183 return ret;
184 }
185 }
186 string statFilePath = STAT_DATA_DIR_NAME + "/" + STAT_DATA_FILE_NAME;
187 if (access(statFilePath.c_str(), F_OK) != 0) {
188 auto fd = creat(statFilePath.c_str(), CLOUD_FILE_MOD);
189 if (fd < 0) {
190 LOGE("create file cloud_sync_read_file_stat fail.");
191 return E_NO_SUCH_FILE;
192 }
193 close(fd);
194 }
195 return E_OK;
196 }
197
OutputToFile()198 void CloudDaemonStatistic::OutputToFile()
199 {
200 string tmpStr = "";
201
202 int32_t ret = CheckFileStat();
203 if (ret != E_OK) {
204 return;
205 }
206 string statFilePath = STAT_DATA_DIR_NAME + "/" + STAT_DATA_FILE_NAME;
207 std::ofstream statDataFile(statFilePath);
208 if (!statDataFile) {
209 LOGE("open out stream file cloud_sync_read_file_stat fail.");
210 return;
211 }
212 for (uint32_t i = 0; i < OPEN_SIZE_MAX; i++) {
213 tmpStr += (to_string(openSizeStat_[i]) + " ");
214 }
215 statDataFile << tmpStr << endl << endl;
216 tmpStr = "";
217 for (uint32_t i = 0; i < FILE_TYPE_MAX; i++) {
218 for (uint32_t j = 0; j < OPEN_TIME_MAX; j++) {
219 tmpStr += (to_string(openTimeStat_[i][j]) + " ");
220 }
221 tmpStr += "\n";
222 }
223 statDataFile << tmpStr << endl;
224 tmpStr = "";
225 for (uint32_t i = 0; i < READ_SIZE_MAX; i++) {
226 tmpStr += (to_string(readSizeStat_[i]) + " ");
227 }
228 statDataFile << tmpStr << endl << endl;
229 tmpStr = "";
230 for (uint32_t i = 0; i < READ_SIZE_MAX; i++) {
231 for (uint32_t j = 0; j < READ_TIME_MAX; j++) {
232 tmpStr += (to_string(readTimeStat_[i][j]) + " ");
233 }
234 tmpStr += "\n";
235 }
236 statDataFile << tmpStr << endl;
237 tmpStr = "";
238 for (uint32_t i = 0; i < VIDEO_READ_INFO; i++) {
239 tmpStr += (to_string(videoReadInfo_[i]) + " ");
240 }
241 statDataFile << tmpStr << endl;
242 statDataFile << bundleName_ << endl;
243 statDataFile.close();
244 }
245
ClearStat()246 void CloudDaemonStatistic::ClearStat()
247 {
248 for (uint32_t i = 0; i < OPEN_SIZE_MAX; i++) {
249 openSizeStat_[i] = 0;
250 }
251 for (uint32_t i = 0; i < FILE_TYPE_MAX; i++) {
252 for (uint32_t j = 0; j < OPEN_TIME_MAX; j++) {
253 openTimeStat_[i][j] = 0;
254 }
255 }
256 for (uint32_t i = 0; i < READ_SIZE_MAX; i++) {
257 readSizeStat_[i] = 0;
258 }
259 for (uint32_t i = 0; i < READ_SIZE_MAX; i++) {
260 for (uint32_t j = 0; j < READ_TIME_MAX; j++) {
261 readTimeStat_[i][j] = 0;
262 }
263 }
264 for (uint32_t i = 0; i < VIDEO_READ_INFO; i++) {
265 videoReadInfo_[i] = 0;
266 }
267 }
268
SumTwoReadStat(const CloudDaemonStatisticInfo & info)269 void CloudDaemonStatistic::SumTwoReadStat(const CloudDaemonStatisticInfo &info)
270 {
271 for (uint32_t i = 0; i < OPEN_SIZE_MAX; i++) {
272 CheckOverflow(openSizeStat_[i], info.openSizeStat[i]);
273 }
274 for (uint32_t i = 0; i < FILE_TYPE_MAX; i++) {
275 for (uint32_t j = 0; j < OPEN_TIME_MAX; j++) {
276 CheckOverflow(openTimeStat_[i][j], info.openTimeStat[i][j]);
277 }
278 }
279 for (uint32_t i = 0; i < READ_SIZE_MAX; i++) {
280 CheckOverflow(readSizeStat_[i], info.readSizeStat[i]);
281 }
282 for (uint32_t i = 0; i < READ_SIZE_MAX; i++) {
283 for (uint32_t j = 0; j < READ_TIME_MAX; j++) {
284 CheckOverflow(readTimeStat_[i][j], info.readTimeStat[i][j]);
285 }
286 }
287 for (uint32_t i = 0; i < VIDEO_READ_INFO; i++) {
288 CheckOverflow(videoReadInfo_[i], info.videoReadInfo[i]);
289 }
290 }
291
ReportReadStat(const CloudDaemonStatisticInfo & info)292 int32_t CloudDaemonStatistic::ReportReadStat(const CloudDaemonStatisticInfo &info)
293 {
294 int32_t ret = CLOUD_SYNC_SYS_EVENT("CLOUD_SYNC_READ_FILE_STAT",
295 HiviewDFX::HiSysEvent::EventType::STATISTIC,
296 "open_size", info.openSizeStat,
297 "open_thm_time", info.openTimeStat[FILE_TYPE_THUMBNAIL],
298 "open_lcd_time", info.openTimeStat[FILE_TYPE_LCD],
299 "open_content_time", info.openTimeStat[FILE_TYPE_CONTENT],
300 "read_size", info.readSizeStat,
301 "read_time_128KB", info.readTimeStat[READ_SIZE_128K],
302 "read_time_256KB", info.readTimeStat[READ_SIZE_256K],
303 "read_time_512KB", info.readTimeStat[READ_SIZE_512K],
304 "read_time_1M", info.readTimeStat[READ_SIZE_1M],
305 "read_time_2M", info.readTimeStat[READ_SIZE_2M],
306 "read_time_4M", info.readTimeStat[READ_SIZE_4M],
307 "video_read_info", info.videoReadInfo,
308 "bundle_name", info.bundleName
309 );
310 return ret;
311 }
312
HandleBundleName(const CloudDaemonStatisticInfo & info)313 void CloudDaemonStatistic::HandleBundleName(const CloudDaemonStatisticInfo &info)
314 {
315 if (!info.bundleName.empty() && info.bundleName != bundleName_) {
316 auto ret = ReportReadStat(info);
317 if (ret != E_OK) {
318 LOGE("report CLOUD_SYNC_READ_FILE_STAT error %{public}d", ret);
319 }
320 } else {
321 SumTwoReadStat(info);
322 }
323 }
324
UpdateStatData()325 void CloudDaemonStatistic::UpdateStatData()
326 {
327 lock_guard<mutex> lock(mutex_);
328 CloudDaemonStatisticInfo info;
329 AddFileData(info);
330 HandleBundleName(info);
331 OutputToFile();
332 ClearStat();
333 }
334
GetInstance()335 CloudDaemonStatistic &CloudDaemonStatistic::GetInstance()
336 {
337 static CloudDaemonStatistic instance_;
338 return instance_;
339 }
340
341 } // namespace CloudFile
342 } // namespace FileManagement
343 } // namespace OHOS