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 #include "gallery_download_file_stat.h"
16
17 #include <fcntl.h>
18 #include <fstream>
19 #include <sys/stat.h>
20 #include <unistd.h>
21
22 #include "dfs_error.h"
23 #include "hisysevent.h"
24 #include "utils_log.h"
25
26 namespace OHOS {
27 namespace FileManagement {
28 namespace CloudFile {
29 #define TYPE_DOWNLOAD_FILE_IMAGE 1
30 #define TYPE_DOWNLOAD_FILE_VIDEO 2
31 #define DOWNLOAD_FILE_BYTE_SIZE 1e6
32 #define DIR_MODE 0770
33 #define FILE_MODE 0660
34 #define CLOUD_SYNC_SYS_EVENT(eventName, type, ...) \
35 HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::FILEMANAGEMENT, eventName, \
36 type, ##__VA_ARGS__) \
37
38 const std::string DOWNLOAD_FILE_STAT_LOCAL_PATH = "/data/service/el1/public/cloudfile/cloud_data_statistic/";
39 const std::string DOWNLOAD_FILE_STAT_NAME = "cloud_sync_download_file_stat";
40 const std::vector<uint64_t> DOWNLOAD_IMAGE_SIZE_RANGE_VECTOR = { 2, 4, 6, 8, 15 };
41 const std::vector<uint64_t> DOWNLOAD_VIDEO_SIZE_RANGE_VECTOR = { 20, 40, 80, 200, 400, 800 };
42
43 enum DownloadFileStatIndex {
44 DOWNLOAD_FILE_ERROR = 1,
45 DOWNLOAD_IMAGE_SIZE,
46 DOWNLOAD_IMAGE_SPEED,
47 DOWNLOAD_VIDEO_SIZE,
48 DOWNLOAD_VIDEO_SPEED,
49 };
50
CreateDataStatisticFolder()51 static int32_t CreateDataStatisticFolder()
52 {
53 std::string path = DOWNLOAD_FILE_STAT_LOCAL_PATH;
54 if (access(path.c_str(), F_OK) == 0) {
55 LOGI("cloud data statistic folder already exists");
56 return E_OK;
57 }
58 int32_t ret = mkdir(path.c_str(), DIR_MODE);
59 if (ret != E_OK) {
60 LOGE("Create cloud data statistic folder fail errno = %{public}d", errno);
61 return E_PATH;
62 }
63 return E_OK;
64 }
65
CreateDownloadFileStatData()66 static int32_t CreateDownloadFileStatData()
67 {
68 const std::string path = DOWNLOAD_FILE_STAT_LOCAL_PATH + DOWNLOAD_FILE_STAT_NAME;
69 if (access(path.c_str(), F_OK) == 0) {
70 LOGI("download file statistics data file already exists");
71 return E_OK;
72 }
73 int fd = open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, FILE_MODE);
74 if (fd == -1) {
75 LOGE("create file downloadstatistic report fail, ret = %{public}d", errno);
76 return errno;
77 }
78 close(fd);
79 return E_OK;
80 }
81
GalleryDownloadFileStat()82 GalleryDownloadFileStat::GalleryDownloadFileStat()
83 {
84 auto ret = CreateDataStatisticFolder();
85 if (ret !=E_OK) {
86 LOGE("create data statistic failed with error %{public}d", ret);
87 return;
88 }
89 ret = CreateDownloadFileStatData();
90 if (ret != E_OK) {
91 LOGE("create download file stat failed with error %{public}d", ret);
92 return;
93 }
94 }
95
GetRangeIndex(uint64_t value,const std::vector<uint64_t> rangeVector)96 static uint32_t GetRangeIndex(uint64_t value, const std::vector<uint64_t> rangeVector)
97 {
98 uint32_t index = 0;
99 for (; index < rangeVector.size(); index++) {
100 if (value <= rangeVector[index] * DOWNLOAD_FILE_BYTE_SIZE) {
101 break;
102 }
103 }
104 return index;
105 }
106
UpdateDownloadSpeedStat(uint32_t mediaType,uint64_t size,uint64_t duration)107 void GalleryDownloadFileStat::UpdateDownloadSpeedStat(uint32_t mediaType, uint64_t size, uint64_t duration)
108 {
109 double sizeMb = static_cast<double>(size) / DOWNLOAD_FILE_BYTE_SIZE;
110 double time = static_cast<double>(duration) / DOWNLOAD_FILE_BYTE_SIZE;
111
112 double precision = 1e-10;
113 uint32_t indexSpeed = 15;
114 if (abs(time) > precision) {
115 double speed = sizeMb / time;
116 indexSpeed = static_cast<uint32_t>(floor(speed));
117 }
118 if (mediaType == TYPE_DOWNLOAD_FILE_IMAGE && indexSpeed < stat_.imageDownloadSpeed.size()) {
119 stat_.imageDownloadSpeed[indexSpeed]++;
120 }
121 if (mediaType == TYPE_DOWNLOAD_FILE_VIDEO && indexSpeed < stat_.videoDownloadSpeed.size()) {
122 stat_.videoDownloadSpeed[indexSpeed]++;
123 }
124 }
125
UpdateDownloadSizeStat(uint32_t mediaType,uint64_t size,uint64_t duration)126 void GalleryDownloadFileStat::UpdateDownloadSizeStat(uint32_t mediaType, uint64_t size, uint64_t duration)
127 {
128 std::vector<uint64_t> rangeVector;
129 if (mediaType == TYPE_DOWNLOAD_FILE_IMAGE) {
130 rangeVector = DOWNLOAD_IMAGE_SIZE_RANGE_VECTOR;
131 uint32_t index = GetRangeIndex(size, rangeVector);
132 if (index >= stat_.imageSize.size()) {
133 return;
134 }
135 stat_.imageSize[index]++;
136 } else {
137 rangeVector = DOWNLOAD_VIDEO_SIZE_RANGE_VECTOR;
138 uint32_t index = GetRangeIndex(size, rangeVector);
139 if (index >= stat_.videoSize.size()) {
140 return;
141 }
142 stat_.videoSize[index]++;
143 }
144 }
145
UpdateDownloadStat(uint32_t mediaType,uint64_t size,uint64_t duration)146 void GalleryDownloadFileStat::UpdateDownloadStat(uint32_t mediaType, uint64_t size, uint64_t duration)
147 {
148 UpdateDownloadSizeStat(mediaType, size, duration);
149 UpdateDownloadSpeedStat(mediaType, size, duration);
150 }
151
VectorToString(std::vector<uint64_t> & vec)152 static std::string VectorToString(std::vector<uint64_t> &vec)
153 {
154 std::ostringstream oss;
155 for (size_t i = 0; i < vec.size(); ++i) {
156 oss << vec[i];
157 if (i <= vec.size() -1) {
158 oss << " ";
159 }
160 }
161 return oss.str();
162 }
163
StringToVector(std::string line)164 static std::vector<uint64_t> StringToVector(std::string line)
165 {
166 std::vector<uint64_t> vec;
167 std::istringstream iss(line);
168 uint64_t num;
169 while (iss >> num) {
170 vec.push_back(num);
171 }
172 return vec;
173 }
174
SumTwoVector(std::vector<uint64_t> & dataOne,std::vector<uint64_t> dataTwo)175 static inline void SumTwoVector(std::vector<uint64_t> &dataOne, std::vector<uint64_t> dataTwo)
176 {
177 if (dataOne.size() != dataTwo.size()) {
178 return;
179 }
180 for (size_t i = 0; i < dataOne.size(); i++) {
181 dataOne[i] += dataTwo[i];
182 }
183 return;
184 }
185
SumTwoDownloadFileStat(DownloadFileStatInfo dataOne,DownloadFileStatInfo dataTwo)186 static inline DownloadFileStatInfo SumTwoDownloadFileStat(DownloadFileStatInfo dataOne, DownloadFileStatInfo dataTwo)
187 {
188 SumTwoVector(dataOne.downloadFileError, dataTwo.downloadFileError);
189 SumTwoVector(dataOne.imageSize, dataTwo.imageSize);
190 SumTwoVector(dataOne.imageDownloadSpeed, dataTwo.imageDownloadSpeed);
191 SumTwoVector(dataOne.videoSize, dataTwo.videoSize);
192 SumTwoVector(dataOne.videoDownloadSpeed, dataTwo.videoDownloadSpeed);
193 return dataOne;
194 }
195
OutputToFile()196 void GalleryDownloadFileStat::OutputToFile()
197 {
198 DownloadFileStatInfo tmpInfo = ReadVecFromLocal();
199 stat_ = SumTwoDownloadFileStat(stat_, tmpInfo);
200
201 std::vector<std::string> lines;
202 /* Keep code order below */
203 lines.emplace_back(stat_.bundleName);
204 lines.emplace_back(VectorToString(stat_.downloadFileError));
205 lines.emplace_back(VectorToString(stat_.imageSize));
206 lines.emplace_back(VectorToString(stat_.imageDownloadSpeed));
207 lines.emplace_back(VectorToString(stat_.videoSize));
208 lines.emplace_back(VectorToString(stat_.videoDownloadSpeed));
209
210 std::ofstream localData(DOWNLOAD_FILE_STAT_LOCAL_PATH + DOWNLOAD_FILE_STAT_NAME, std::ios::trunc);
211 if (!localData.is_open()) {
212 LOGE("Open cloud data statistic local data fail %{public}d", errno);
213 return;
214 }
215 for (std::string line : lines) {
216 localData << line << std::endl;
217 }
218 localData.close();
219 ClearDownloadFileStat();
220 return;
221 }
222
ReadVecFromLocal()223 DownloadFileStatInfo GalleryDownloadFileStat::ReadVecFromLocal()
224 {
225 std::vector<uint64_t> vec;
226 DownloadFileStatInfo tmpStat;
227 std::ifstream localData(DOWNLOAD_FILE_STAT_LOCAL_PATH + DOWNLOAD_FILE_STAT_NAME);
228 if (localData) {
229 uint32_t rowCount = 0;
230 std::string line;
231 while (std::getline(localData, line)) {
232 if (rowCount != 0) {
233 vec = StringToVector(line);
234 }
235 if (rowCount == DOWNLOAD_FILE_ERROR) {
236 tmpStat.downloadFileError = vec;
237 }
238 if (rowCount == DOWNLOAD_IMAGE_SIZE) {
239 tmpStat.imageSize = vec;
240 }
241 if (rowCount == DOWNLOAD_IMAGE_SPEED) {
242 tmpStat.imageDownloadSpeed = vec;
243 }
244 if (rowCount == DOWNLOAD_VIDEO_SIZE) {
245 tmpStat.videoSize = vec;
246 }
247 if (rowCount == DOWNLOAD_VIDEO_SPEED) {
248 tmpStat.videoDownloadSpeed = vec;
249 }
250 rowCount += 1;
251 }
252 localData.close();
253 } else {
254 LOGE("Open cloud data statistic local data fail %{public}d", errno);
255 }
256 return tmpStat;
257 }
258
ClearDownloadFileStat()259 void GalleryDownloadFileStat::ClearDownloadFileStat()
260 {
261 std::fill(stat_.downloadFileError.begin(), stat_.downloadFileError.end(), 0);
262 std::fill(stat_.imageSize.begin(), stat_.imageSize.end(), 0);
263 std::fill(stat_.imageDownloadSpeed.begin(), stat_.imageDownloadSpeed.end(), 0);
264 std::fill(stat_.videoSize.begin(), stat_.videoSize.end(), 0);
265 std::fill(stat_.videoDownloadSpeed.begin(), stat_.videoDownloadSpeed.end(), 0);
266 }
267
Report()268 void GalleryDownloadFileStat::Report()
269 {
270 const std::string path = DOWNLOAD_FILE_STAT_LOCAL_PATH + DOWNLOAD_FILE_STAT_NAME;
271 if (access(path.c_str(), F_OK) == -1) {
272 LOGE("download file statistics data file not exists");
273 return;
274 }
275
276 /* read stat from dist */
277 stat_ = ReadVecFromLocal();
278
279 int32_t ret = CLOUD_SYNC_SYS_EVENT("CLOUD_SYNC_DOWNLOAD_FILE_STAT",
280 HiviewDFX::HiSysEvent::EventType::STATISTIC,
281 "bundle_name", stat_.bundleName,
282 "download_file", stat_.downloadFileError,
283 "image_size", stat_.imageSize,
284 "image_download_speed", stat_.imageDownloadSpeed,
285 "video_size", stat_.videoSize,
286 "video_download_speed", stat_.videoDownloadSpeed);
287 if (ret != E_OK) {
288 LOGE("report CLOUD_SYNC_DOWNLOAD_FILE_STAT error %{public}d", ret);
289 }
290 ret = unlink(path.c_str());
291 if (ret != 0) {
292 LOGE("fail to delete local statistic data, errno %{public}d", errno);
293 }
294 }
295
GetInstance()296 GalleryDownloadFileStat &GalleryDownloadFileStat::GetInstance()
297 {
298 static GalleryDownloadFileStat downloadStat_;
299 return downloadStat_;
300 }
301 } // CloudFile
302 } // FileManagement
303 } // OHOS