1 /*
2  * Copyright (c) 2023 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 "io_collector_impl.h"
17 
18 #include <regex>
19 #include <unordered_map>
20 
21 #include <fcntl.h>
22 #include <securec.h>
23 #include <string_ex.h>
24 #include <unistd.h>
25 
26 #include "common_util.h"
27 #include "common_utils.h"
28 #include "file_util.h"
29 #include "io_calculator.h"
30 #include "io_decorator.h"
31 #include "hiview_logger.h"
32 #include "process_status.h"
33 #include "string_util.h"
34 #include "time_util.h"
35 
36 using namespace OHOS::HiviewDFX::UCollect;
37 
38 namespace OHOS {
39 namespace HiviewDFX {
40 namespace UCollectUtil {
41 namespace {
42 DEFINE_LOG_TAG("UCollectUtil-IoCollector");
43 constexpr int DISK_STATS_SIZE = 12;
44 constexpr int DISK_STATS_PERIOD = 2;
45 constexpr int PROC_IO_STATS_PERIOD = 2;
46 constexpr int EMMC_INFO_SIZE_RATIO = 2 * 1024 * 1024;
47 constexpr int MAX_FILE_NUM = 10;
48 const std::string MMC = "mmc";
49 const std::string EXPORT_FILE_SUFFIX = ".txt";
50 const std::string EXPORT_FILE_REGEX = "[0-9]{14}(.*)";
51 const std::string UNDERLINE = "_";
52 const std::string RAW_DISK_STATS_FILE_PREFIX = "proc_diskstats_";
53 const std::string DISK_STATS_FILE_PREFIX = "proc_diskstats_statistics_";
54 const std::string EMMC_INFO_FILE_PREFIX = "emmc_info_";
55 const std::string PROC_IO_STATS_FILE_PREFIX = "proc_io_stats_";
56 const std::string SYS_IO_STATS_FILE_PREFIX = "sys_io_stats_";
57 const std::string PROC_DISKSTATS = "/proc/diskstats";
58 const std::string COLLECTION_IO_PATH = "/data/log/hiview/unified_collection/io/";
59 }
60 
Create()61 std::shared_ptr<IoCollector> IoCollector::Create()
62 {
63     static std::shared_ptr<IoCollector> instance_ = std::make_shared<IoDecorator>(std::make_shared<IoCollectorImpl>());
64     return instance_;
65 }
66 
IoCollectorImpl()67 IoCollectorImpl::IoCollectorImpl()
68 {
69     HIVIEW_LOGI("init collect data.");
70     InitDiskData();
71     InitProcIoData();
72 }
73 
InitDiskData()74 void IoCollectorImpl::InitDiskData()
75 {
76     std::unique_lock<std::mutex> lockDisk(collectDiskMutex_);
77     preCollectDiskTime_ = TimeUtil::GetMilliseconds();
78     CalculateDiskStats(0, true);
79 }
80 
InitProcIoData()81 void IoCollectorImpl::InitProcIoData()
82 {
83     std::unique_lock<std::mutex> lockProcIo(collectProcIoMutex_);
84     currCollectProcIoTime_ = TimeUtil::GetMilliseconds();
85     preCollectProcIoTime_ = currCollectProcIoTime_;
86     CalculateAllProcIoStats(0, true);
87 }
88 
CollectProcessIo(int32_t pid)89 CollectResult<ProcessIo> IoCollectorImpl::CollectProcessIo(int32_t pid)
90 {
91     CollectResult<ProcessIo> result;
92     std::string filename = PROC + std::to_string(pid) + IO;
93     std::string content;
94     FileUtil::LoadStringFromFile(filename, content);
95     std::vector<std::string> vec;
96     OHOS::SplitStr(content, "\n", vec);
97     ProcessIo& processIO = result.data;
98     processIO.pid = pid;
99     processIO.name = CommonUtils::GetProcNameByPid(pid);
100     std::string type;
101     int32_t value = 0;
102     for (const std::string &str : vec) {
103         if (CommonUtil::ParseTypeAndValue(str, type, value)) {
104             if (type == "rchar") {
105                 processIO.rchar = value;
106             } else if (type == "wchar") {
107                 processIO.wchar = value;
108             } else if (type == "syscr") {
109                 processIO.syscr = value;
110             } else if (type == "syscw") {
111                 processIO.syscw = value;
112             } else if (type == "read_bytes") {
113                 processIO.readBytes = value;
114             } else if (type == "cancelled_write_bytes") {
115                 processIO.cancelledWriteBytes = value;
116             } else if (type == "write_bytes") {
117                 processIO.writeBytes = value;
118             }
119         }
120     }
121     result.retCode = UcError::SUCCESS;
122     return result;
123 }
124 
GetDirRegexFiles(const std::string & path,const std::string & pattern,std::vector<std::string> & files)125 static void GetDirRegexFiles(const std::string& path, const std::string& pattern,
126     std::vector<std::string>& files)
127 {
128     DIR* dir = opendir(path.c_str());
129     if (dir == nullptr) {
130         HIVIEW_LOGE("failed to open dir=%{public}s", path.c_str());
131         return;
132     }
133     std::regex reg = std::regex(pattern);
134     while (true) {
135         struct dirent* ptr = readdir(dir);
136         if (ptr == nullptr) {
137             break;
138         }
139         if (ptr->d_type == DT_REG) {
140             if (regex_match(ptr->d_name, reg)) {
141                 files.push_back(FileUtil::IncludeTrailingPathDelimiter(path) + std::string(ptr->d_name));
142             }
143         }
144     }
145     closedir(dir);
146     std::sort(files.begin(), files.end());
147 }
148 
GetFileNameNum(const std::string & fileName)149 static int GetFileNameNum(const std::string& fileName)
150 {
151     int ret = 0;
152     auto startPos = fileName.find(UNDERLINE);
153     if (startPos == std::string::npos) {
154         return ret;
155     }
156     auto endPos = fileName.find(EXPORT_FILE_SUFFIX);
157     if (endPos == std::string::npos) {
158         return ret;
159     }
160     if (endPos <= startPos + 1) {
161         return ret;
162     }
163     return StringUtil::StrToInt(fileName.substr(startPos + 1, endPos - startPos - 1));
164 }
165 
CreateExportFileName(const std::string & filePrefix)166 std::string IoCollectorImpl::CreateExportFileName(const std::string& filePrefix)
167 {
168     std::unique_lock<std::mutex> lock(exportFileMutex_);
169     if (!FileUtil::IsDirectory(COLLECTION_IO_PATH) && !FileUtil::ForceCreateDirectory(COLLECTION_IO_PATH)) {
170         HIVIEW_LOGE("failed to create dir=%{public}s", COLLECTION_IO_PATH.c_str());
171         return "";
172     }
173 
174     std::vector<std::string> files;
175     GetDirRegexFiles(COLLECTION_IO_PATH, filePrefix + EXPORT_FILE_REGEX, files);
176     if (files.size() >= MAX_FILE_NUM) {
177         for (size_t index = 0; index <= files.size() - MAX_FILE_NUM; ++index) {
178             HIVIEW_LOGI("remove file=%{public}s", files[index].c_str());
179             (void)FileUtil::RemoveFile(files[index]);
180         }
181     }
182 
183     uint64_t fileTime = TimeUtil::GetMilliseconds() / TimeUtil::SEC_TO_MILLISEC;
184     std::string timeFormat = TimeUtil::TimestampFormatToDate(fileTime, "%Y%m%d%H%M%S");
185     std::string fileName;
186     fileName.append(COLLECTION_IO_PATH).append(filePrefix).append(timeFormat);
187     if (!files.empty()) {
188         auto startPos = files.back().find(timeFormat);
189         if (startPos != std::string::npos) {
190             int fileNameNum = GetFileNameNum(files.back().substr(startPos)); // yyyymmddHHMMSS_1.txt
191             fileName.append(UNDERLINE).append(std::to_string(++fileNameNum));
192         }
193     }
194     fileName.append(EXPORT_FILE_SUFFIX);
195     (void)FileUtil::CreateFile(fileName);
196     HIVIEW_LOGI("create file=%{public}s", fileName.c_str());
197     return fileName;
198 }
199 
CollectRawDiskStats()200 CollectResult<std::string> IoCollectorImpl::CollectRawDiskStats()
201 {
202     CollectResult<std::string> result;
203     result.retCode = UcError::UNSUPPORT;
204 
205     std::string fileName = CreateExportFileName(RAW_DISK_STATS_FILE_PREFIX);
206     if (fileName.empty()) {
207         return result;
208     }
209     int ret = FileUtil::CopyFile(PROC_DISKSTATS, fileName);
210     if (ret != 0) {
211         HIVIEW_LOGE("copy /proc/diskstats to file=%{public}s failed.", fileName.c_str());
212         return result;
213     }
214 
215     result.data = fileName;
216     result.retCode = UcError::SUCCESS;
217     return result;
218 }
219 
CollectDiskStats(DiskStatsFilter filter,bool isUpdate)220 CollectResult<std::vector<DiskStats>> IoCollectorImpl::CollectDiskStats(DiskStatsFilter filter, bool isUpdate)
221 {
222     CollectResult<std::vector<DiskStats>> result;
223     GetDiskStats(filter, isUpdate, result.data);
224     HIVIEW_LOGI("collect disk stats size=%{public}zu, isUpdate=%{public}d", result.data.size(), isUpdate);
225     result.retCode = UcError::SUCCESS;
226     return result;
227 }
228 
GetDiskStats(DiskStatsFilter filter,bool isUpdate,std::vector<DiskStats> & diskStats)229 void IoCollectorImpl::GetDiskStats(DiskStatsFilter filter, bool isUpdate, std::vector<DiskStats>& diskStats)
230 {
231     std::unique_lock<std::mutex> lock(collectDiskMutex_);
232     uint64_t currCollectDiskTime = TimeUtil::GetMilliseconds();
233     uint64_t period = (currCollectDiskTime > preCollectDiskTime_) ?
234         ((currCollectDiskTime - preCollectDiskTime_) / TimeUtil::SEC_TO_MILLISEC) : 0;
235     if (period > DISK_STATS_PERIOD) {
236         if (isUpdate) {
237             preCollectDiskTime_ = currCollectDiskTime;
238         }
239         CalculateDiskStats(period, isUpdate);
240     }
241 
242     for (auto it = diskStatsMap_.begin(); it != diskStatsMap_.end();) {
243         if (it->second.collectTime == preCollectDiskTime_) {
244             if (!it->second.stats.deviceName.empty() && !filter(it->second.stats)) {
245                 diskStats.push_back(it->second.stats);
246             }
247             ++it;
248         } else {
249             it = diskStatsMap_.erase(it);
250         }
251     }
252     return;
253 }
254 
CalculateDiskStats(uint64_t period,bool isUpdate)255 void IoCollectorImpl::CalculateDiskStats(uint64_t period, bool isUpdate)
256 {
257     std::string content;
258     if (!FileUtil::LoadStringFromFile(PROC_DISKSTATS, content) || content.empty()) {
259         HIVIEW_LOGE("load file=%{public}s failed.", PROC_DISKSTATS.c_str());
260         return;
261     }
262     std::vector<std::string> contents;
263     OHOS::SplitStr(content, "\n", contents);
264     for (const std::string& line : contents) {
265         std::vector<std::string> items;
266         StringUtil::SplitStr(line, " ", items);
267         if (items.size() < DISK_STATS_SIZE) {
268             HIVIEW_LOGE("items num=%{public}zu.", items.size());
269             continue;
270         }
271         std::string deviceName = items[2]; // 2 : index of device name
272         if (deviceName.empty()) {
273             HIVIEW_LOGE("device name empty.");
274             continue;
275         }
276         DiskData currData;
277         currData.operRead = StringUtil::StringToUl(items[4]);    // 4 : index of reads merged
278         currData.sectorRead = StringUtil::StringToUl(items[5]);  // 5 : index of sectors read
279         currData.readTime = StringUtil::StringToUl(items[6]);    // 6 : index of time spent reading (ms)
280         currData.operWrite = StringUtil::StringToUl(items[8]);   // 8 : index of writes merged
281         currData.sectorWrite = StringUtil::StringToUl(items[9]); // 9 : index of sectors written
282         currData.writeTime = StringUtil::StringToUl(items[10]);  // 10 : index of time spent reading (ms)
283         currData.ioWait = StringUtil::StringToUl(items[11]);     // 11 : index of I/Os currently in progress
284 
285         CalculateDeviceDiskStats(currData, deviceName, period);
286         if (isUpdate) {
287             diskStatsMap_[deviceName].collectTime = preCollectDiskTime_;
288             diskStatsMap_[deviceName].preData = currData;
289         }
290     }
291 }
292 
CalculateDeviceDiskStats(const DiskData & currData,const std::string & deviceName,uint64_t period)293 void IoCollectorImpl::CalculateDeviceDiskStats(const DiskData& currData, const std::string& deviceName, uint64_t period)
294 {
295     if (diskStatsMap_.find(deviceName) == diskStatsMap_.end()) {
296         return;
297     }
298 
299     DiskStatsDevice& device = diskStatsMap_[deviceName];
300     DiskData& preData = device.preData;
301     DiskStats& stats = device.stats;
302     stats.deviceName = deviceName;
303     if (period != 0) {
304         stats.sectorReadRate = IoCalculator::PercentValue(preData.sectorRead, currData.sectorRead, period);
305         stats.sectorWriteRate = IoCalculator::PercentValue(preData.sectorWrite, currData.sectorWrite, period);
306         stats.operReadRate = IoCalculator::PercentValue(preData.operRead, currData.operRead, period);
307         stats.operWriteRate = IoCalculator::PercentValue(preData.operWrite, currData.operWrite, period);
308         stats.readTimeRate = IoCalculator::PercentValue(preData.readTime, currData.readTime, period);
309         stats.writeTimeRate = IoCalculator::PercentValue(preData.writeTime, currData.writeTime, period);
310         stats.ioWait = currData.ioWait;
311     }
312 }
313 
ExportDiskStats(DiskStatsFilter filter)314 CollectResult<std::string> IoCollectorImpl::ExportDiskStats(DiskStatsFilter filter)
315 {
316     CollectResult<std::string> result;
317     result.retCode = UcError::UNSUPPORT;
318 
319     std::vector<DiskStats> diskStats;
320     GetDiskStats(filter, false, diskStats);
321     std::sort(diskStats.begin(), diskStats.end(), [](const DiskStats &leftStats, const DiskStats &rightStats) {
322         return leftStats.deviceName < rightStats.deviceName;
323     });
324 
325     std::string fileName = CreateExportFileName(DISK_STATS_FILE_PREFIX);
326     if (fileName.empty()) {
327         return result;
328     }
329     int fd = open(fileName.c_str(), O_WRONLY);
330     if (fd < 0) {
331         HIVIEW_LOGE("create fileName=%{public}s failed.", fileName.c_str());
332         return result;
333     }
334     dprintf(fd, "%-13s\t%20s\t%20s\t%20s\t%20s\t%12s\t%12s\t%12s\n", "device", "sectorReadRate/s", "sectorWriteRate/s",
335         "operReadRate/s", "operWriteRate/s", "readTime", "writeTime", "ioWait");
336     for (auto &stats : diskStats) {
337         dprintf(fd, "%-13s\t%12.2f\t%12.2f\t%12.2f\t%12.2f\t%12.4f\t%12.4f\t%12" PRIu64 "\n",
338             stats.deviceName.c_str(), stats.sectorReadRate, stats.sectorWriteRate, stats.operReadRate,
339             stats.operWriteRate, stats.readTimeRate, stats.writeTimeRate, stats.ioWait);
340     }
341     close(fd);
342 
343     result.retCode = UcError::SUCCESS;
344     result.data = fileName;
345     return result;
346 }
347 
ReadEMMCInfo(const std::string & path,std::vector<EMMCInfo> & mmcInfos)348 void IoCollectorImpl::ReadEMMCInfo(const std::string& path, std::vector<EMMCInfo>& mmcInfos)
349 {
350     EMMCInfo mmcInfo;
351     mmcInfo.type = FileUtil::GetFirstLine(path + "/type");
352     if (mmcInfo.type.empty()) {
353         HIVIEW_LOGE("load file=%{public}s/type failed.", path.c_str());
354         return;
355     }
356     mmcInfo.csd = FileUtil::GetFirstLine(path + "/csd");
357     mmcInfo.name = FileUtil::GetFirstLine(path + "/name");
358     if (mmcInfo.name.empty()) {
359         HIVIEW_LOGE("load file=%{public}s/name failed.", path.c_str());
360         return;
361     }
362     mmcInfo.size = IoCalculator::GetEMMCSize(path);
363     if (mmcInfo.size == -1) {
364         return;
365     }
366     mmcInfo.manfid = IoCalculator::GetEMMCManfid(path);
367     if (mmcInfo.manfid.empty()) {
368         return;
369     }
370     mmcInfos.emplace_back(mmcInfo);
371 }
372 
GetEMMCPath(const std::string & path)373 std::string IoCollectorImpl::GetEMMCPath(const std::string& path)
374 {
375     std::string mmcPath;
376     DIR *dir = opendir(path.c_str());
377     if (dir == nullptr) {
378         HIVIEW_LOGE("open dir=%{public}s failed.", path.c_str());
379         return mmcPath;
380     }
381     struct dirent *de = nullptr;
382     while ((de = readdir(dir)) != nullptr) {
383         if ((de->d_type == DT_LNK) || (de->d_type == DT_DIR)) {
384             std::string fileName = std::string(de->d_name);
385             if (fileName.length() <= MMC.length()) {
386                 continue;
387             }
388             if (fileName.substr(0, MMC.length()) != MMC) {
389                 continue;
390             }
391             if (fileName.find(":") == std::string::npos) {
392                 continue;
393             }
394             // mmc0:0001
395             mmcPath = path + "/" + fileName + "/cid";
396             if (FileUtil::FileExists(mmcPath)) {
397                 mmcPath = path + "/" + fileName;
398             } else {
399                 mmcPath = "";
400             }
401             break;
402         }
403     }
404     closedir(dir);
405     return mmcPath;
406 }
407 
CalculateEMMCInfo(std::vector<EMMCInfo> & mmcInfos)408 void IoCollectorImpl::CalculateEMMCInfo(std::vector<EMMCInfo>& mmcInfos)
409 {
410     const std::string procBootDevice = "/proc/bootdevice";
411     ReadEMMCInfo(procBootDevice, mmcInfos);
412 
413     const std::string mmcHostPath = "/sys/class/mmc_host";
414     DIR *dir = opendir(mmcHostPath.c_str());
415     if (dir == nullptr) {
416         HIVIEW_LOGE("open dir=%{public}s failed.", mmcHostPath.c_str());
417         return;
418     }
419     struct dirent *de = nullptr;
420     while ((de = readdir(dir)) != nullptr) {
421         if ((de->d_type == DT_LNK) || (de->d_type == DT_DIR)) {
422             if ((strlen(de->d_name) <= MMC.length()) || (de->d_name[0] != 'm')) {
423                 continue;
424             }
425             // mmc0
426             std::string mmcPath = mmcHostPath + "/" + std::string(de->d_name);
427             mmcPath = GetEMMCPath(mmcPath);
428             if (!mmcPath.empty()) {
429                 ReadEMMCInfo(mmcPath, mmcInfos);
430             }
431         }
432     }
433     closedir(dir);
434 }
435 
CollectEMMCInfo()436 CollectResult<std::vector<EMMCInfo>> IoCollectorImpl::CollectEMMCInfo()
437 {
438     CollectResult<std::vector<EMMCInfo>> result;
439     CalculateEMMCInfo(result.data);
440     HIVIEW_LOGI("collect emmc info size=%{public}zu", result.data.size());
441     result.retCode = UcError::SUCCESS;
442     return result;
443 }
444 
ExportEMMCInfo()445 CollectResult<std::string> IoCollectorImpl::ExportEMMCInfo()
446 {
447     CollectResult<std::string> result;
448     result.retCode = UcError::UNSUPPORT;
449 
450     std::vector<EMMCInfo> mmcInfos;
451     CalculateEMMCInfo(mmcInfos);
452     std::sort(mmcInfos.begin(), mmcInfos.end(), [](const EMMCInfo &leftInfo, const EMMCInfo &rightInfo) {
453         return leftInfo.name < rightInfo.name;
454     });
455 
456     std::string fileName = CreateExportFileName(EMMC_INFO_FILE_PREFIX);
457     if (fileName.empty()) {
458         return result;
459     }
460     int fd = open(fileName.c_str(), O_WRONLY);
461     if (fd < 0) {
462         HIVIEW_LOGE("open file=%{public}s failed.", fileName.c_str());
463         return result;
464     }
465     dprintf(fd, "%-15s\t%15s\t%15s\t%15s\t%15s\n", "name", "manfid", "csd", "type", "capacity(GB)");
466     for (auto &mmcInfo : mmcInfos) {
467         dprintf(fd, "%-15s\t%-12s\t%-35s\t%-12s\t%12.2f\n", mmcInfo.name.c_str(), mmcInfo.manfid.c_str(),
468             mmcInfo.csd.c_str(), mmcInfo.type.c_str(), static_cast<double>(mmcInfo.size) / EMMC_INFO_SIZE_RATIO);
469     }
470     close(fd);
471 
472     result.retCode = UcError::SUCCESS;
473     result.data = fileName;
474     return result;
475 }
476 
GetProcIoStats(std::vector<ProcessIoStats> & allProcIoStats,bool isUpdate)477 void IoCollectorImpl::GetProcIoStats(std::vector<ProcessIoStats>& allProcIoStats, bool isUpdate)
478 {
479     std::unique_lock<std::mutex> lock(collectProcIoMutex_);
480     currCollectProcIoTime_ = TimeUtil::GetMilliseconds();
481     uint64_t period = (currCollectProcIoTime_ > preCollectProcIoTime_) ?
482         ((currCollectProcIoTime_ - preCollectProcIoTime_) / TimeUtil::SEC_TO_MILLISEC) : 0;
483     if (period > PROC_IO_STATS_PERIOD) {
484         CalculateAllProcIoStats(period, isUpdate);
485         if (isUpdate) {
486             preCollectProcIoTime_ = currCollectProcIoTime_;
487         }
488     }
489 
490     for (auto it = procIoStatsMap_.begin(); it != procIoStatsMap_.end();) {
491         if (it->second.collectTime == preCollectProcIoTime_) {
492             if (it->second.stats.pid != 0 && !ProcIoStatsFilter(it->second.stats)) {
493                 allProcIoStats.push_back(it->second.stats);
494             }
495             ++it;
496         } else {
497             it = procIoStatsMap_.erase(it);
498         }
499     }
500 }
501 
CalculateAllProcIoStats(uint64_t period,bool isUpdate)502 void IoCollectorImpl::CalculateAllProcIoStats(uint64_t period, bool isUpdate)
503 {
504     DIR *dir = opendir(PROC.c_str());
505     if (dir == nullptr) {
506         HIVIEW_LOGE("open dir=%{public}s failed.", PROC.c_str());
507         return;
508     }
509 
510     struct dirent *de = nullptr;
511     while ((de = readdir(dir)) != nullptr) {
512         if (de->d_type != DT_DIR) {
513             continue;
514         }
515         int32_t pid = StringUtil::StrToInt(std::string(de->d_name));
516         if (pid <= 0) {
517             continue;
518         }
519         auto collectProcIoResult = CollectProcessIo(pid);
520         if (collectProcIoResult.retCode == UcError::SUCCESS) {
521             CalculateProcIoStats(collectProcIoResult.data, pid, period);
522             if (isUpdate) {
523                 procIoStatsMap_[pid].collectTime = currCollectProcIoTime_;
524                 procIoStatsMap_[pid].preData = collectProcIoResult.data;
525             }
526         }
527     }
528     closedir(dir);
529 }
530 
ProcIoStatsFilter(const ProcessIoStats & stats)531 bool IoCollectorImpl::ProcIoStatsFilter(const ProcessIoStats& stats)
532 {
533     return (stats.rcharRate == 0 && stats.wcharRate == 0 && stats.syscrRate == 0 && stats.syscwRate == 0 &&
534         stats.readBytesRate == 0 && stats.writeBytesRate == 0);
535 }
536 
GetProcStateInCollectionPeriod(int32_t pid)537 int32_t IoCollectorImpl::GetProcStateInCollectionPeriod(int32_t pid)
538 {
539     ProcessState procState = ProcessStatus::GetInstance().GetProcessState(pid);
540     if (procState == FOREGROUND) {
541         return static_cast<int32_t>(FOREGROUND);
542     }
543     uint64_t procForegroundTime = ProcessStatus::GetInstance().GetProcessLastForegroundTime(pid);
544     if (procForegroundTime >= preCollectProcIoTime_) {
545         return static_cast<int32_t>(FOREGROUND);
546     }
547     return static_cast<int32_t>(procState);
548 }
549 
CalculateProcIoStats(const ProcessIo & currData,int32_t pid,uint64_t period)550 void IoCollectorImpl::CalculateProcIoStats(const ProcessIo& currData, int32_t pid, uint64_t period)
551 {
552     if (procIoStatsMap_.find(pid) == procIoStatsMap_.end()) {
553         return;
554     }
555 
556     ProcessIoStatsInfo& statsInfo = procIoStatsMap_[pid];
557     ProcessIo& preData = statsInfo.preData;
558     ProcessIoStats& stats = statsInfo.stats;
559     stats.pid = pid;
560     stats.name = ProcessStatus::GetInstance().GetProcessName(pid);
561     stats.ground = GetProcStateInCollectionPeriod(pid);
562     if (period != 0) {
563         stats.rcharRate = IoCalculator::PercentValue(preData.rchar, currData.rchar, period);
564         stats.wcharRate = IoCalculator::PercentValue(preData.wchar, currData.wchar, period);
565         stats.syscrRate = IoCalculator::PercentValue(preData.syscr, currData.syscr, period);
566         stats.syscwRate = IoCalculator::PercentValue(preData.syscw, currData.syscw, period);
567         stats.readBytesRate = IoCalculator::PercentValue(preData.readBytes, currData.readBytes, period);
568         stats.writeBytesRate = IoCalculator::PercentValue(preData.writeBytes, currData.writeBytes, period);
569     }
570 }
571 
CollectAllProcIoStats(bool isUpdate)572 CollectResult<std::vector<ProcessIoStats>> IoCollectorImpl::CollectAllProcIoStats(bool isUpdate)
573 {
574     CollectResult<std::vector<ProcessIoStats>> result;
575     GetProcIoStats(result.data, isUpdate);
576     HIVIEW_LOGI("collect process io stats size=%{public}zu, isUpdate=%{public}d", result.data.size(), isUpdate);
577     result.retCode = UcError::SUCCESS;
578     return result;
579 }
580 
ExportAllProcIoStats()581 CollectResult<std::string> IoCollectorImpl::ExportAllProcIoStats()
582 {
583     CollectResult<std::string> result;
584     result.retCode = UcError::UNSUPPORT;
585 
586     std::vector<ProcessIoStats> allProcIoStats;
587     GetProcIoStats(allProcIoStats, false);
588     std::sort(allProcIoStats.begin(), allProcIoStats.end(),
589         [](const ProcessIoStats &leftStats, const ProcessIoStats &rightStats) {
590             return leftStats.name < rightStats.name;
591         });
592 
593     std::string fileName = CreateExportFileName(PROC_IO_STATS_FILE_PREFIX);
594     if (fileName.empty()) {
595         return result;
596     }
597     int fd = open(fileName.c_str(), O_WRONLY);
598     if (fd < 0) {
599         HIVIEW_LOGE("open file=%{public}s failed.", fileName.c_str());
600         return result;
601     }
602     dprintf(fd, "%-13s\t%12s\t%12s\t%12s\t%12s\t%12s\t%12s\t%20s\t%20s\n", "pid", "pname", "fg/bg",
603         "rchar/s", "wchar/s", "syscr/s", "syscw/s", "readBytes/s", "writeBytes/s");
604     for (auto &procIoStats : allProcIoStats) {
605         dprintf(fd, "%-12d\t%12s\t%12d\t%12.2f\t%12.2f\t%12.2f\t%12.2f\t%12.2f\t%12.2f\n",
606             procIoStats.pid, procIoStats.name.c_str(), procIoStats.ground, procIoStats.rcharRate, procIoStats.wcharRate,
607             procIoStats.syscrRate, procIoStats.syscwRate, procIoStats.readBytesRate, procIoStats.writeBytesRate);
608     }
609     close(fd);
610 
611     result.retCode = UcError::SUCCESS;
612     result.data = fileName;
613     return result;
614 }
615 
CollectSysIoStats()616 CollectResult<SysIoStats> IoCollectorImpl::CollectSysIoStats()
617 {
618     CollectResult<SysIoStats> result;
619     std::vector<ProcessIoStats> allProcIoStats;
620     GetProcIoStats(allProcIoStats, false);
621 
622     auto &sysIoStats = result.data;
623     for (auto &procIoStats : allProcIoStats) {
624         sysIoStats.rcharRate += procIoStats.rcharRate;
625         sysIoStats.wcharRate += procIoStats.wcharRate;
626         sysIoStats.syscrRate += procIoStats.syscrRate;
627         sysIoStats.syscwRate += procIoStats.syscwRate;
628         sysIoStats.readBytesRate += procIoStats.readBytesRate;
629         sysIoStats.writeBytesRate += procIoStats.writeBytesRate;
630     }
631     result.retCode = UcError::SUCCESS;
632     return result;
633 }
634 
ExportSysIoStats()635 CollectResult<std::string> IoCollectorImpl::ExportSysIoStats()
636 {
637     CollectResult<std::string> result;
638     result.retCode = UcError::UNSUPPORT;
639     auto collectSysIoStatsResult = CollectSysIoStats();
640     if (collectSysIoStatsResult.retCode != UcError::SUCCESS) {
641         return result;
642     }
643 
644     std::string fileName = CreateExportFileName(SYS_IO_STATS_FILE_PREFIX);
645     if (fileName.empty()) {
646         return result;
647     }
648     int fd = open(fileName.c_str(), O_WRONLY);
649     if (fd < 0) {
650         HIVIEW_LOGE("open file=%{public}s failed.", fileName.c_str());
651         return result;
652     }
653     dprintf(fd, "%-12s\t%12s\t%12s\t%12s\t%20s\t%20s\n",
654         "rchar/s", "wchar/s", "syscr/s", "syscw/s", "readBytes/s", "writeBytes/s");
655     auto &sysIoStats = collectSysIoStatsResult.data;
656     dprintf(fd, "%-12.2f\t%12.2f\t%12.2f\t%12.2f\t%12.2f\t%12.2f\n", sysIoStats.rcharRate, sysIoStats.wcharRate,
657         sysIoStats.syscrRate, sysIoStats.syscwRate, sysIoStats.readBytesRate, sysIoStats.writeBytesRate);
658     close(fd);
659 
660     result.retCode = UcError::SUCCESS;
661     result.data = fileName;
662     return result;
663 }
664 } // UCollectUtil
665 } // HiViewDFX
666 } // OHOS
667