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