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_BUNDLE_NAME = 0,
45 DOWNLOAD_FILE_ERROR,
46 DOWNLOAD_IMAGE_SIZE,
47 DOWNLOAD_IMAGE_SPEED,
48 DOWNLOAD_VIDEO_SIZE,
49 DOWNLOAD_VIDEO_SPEED,
50 };
51
CreateDataStatisticFolder()52 static int32_t CreateDataStatisticFolder()
53 {
54 std::string path = DOWNLOAD_FILE_STAT_LOCAL_PATH;
55 if (access(path.c_str(), F_OK) == 0) {
56 LOGI("cloud data statistic folder already exists");
57 return E_OK;
58 }
59 int32_t ret = mkdir(path.c_str(), DIR_MODE);
60 if (ret != E_OK) {
61 LOGE("Create cloud data statistic folder fail errno = %{public}d", errno);
62 return E_PATH;
63 }
64 return E_OK;
65 }
66
CreateDownloadFileStatData()67 static int32_t CreateDownloadFileStatData()
68 {
69 const std::string path = DOWNLOAD_FILE_STAT_LOCAL_PATH + DOWNLOAD_FILE_STAT_NAME;
70 if (access(path.c_str(), F_OK) == 0) {
71 LOGI("download file statistics data file already exists");
72 return E_OK;
73 }
74 std::FILE *file = fopen(path.c_str(), "w");
75 if (file == nullptr) {
76 LOGE("create file downloadstatistic report fail, ret = %{public}d", errno);
77 return errno;
78 }
79 if (fclose(file)) {
80 LOGE("close file downloadstatistic report fail, ret = %{public}d", errno);
81 }
82 return E_OK;
83 }
84
GalleryDownloadFileStat()85 GalleryDownloadFileStat::GalleryDownloadFileStat()
86 {
87 auto ret = CreateDataStatisticFolder();
88 if (ret !=E_OK) {
89 LOGE("create data statistic failed with error %{public}d", ret);
90 return;
91 }
92 ret = CreateDownloadFileStatData();
93 if (ret != E_OK) {
94 LOGE("create download file stat failed with error %{public}d", ret);
95 return;
96 }
97 }
98
GetRangeIndex(uint64_t value,const std::vector<uint64_t> rangeVector)99 static uint32_t GetRangeIndex(uint64_t value, const std::vector<uint64_t> rangeVector)
100 {
101 uint32_t index = 0;
102 for (; index < rangeVector.size(); index++) {
103 if (value <= rangeVector[index] * DOWNLOAD_FILE_BYTE_SIZE) {
104 break;
105 }
106 }
107 return index;
108 }
109
UpdateDownloadSpeedStat(uint32_t mediaType,uint64_t size,uint64_t duration)110 void GalleryDownloadFileStat::UpdateDownloadSpeedStat(uint32_t mediaType, uint64_t size, uint64_t duration)
111 {
112 double sizeMb = static_cast<double>(size) / DOWNLOAD_FILE_BYTE_SIZE;
113 double time = static_cast<double>(duration) / DOWNLOAD_FILE_BYTE_SIZE;
114
115 double precision = 1e-10;
116 uint32_t indexSpeed = 15;
117 if (abs(time) > precision) {
118 double speed = sizeMb / time;
119 indexSpeed = static_cast<uint32_t>(floor(speed));
120 }
121 if (mediaType == TYPE_DOWNLOAD_FILE_IMAGE && indexSpeed < stat_.imageDownloadSpeed.size()) {
122 stat_.imageDownloadSpeed[indexSpeed]++;
123 }
124 if (mediaType == TYPE_DOWNLOAD_FILE_VIDEO && indexSpeed < stat_.videoDownloadSpeed.size()) {
125 stat_.videoDownloadSpeed[indexSpeed]++;
126 }
127 }
128
UpdateDownloadSizeStat(uint32_t mediaType,uint64_t size,uint64_t duration)129 void GalleryDownloadFileStat::UpdateDownloadSizeStat(uint32_t mediaType, uint64_t size, uint64_t duration)
130 {
131 std::vector<uint64_t> rangeVector;
132 if (mediaType == TYPE_DOWNLOAD_FILE_IMAGE) {
133 rangeVector = DOWNLOAD_IMAGE_SIZE_RANGE_VECTOR;
134 uint32_t index = GetRangeIndex(size, rangeVector);
135 if (index >= stat_.imageSize.size()) {
136 return;
137 }
138 stat_.imageSize[index]++;
139 } else {
140 rangeVector = DOWNLOAD_VIDEO_SIZE_RANGE_VECTOR;
141 uint32_t index = GetRangeIndex(size, rangeVector);
142 if (index >= stat_.videoSize.size()) {
143 return;
144 }
145 stat_.videoSize[index]++;
146 }
147 }
148
UpdateDownloadStat(uint32_t mediaType,uint64_t size,uint64_t duration)149 void GalleryDownloadFileStat::UpdateDownloadStat(uint32_t mediaType, uint64_t size, uint64_t duration)
150 {
151 UpdateDownloadSizeStat(mediaType, size, duration);
152 UpdateDownloadSpeedStat(mediaType, size, duration);
153 }
154
UpdateDownloadBundleName(const std::string & bundleName)155 void GalleryDownloadFileStat::UpdateDownloadBundleName(const std::string &bundleName)
156 {
157 stat_.bundleName = bundleName;
158 }
159
VectorToString(const std::vector<uint64_t> & vec)160 static std::string VectorToString(const std::vector<uint64_t> &vec)
161 {
162 std::ostringstream oss;
163 for (size_t i = 0; i < vec.size(); ++i) {
164 oss << vec[i];
165 if (i <= vec.size() -1) {
166 oss << " ";
167 }
168 }
169 return oss.str();
170 }
171
StringToVector(std::string line)172 static std::vector<uint64_t> StringToVector(std::string line)
173 {
174 std::vector<uint64_t> vec;
175 std::istringstream iss(line);
176 uint64_t num;
177 while (iss >> num) {
178 vec.push_back(num);
179 }
180 return vec;
181 }
182
SumTwoVector(std::vector<uint64_t> & dataOne,std::vector<uint64_t> dataTwo)183 static inline void SumTwoVector(std::vector<uint64_t> &dataOne, std::vector<uint64_t> dataTwo)
184 {
185 if (dataOne.size() != dataTwo.size()) {
186 return;
187 }
188 for (size_t i = 0; i < dataOne.size(); i++) {
189 dataOne[i] += dataTwo[i];
190 }
191 return;
192 }
193
SumTwoDownloadFileStat(DownloadFileStatInfo dataOne,DownloadFileStatInfo dataTwo)194 static inline DownloadFileStatInfo SumTwoDownloadFileStat(DownloadFileStatInfo dataOne, DownloadFileStatInfo dataTwo)
195 {
196 SumTwoVector(dataOne.downloadFileError, dataTwo.downloadFileError);
197 SumTwoVector(dataOne.imageSize, dataTwo.imageSize);
198 SumTwoVector(dataOne.imageDownloadSpeed, dataTwo.imageDownloadSpeed);
199 SumTwoVector(dataOne.videoSize, dataTwo.videoSize);
200 SumTwoVector(dataOne.videoDownloadSpeed, dataTwo.videoDownloadSpeed);
201 if (dataOne.bundleName.empty()) {
202 dataOne.bundleName = dataTwo.bundleName;
203 }
204 return dataOne;
205 }
206
HandleBundleName(const DownloadFileStatInfo & info)207 void GalleryDownloadFileStat::HandleBundleName(const DownloadFileStatInfo &info)
208 {
209 if (!info.bundleName.empty() && info.bundleName != stat_.bundleName &&
210 !stat_.bundleName.empty()) {
211 auto ret = ReportDownloadFileStat(info);
212 if (ret != E_OK) {
213 LOGE("report CLOUD_SYNC_DOWNLOAD_FILE_STAT error %{public}d", ret);
214 }
215 } else {
216 stat_ = SumTwoDownloadFileStat(stat_, info);
217 }
218 }
219
OutputToFile()220 void GalleryDownloadFileStat::OutputToFile()
221 {
222 DownloadFileStatInfo tmpInfo = ReadVecFromLocal();
223 HandleBundleName(tmpInfo);
224
225 std::vector<std::string> lines;
226 /* Keep code order below */
227 lines.emplace_back(stat_.bundleName);
228 lines.emplace_back(VectorToString(stat_.downloadFileError));
229 lines.emplace_back(VectorToString(stat_.imageSize));
230 lines.emplace_back(VectorToString(stat_.imageDownloadSpeed));
231 lines.emplace_back(VectorToString(stat_.videoSize));
232 lines.emplace_back(VectorToString(stat_.videoDownloadSpeed));
233
234 std::ofstream localData(DOWNLOAD_FILE_STAT_LOCAL_PATH + DOWNLOAD_FILE_STAT_NAME, std::ios::trunc);
235 if (!localData.is_open()) {
236 LOGE("Open cloud data statistic local data fail %{public}d", errno);
237 return;
238 }
239 for (std::string line : lines) {
240 localData << line << std::endl;
241 }
242 localData.close();
243 ClearDownloadFileStat();
244 return;
245 }
246
ReadVecFromLocal()247 DownloadFileStatInfo GalleryDownloadFileStat::ReadVecFromLocal()
248 {
249 std::vector<uint64_t> vec;
250 DownloadFileStatInfo tmpStat;
251 std::ifstream localData(DOWNLOAD_FILE_STAT_LOCAL_PATH + DOWNLOAD_FILE_STAT_NAME);
252 if (localData) {
253 uint32_t rowCount = 0;
254 std::string line;
255 while (std::getline(localData, line)) {
256 if (rowCount != 0) {
257 vec = StringToVector(line);
258 }
259 if (rowCount == DOWNLOAD_BUNDLE_NAME) {
260 tmpStat.bundleName = line;
261 }
262 if (rowCount == DOWNLOAD_FILE_ERROR) {
263 tmpStat.downloadFileError = vec;
264 }
265 if (rowCount == DOWNLOAD_IMAGE_SIZE) {
266 tmpStat.imageSize = vec;
267 }
268 if (rowCount == DOWNLOAD_IMAGE_SPEED) {
269 tmpStat.imageDownloadSpeed = vec;
270 }
271 if (rowCount == DOWNLOAD_VIDEO_SIZE) {
272 tmpStat.videoSize = vec;
273 }
274 if (rowCount == DOWNLOAD_VIDEO_SPEED) {
275 tmpStat.videoDownloadSpeed = vec;
276 }
277 rowCount += 1;
278 }
279 localData.close();
280 } else {
281 LOGE("Open cloud data statistic local data fail %{public}d", errno);
282 }
283 return tmpStat;
284 }
285
ClearDownloadFileStat()286 void GalleryDownloadFileStat::ClearDownloadFileStat()
287 {
288 std::fill(stat_.downloadFileError.begin(), stat_.downloadFileError.end(), 0);
289 std::fill(stat_.imageSize.begin(), stat_.imageSize.end(), 0);
290 std::fill(stat_.imageDownloadSpeed.begin(), stat_.imageDownloadSpeed.end(), 0);
291 std::fill(stat_.videoSize.begin(), stat_.videoSize.end(), 0);
292 std::fill(stat_.videoDownloadSpeed.begin(), stat_.videoDownloadSpeed.end(), 0);
293 }
294
ReportDownloadFileStat(const DownloadFileStatInfo & info)295 int32_t GalleryDownloadFileStat::ReportDownloadFileStat(const DownloadFileStatInfo &info)
296 {
297 int32_t ret = CLOUD_SYNC_SYS_EVENT("CLOUD_SYNC_DOWNLOAD_FILE_STAT",
298 HiviewDFX::HiSysEvent::EventType::STATISTIC,
299 "bundle_name", info.bundleName,
300 "download_file", info.downloadFileError,
301 "image_size", info.imageSize,
302 "image_download_speed", info.imageDownloadSpeed,
303 "video_size", info.videoSize,
304 "video_download_speed", info.videoDownloadSpeed);
305 return ret;
306 }
307
Report()308 void GalleryDownloadFileStat::Report()
309 {
310 const std::string path = DOWNLOAD_FILE_STAT_LOCAL_PATH + DOWNLOAD_FILE_STAT_NAME;
311 if (access(path.c_str(), F_OK) == -1) {
312 LOGE("download file statistics data file not exists");
313 return;
314 }
315
316 /* read stat from dist */
317 stat_ = ReadVecFromLocal();
318
319 int32_t ret = ReportDownloadFileStat(stat_);
320 if (ret != E_OK) {
321 LOGE("report CLOUD_SYNC_DOWNLOAD_FILE_STAT error %{public}d", ret);
322 }
323 ret = unlink(path.c_str());
324 if (ret != 0) {
325 LOGE("fail to delete local statistic data, errno %{public}d", errno);
326 }
327 }
328
GetInstance()329 GalleryDownloadFileStat &GalleryDownloadFileStat::GetInstance()
330 {
331 static GalleryDownloadFileStat downloadStat_;
332 return downloadStat_;
333 }
334 } // CloudFile
335 } // FileManagement
336 } // OHOS