• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 "appfreeze_cpu_freq_manager.h"
17 
18 #include <fcntl.h>
19 #include <string>
20 #include <iostream>
21 #include <iomanip>
22 #include <sstream>
23 #include <cstdint>
24 #include <dlfcn.h>
25 #include <cstdio>
26 
27 #include "file_ex.h"
28 #include "directory_ex.h"
29 #include "string_ex.h"
30 #include "hilog_tag_wrapper.h"
31 #include "time_util.h"
32 #include "appfreeze_util.h"
33 #include "dfx_define.h"
34 #include "fault_data.h"
35 
36 namespace OHOS {
37 namespace AppExecFwk {
38 namespace {
39     constexpr int64_t HZ_TO_MHZ = 1000;
40     constexpr size_t CPU_FREQ_AND_TIME_NUM = 5;
41     constexpr int CPU_FREQ_DECIMAL_BASE = 10;
42     constexpr float CPU_PERCENTAGE = 100.0f;
43     constexpr float CPU_MIN_FREQ_USAGE_VALUE = 1.0f;
44     constexpr uint32_t TIME_IN_STATE_FIRST_INDEX = 0;
45     constexpr uint32_t TIME_IN_STATE_SECOND_INDEX = 1;
46     constexpr uint32_t START_TIME_FIRST_INDEX = 13;
47     constexpr uint32_t START_TIME_SECOND_INDEX = 14;
48     constexpr const char* const LOG_FILE_HEAD = "Generated by HiviewDFX @OpenHarmony";
49     constexpr const char* const LOG_FILE_SEP = "===============================================================";
50     constexpr int START_PATH_LEN = 128;
51     constexpr const char* const LIB_THREAD_CPU_LOAD_PATH = "libucollection_utility.z.so";
52     constexpr int TIME_LIMIT = 6000; // 6s
53     constexpr size_t MAX_CPU_MAP_SIZE = 10;
54     constexpr uint32_t DEFAULT_CPU_SIZE = 1;
55     constexpr const char* const CPU_INFO_PREFIX = "cpu-info-";
56 
57 }
58 std::shared_ptr<AppfreezeCpuFreqManager> AppfreezeCpuFreqManager::instance_ = nullptr;
59 ffrt::mutex AppfreezeCpuFreqManager::freezeInfoMutex_;
60 int AppfreezeCpuFreqManager::cpuCount_ = 0;
61 std::map<std::string, CpuDataProcessor> AppfreezeCpuFreqManager::cpuInfoMap_;
62 
63 typedef double (*GetThreadCpuload)(int);
64 
AppfreezeCpuFreqManager()65 AppfreezeCpuFreqManager::AppfreezeCpuFreqManager()
66 {
67     cpuCount_ = AppfreezeUtil::GetCpuCount();
68 }
69 
~AppfreezeCpuFreqManager()70 AppfreezeCpuFreqManager::~AppfreezeCpuFreqManager()
71 {
72 }
73 
GetInstance()74 AppfreezeCpuFreqManager &AppfreezeCpuFreqManager::GetInstance()
75 {
76     static AppfreezeCpuFreqManager instance;
77     return instance;
78 }
79 
ClearOldCpuData(uint64_t curTime)80 void AppfreezeCpuFreqManager::ClearOldCpuData(uint64_t curTime)
81 {
82     std::lock_guard<ffrt::mutex> lock(freezeInfoMutex_);
83     if (cpuInfoMap_.size() < MAX_CPU_MAP_SIZE) {
84         return ;
85     }
86     for (auto it = cpuInfoMap_.begin(); it != cpuInfoMap_.end();) {
87         auto diff = curTime - it->second.GetCpuStartTime().halfStartTime;
88         if (diff > TIME_LIMIT || diff < 0) {
89             it = cpuInfoMap_.erase(it);
90         } else {
91             ++it;
92         }
93     }
94 }
95 
IsSkipTask(uint64_t curTime,const std::string & key,int32_t pid)96 bool AppfreezeCpuFreqManager::IsSkipTask(uint64_t curTime, const std::string &key, int32_t pid)
97 {
98     std::lock_guard<ffrt::mutex> lock(freezeInfoMutex_);
99     auto it = cpuInfoMap_.find(key);
100     if (it != cpuInfoMap_.end()) {
101         auto diff = curTime - it->second.GetCpuStartTime().halfStartTime;
102         if (diff > TIME_LIMIT || diff < 0) {
103             it = cpuInfoMap_.erase(it);
104         } else {
105             TAG_LOGW(AAFwkTag::APPDFR, "Skip this task. "
106                 "The task of the current process is already being executed, pid:%{public}d", pid);
107             return true;
108         }
109     }
110     if (cpuInfoMap_.size() >= MAX_CPU_MAP_SIZE) {
111         TAG_LOGW(AAFwkTag::APPDFR, "Skip this task. "
112             "The current queue can only execute up to %{public}zu tasks", MAX_CPU_MAP_SIZE);
113         return true;
114     }
115     return false;
116 }
117 
InitCpuDataProcessor(const std::string & eventType,int32_t pid,int32_t uid,const std::string & stackPath)118 bool AppfreezeCpuFreqManager::InitCpuDataProcessor(const std::string &eventType,
119     int32_t pid, int32_t uid, const std::string &stackPath)
120 {
121     uint64_t curTime = AppfreezeUtil::GetMilliseconds();
122     ClearOldCpuData(curTime);
123     std::string key = eventType + std::to_string(uid);
124     if (IsSkipTask(curTime, key, pid)) {
125         return false;
126     }
127     CpuStartTime cpuStartTime = {
128         .halfStartTime = curTime,
129         .optimalCpuStartTime = GetOptimalCpuTime(pid),
130     };
131     std::vector<std::vector<CpuFreqData>> cpuData;
132     std::vector<TotalTime> totalTimeList;
133     ParseCpuData(cpuData, totalTimeList);
134     CpuDataProcessor data(cpuData, totalTimeList, cpuStartTime, stackPath, pid);
135     {
136         std::lock_guard<ffrt::mutex> lock(freezeInfoMutex_);
137         cpuInfoMap_[key] = data;
138     }
139     TAG_LOGD(AAFwkTag::APPDFR, "init success. eventType: %{public}s path: %{public}s "
140         "halfStartTime: %{public}" PRIu64", optimalCpuStartTime: %{public}" PRIu64".",
141         eventType.c_str(), stackPath.c_str(), cpuStartTime.halfStartTime,
142         cpuStartTime.optimalCpuStartTime);
143     return true;
144 }
145 
ParseCpuData(std::vector<std::vector<CpuFreqData>> & datas,std::vector<TotalTime> & totalTimeLists)146 void AppfreezeCpuFreqManager::ParseCpuData(std::vector<std::vector<CpuFreqData>>& datas,
147     std::vector<TotalTime>& totalTimeLists)
148 {
149     TAG_LOGD(AAFwkTag::APPDFR, "ParseCpuData start time: %{public}s",
150         AbilityRuntime::TimeUtil::DefaultCurrentTimeStr().c_str());
151     std::string tmp = "start time: " + AbilityRuntime::TimeUtil::DefaultCurrentTimeStr();
152     TAG_LOGW(AAFwkTag::APPDFR, "ParseCpuData called, %{public}s", tmp.c_str());
153     for (int32_t i = 0; i < cpuCount_; ++i) {
154         std::vector<CpuFreqData> parseDatas;
155         TotalTime totalTime{};
156         if (ReadCpuDataByNum(i, parseDatas, totalTime)) {
157             datas.push_back(parseDatas);
158             totalTimeLists.push_back(totalTime);
159         }
160     }
161     TAG_LOGD(AAFwkTag::APPDFR, "ParseCpuData end time: %{public}s",
162         AbilityRuntime::TimeUtil::DefaultCurrentTimeStr().c_str());
163 }
164 
ReadCpuDataByNum(int32_t num,std::vector<CpuFreqData> & parseDatas,TotalTime & totalTime)165 bool AppfreezeCpuFreqManager::ReadCpuDataByNum(int32_t num, std::vector<CpuFreqData>& parseDatas,
166     TotalTime& totalTime)
167 {
168     TAG_LOGD(AAFwkTag::APPDFR, "ReadCpuDataByNum start time: %{public}s",
169         AbilityRuntime::TimeUtil::DefaultCurrentTimeStr().c_str());
170     if (num > cpuCount_) {
171         TAG_LOGE(AAFwkTag::APPDFR, "Read cpu info failed, num:%{public}d, cpuCount:%{public}d",
172             num, cpuCount_);
173         return false;
174     }
175     std::string cpuFreqPath = "/sys/devices/system/cpu/cpu" + std::to_string(num) + "/power/time_in_state";
176     std::string data;
177     if (!LoadStringFromFile(cpuFreqPath, data)) {
178         TAG_LOGE(AAFwkTag::APPDFR, "Read cpu time failed, cpuFreqPath:%{public}s", cpuFreqPath.c_str());
179         return false;
180     }
181     std::istringstream iss(data);
182     std::string line;
183     while (std::getline(iss, line)) {
184         if (line.empty()) {
185             continue;
186         }
187         std::vector<std::string> tokens;
188         SplitStr(line, " ", tokens);
189         if (tokens.size() != CPU_FREQ_AND_TIME_NUM) {
190             continue;
191         }
192         CpuFreqData cpuFreqData{};
193         cpuFreqData.frequency = static_cast<uint64_t>(strtoull(tokens[TIME_IN_STATE_FIRST_INDEX].c_str(),
194             nullptr, CPU_FREQ_DECIMAL_BASE));
195         cpuFreqData.runningTime = static_cast<uint64_t>(strtoull(tokens[TIME_IN_STATE_SECOND_INDEX].c_str(),
196             nullptr, CPU_FREQ_DECIMAL_BASE));
197         totalTime.totalRunningTime += cpuFreqData.runningTime;
198         for (size_t i = 1; i < tokens.size(); ++i) {
199             totalTime.totalCpuTime += static_cast<uint64_t>(strtoull(tokens[i].c_str(), nullptr,
200                 CPU_FREQ_DECIMAL_BASE));
201         }
202         parseDatas.push_back(cpuFreqData);
203     }
204     return true;
205 }
206 
GetCpuStr(int code,std::vector<FrequencyPair> & freqPairs,float percentage)207 std::string AppfreezeCpuFreqManager::GetCpuStr(int code, std::vector<FrequencyPair>& freqPairs,
208     float percentage)
209 {
210     std::sort(freqPairs.begin(), freqPairs.end(),
211         [] (const auto& pairOne, const auto& pairTwo) { return pairOne.percentage > pairTwo.percentage; });
212 
213     std::stringstream ss;
214     ss << "cpu" << std::to_string(code) << " Usage " << AppfreezeUtil::RoundToTwoDecimals(percentage) << "%, ";
215     bool isEnd = true;
216     for (const auto& pair : freqPairs) {
217         if (!isEnd) {
218             ss << ", ";
219         }
220         isEnd = false;
221         ss << pair.frequency << "MHZ " << AppfreezeUtil::RoundToTwoDecimals(pair.percentage) << "%";
222     }
223     ss << std::endl;
224     return ss.str();
225 }
226 
GetCpuTotalValue(size_t i,std::vector<TotalTime> totalTimeList,std::vector<TotalTime> blockTotalTimeList,TotalTime & totalTime)227 bool AppfreezeCpuFreqManager::GetCpuTotalValue(size_t i, std::vector<TotalTime> totalTimeList,
228     std::vector<TotalTime> blockTotalTimeList, TotalTime& totalTime)
229 {
230     if (totalTimeList.size() <= i || totalTimeList.size() != blockTotalTimeList.size()) {
231         TAG_LOGE(AAFwkTag::APPDFR, "index:%{public}zu, halfTotal size:%{public}zu, "
232             "blockTotal size:%{public}zu.", i, totalTimeList.size(), blockTotalTimeList.size());
233         return false;
234     }
235     totalTime.totalCpuTime = totalTimeList[i].totalCpuTime > blockTotalTimeList[i].totalCpuTime ?
236         (totalTimeList[i].totalCpuTime - blockTotalTimeList[i].totalCpuTime) :
237         (blockTotalTimeList[i].totalCpuTime - totalTimeList[i].totalCpuTime);
238     if (totalTime.totalCpuTime <= 0) {
239         TAG_LOGE(AAFwkTag::APPDFR, "totalCpuTime:%{public}" PRIu64"less than zero.", totalTime.totalCpuTime);
240         return false;
241     }
242     totalTime.totalRunningTime = totalTimeList[i].totalRunningTime > blockTotalTimeList[i].totalRunningTime ?
243         (totalTimeList[i].totalRunningTime - blockTotalTimeList[i].totalRunningTime) :
244         (blockTotalTimeList[i].totalRunningTime - totalTimeList[i].totalRunningTime);
245     return true;
246 }
247 
GetCpuInfoContent(const std::vector<std::vector<CpuFreqData>> & handlingHalfCpuData,const std::vector<TotalTime> & totalTimeList)248 std::string AppfreezeCpuFreqManager::GetCpuInfoContent(
249     const std::vector<std::vector<CpuFreqData>> &handlingHalfCpuData, const std::vector<TotalTime> &totalTimeList)
250 {
251     if (handlingHalfCpuData.size() == 0 || totalTimeList.size() == 0) {
252         return "";
253     }
254     std::stringstream ss;
255     ss << "start time:" << AbilityRuntime::TimeUtil::DefaultCurrentTimeStr() << std::endl;
256     std::vector<std::vector<CpuFreqData>> blockCpuData;
257     std::vector<TotalTime> blockTotalTimeList;
258     ParseCpuData(blockCpuData, blockTotalTimeList);
259     if (handlingHalfCpuData.size() != blockCpuData.size()) {
260         TAG_LOGE(AAFwkTag::APPDFR, "Half and block have different sizes, halfData:%{public}zu, "
261             "blockData:%{public}zu", handlingHalfCpuData.size(), blockCpuData.size());
262         return "";
263     }
264     for (size_t i = 0; i < handlingHalfCpuData.size(); ++i) {
265         auto halfData = handlingHalfCpuData[i];
266         auto blockData = blockCpuData[i];
267         if (halfData.size() != blockData.size()) {
268             TAG_LOGE(AAFwkTag::APPDFR, "Half and block have different sizes, halfData:%{public}zu, "
269                 "blockData:%{public}zu", halfData.size(), blockData.size());
270             return "";
271         }
272         TotalTime totalTime{};
273         if (!GetCpuTotalValue(i, totalTimeList, blockTotalTimeList, totalTime)) {
274             return "";
275         }
276         float percentage = (static_cast<float>(totalTime.totalRunningTime) /
277             static_cast<float>(totalTime.totalCpuTime)) * CPU_PERCENTAGE;;
278         std::vector<FrequencyPair> freqPairs;
279         for (size_t j = 0; j < halfData.size(); ++j) {
280             FrequencyPair pair{};
281             uint64_t runningTime = halfData[j].runningTime > blockData[j].runningTime ?
282                 (halfData[j].runningTime - blockData[j].runningTime) :
283                 (blockData[j].runningTime - halfData[j].runningTime);
284             pair.percentage = (static_cast<float>(runningTime) /
285                 static_cast<float>(totalTime.totalCpuTime)) * CPU_PERCENTAGE;
286             if (pair.percentage < 1 || halfData[j].frequency != blockData[j].frequency) {
287                 continue;
288             }
289             pair.frequency = halfData[j].frequency / HZ_TO_MHZ;
290             freqPairs.push_back(pair);
291         }
292         ss << GetCpuStr(i, freqPairs, percentage);
293     }
294     ss << "end time:" << AbilityRuntime::TimeUtil::DefaultCurrentTimeStr() << std::endl;
295     return ss.str();
296 }
297 
GetAppCpuTime(int32_t pid)298 uint64_t AppfreezeCpuFreqManager::GetAppCpuTime(int32_t pid)
299 {
300     if (pid < 0) {
301         return 0;
302     }
303     uint64_t cpuTime = 0;
304     std::string filePath = "/proc/" + std::to_string(pid) + "/task/" + std::to_string(pid) + "/stat";
305     std::string content;
306     if (!LoadStringFromFile(filePath, content)) {
307         TAG_LOGE(AAFwkTag::APPDFR, "Read cpu task stat failed, path:%{public}s", filePath.c_str());
308         return cpuTime;
309     }
310     if (!content.empty()) {
311         std::vector<std::string> tokens;
312         SplitStr(content, " ", tokens);
313         if (tokens.size() <= START_TIME_SECOND_INDEX) {
314             TAG_LOGE(AAFwkTag::APPDFR, "GetAppCpuTime failed, content size: %{public}zu.", tokens.size());
315             return cpuTime;
316         }
317         cpuTime = static_cast<uint64_t>(strtoull(tokens[START_TIME_FIRST_INDEX].c_str(),
318             nullptr, CPU_FREQ_DECIMAL_BASE));
319         cpuTime += static_cast<uint64_t>(strtoull(tokens[START_TIME_SECOND_INDEX].c_str(),
320             nullptr, CPU_FREQ_DECIMAL_BASE));
321     }
322     return cpuTime;
323 }
324 
GetProcessCpuTime(int32_t pid)325 uint64_t AppfreezeCpuFreqManager::GetProcessCpuTime(int32_t pid)
326 {
327     if (pid < 0) {
328         return 0;
329     }
330     std::string statPath = "/proc/" + std::to_string(pid) + "/stat";
331     std::string content;
332     if (!LoadStringFromFile(statPath, content)) {
333         TAG_LOGE(AAFwkTag::APPDFR, "Read cpu stat failed, path:%{public}s", statPath.c_str());
334         return 0;
335     }
336     uint64_t processCpuTime = 0;
337     if (!content.empty()) {
338         std::vector<std::string> tokens;
339         SplitStr(content, " ", tokens);
340         if (tokens.size() <= START_TIME_SECOND_INDEX) {
341             TAG_LOGE(AAFwkTag::APPDFR, "GetAppCpuTime failed, content size: %{public}zu.", tokens.size());
342             return processCpuTime;
343         }
344         processCpuTime = static_cast<uint64_t>(strtoull(tokens[START_TIME_FIRST_INDEX].c_str(),
345             nullptr, CPU_FREQ_DECIMAL_BASE));
346         processCpuTime += static_cast<uint64_t>(strtoull(tokens[START_TIME_SECOND_INDEX].c_str(),
347             nullptr, CPU_FREQ_DECIMAL_BASE));
348     }
349     return processCpuTime;
350 }
351 
GetDeviceRuntime()352 uint64_t AppfreezeCpuFreqManager::GetDeviceRuntime()
353 {
354     std::string statPath = AppfreezeUtil::PROC_STAT_PATH;
355     std::string content;
356     if (!LoadStringFromFile(statPath, content)) {
357         TAG_LOGE(AAFwkTag::APPDFR, "Read device run time failed, path:%{public}s", statPath.c_str());
358         return 0;
359     }
360     uint64_t deviceRuntime = 0;
361     std::string line;
362     std::istringstream iss(content);
363     if (std::getline(iss, line) && !line.empty()) {
364         std::vector<std::string> strings;
365         SplitStr(line, " ", strings);
366         if (strings.size() <= DEFAULT_CPU_SIZE) {
367             TAG_LOGE(AAFwkTag::APPDFR, "GetDeviceRuntime failed, string size: %{public}zu.", strings.size());
368             return deviceRuntime;
369         }
370         for (size_t i = 1; i < strings.size(); ++i) {
371             deviceRuntime += static_cast<uint64_t>(strtoull(strings[i].c_str(), nullptr,
372                 CPU_FREQ_DECIMAL_BASE));
373         }
374     }
375     return deviceRuntime;
376 }
377 
GetOptimalCpuTime(int32_t pid)378 double AppfreezeCpuFreqManager::GetOptimalCpuTime(int32_t pid)
379 {
380     int maxCpuCount = cpuCount_ - AppfreezeUtil::CPU_COUNT_SUBTRACT;
381     if (maxCpuCount <= 0) {
382         TAG_LOGE(AAFwkTag::APPDFR, "GetOptimalCpuTime failed, maxCpuCount:%{public}d", maxCpuCount);
383         return -1;
384     }
385     std::string statPath = "/sys/devices/system/cpu/cpu" + std::to_string(maxCpuCount) + "/cpu_capacity";
386     std::string content;
387     int ret = -1;
388     if (!LoadStringFromFile(statPath, content)) {
389         TAG_LOGE(AAFwkTag::APPDFR, "GetOptimalCpuTime failed, path:%{public}s, errno:%{public}d",
390             statPath.c_str(), errno);
391         return ret;
392     }
393     if (content.empty()) {
394         TAG_LOGE(AAFwkTag::APPDFR, "Read info failed, path:%{public}s", statPath.c_str());
395         return ret;
396     }
397     int32_t dmips = static_cast<int32_t>(strtoull(content.c_str(), nullptr, CPU_FREQ_DECIMAL_BASE));
398     void* threadFuncHandler = dlopen(LIB_THREAD_CPU_LOAD_PATH, RTLD_LAZY);
399     if (threadFuncHandler == nullptr) {
400         TAG_LOGE(AAFwkTag::APPDFR, "dlopen failed, funcHandler is nullptr.");
401         return ret;
402     }
403     dlerror();
404     char* err = nullptr;
405     auto getThreadCpuload = reinterpret_cast<GetThreadCpuload>(dlsym(threadFuncHandler, "GetThreadCpuload"));
406     err = dlerror();
407     if (err != nullptr) {
408         TAG_LOGE(AAFwkTag::APPDFR, "dlsym GetThreadCpuload func failed. %{public}s", err);
409         return ret;
410     }
411     double optimalCpuTime = getThreadCpuload(pid);
412     threadFuncHandler = nullptr;
413     getThreadCpuload = nullptr;
414     dlclose(threadFuncHandler);
415     if (dmips <= 0 || optimalCpuTime < 0) {
416         return ret;
417     }
418     TAG_LOGW(AAFwkTag::APPDFR, "dmips %{public}d optimalCpuTime %{public}lf", dmips, optimalCpuTime);
419     return optimalCpuTime / dmips;
420 }
421 
GetStartTime(uint64_t start)422 std::string AppfreezeCpuFreqManager::GetStartTime(uint64_t start)
423 {
424     const uint32_t placeholder = 3;
425     uint64_t startTime = start / AppfreezeUtil::SEC_TO_MILLISEC;
426     std::ostringstream startTimeStr;
427     startTimeStr << AppfreezeUtil::TimestampFormatToDate(startTime, "%Y-%m-%d %H:%M:%S");
428     startTimeStr << ":" << std::setw(placeholder) << std::setfill('0') <<
429         std::to_string(start % AppfreezeUtil::SEC_TO_MILLISEC);
430     return startTimeStr.str();
431 }
432 
GetStaticInfoHead()433 std::string AppfreezeCpuFreqManager::GetStaticInfoHead()
434 {
435     std::ostringstream staticInfoStr;
436     staticInfoStr << "#Basic Concepts" << std::endl;
437     staticInfoStr << "T1:  StaticsDuration, EndTime - StartTime." << std::endl;
438     staticInfoStr << "T2:  CpuTime              --Time that spend on CPU." << std::endl;
439     staticInfoStr << "T3:  SyncWaitTime         --SleepingTime + Runnable Time, etc." << std::endl;
440     staticInfoStr << "T4:  OptimalCpuTime       --run the thread at the max Core's max cpu capacity." << std::endl;
441     staticInfoStr << "T5:  SupplyAvailableTime  --T2 - T3. Time can be optimized by scheduling." << std::endl;
442     staticInfoStr << "Equation:  T1 = T2 + T3. T2 = T4 = T5." << std::endl;
443     staticInfoStr <<
444         "|-----------------------------------StaticsDuration-----------------------------------|." << std::endl;
445     staticInfoStr <<
446         "|-------------------------CpuTime----------------------|--------SyncWaitTime----------|." << std::endl;
447     staticInfoStr <<
448         "|----OptimalCpuTime----|------SupplyAvailableTime------|--------SyncWaitTime----------|." << std::endl;
449     return staticInfoStr.str();
450 }
451 
GetStaticInfo(int32_t pid,CpuStartTime cpuStartTime)452 std::string AppfreezeCpuFreqManager::GetStaticInfo(int32_t pid, CpuStartTime cpuStartTime)
453 {
454     std::ostringstream staticInfoStr;
455     staticInfoStr << GetStaticInfoHead() << std::endl;
456     staticInfoStr << "#Basic Statistical Infomation " << std::endl;
457     staticInfoStr << "ProcessCpuTime: " << GetProcessCpuTime(pid) << " ms" << std::endl;
458     staticInfoStr << "DeviceRuntime: " << GetDeviceRuntime() << " ms" << std::endl;
459     staticInfoStr << "Tid: " << pid << std::endl;
460     staticInfoStr << "StartTime: " << GetStartTime(cpuStartTime.halfStartTime) << std::endl;
461     staticInfoStr << "EndTime: " << AbilityRuntime::TimeUtil::DefaultCurrentTimeStr() << std::endl;
462     uint64_t duration = AppfreezeUtil::GetMilliseconds() - cpuStartTime.halfStartTime;
463     staticInfoStr << "StaticsDuration: " << duration << " ms" << std::endl;
464     uint64_t cpuTime = GetAppCpuTime(pid);
465     uint64_t syncWaitTime = duration - cpuTime;
466     uint64_t optimalCpuTime = GetOptimalCpuTime(pid) - cpuStartTime.optimalCpuStartTime;
467     uint64_t supplyAvailableTime = duration - optimalCpuTime - syncWaitTime;
468     staticInfoStr << "CpuTime: " << cpuTime << " ms" << std::endl;
469     staticInfoStr << "SyncWaitTime: " << syncWaitTime << " ms" << std::endl;
470     staticInfoStr << "OptimalCpuTime: " << optimalCpuTime << " ms" << std::endl;
471     staticInfoStr << "SupplyAvailableTime: " << supplyAvailableTime << " ms" << std::endl;
472     return staticInfoStr.str();
473 }
474 
WriteDfxLogToFile(const std::string & filePath,const std::string & bundleName)475 void AppfreezeCpuFreqManager::WriteDfxLogToFile(const std::string &filePath, const std::string &bundleName)
476 {
477     std::stringstream ss;
478     ss << LOG_FILE_HEAD << std::endl;
479     ss << LOG_FILE_SEP << std::endl;
480     ss << "TimeStamp: " << AbilityRuntime::TimeUtil::DefaultCurrentTimeStr() << std::endl;
481     ss << "Module name: " << bundleName << std::endl;
482     OHOS::SaveStringToFile(filePath, ss.str());
483 }
484 
IsContainHalfData(const std::string & key,CpuDataProcessor & cpuData,int32_t pid)485 bool AppfreezeCpuFreqManager::IsContainHalfData(const std::string &key, CpuDataProcessor &cpuData, int32_t pid)
486 {
487     std::lock_guard<ffrt::mutex> lock(freezeInfoMutex_);
488     auto it = cpuInfoMap_.find(key);
489     if (it == cpuInfoMap_.end()) {
490         TAG_LOGI(AAFwkTag::APPDFR, "Not find warning fault, pid: %{public}d", pid);
491         return false;
492     }
493     int warningPid = it->second.GetPid();
494     if (warningPid != pid) {
495         TAG_LOGI(AAFwkTag::APPDFR, "Not find current pid:%{public}d, warning pid:%{public}d", pid, warningPid);
496         return false;
497     }
498     auto diff = AppfreezeUtil::GetMilliseconds() - it->second.GetCpuStartTime().halfStartTime;
499     if (diff > TIME_LIMIT) {
500         it = cpuInfoMap_.erase(it);
501         TAG_LOGI(AAFwkTag::APPDFR, "The last fault occurred more than 6 seconds ago, "
502             "diff: %{public}" PRIu64", pid: %{public}d.", diff, pid);
503         return false;
504     }
505     cpuData = it->second;
506     return true;
507 }
508 
WriteCpuInfoToFile(const std::string & eventType,const std::string & bundleName,int32_t uid,int32_t pid,const std::string & eventName)509 std::string AppfreezeCpuFreqManager::WriteCpuInfoToFile(const std::string &eventType,
510     const std::string &bundleName, int32_t uid, int32_t pid, const std::string &eventName)
511 {
512     std::string key = eventType + std::to_string(uid);
513     CpuDataProcessor cpuData;
514     if (!IsContainHalfData(key, cpuData, pid)) {
515         return "";
516     }
517 
518     std::string cpuInfo = GetCpuInfoContent(cpuData.GetHandlingHalfCpuData(), cpuData.GetTotalTimeList());
519     if (cpuInfo.empty()) {
520         return "";
521     }
522     std::string fileName = CPU_INFO_PREFIX + std::to_string(uid) +
523         AbilityRuntime::TimeUtil::FormatTime("%Y%m%d%H%M%S");
524     std::string filePath = AppfreezeUtil::CreateFile(AppfreezeUtil::EVENTLOG_PATH, fileName);
525     WriteDfxLogToFile(filePath, bundleName);
526 
527     std::ostringstream str;
528     str << std::endl << GetStaticInfo(pid, cpuData.GetCpuStartTime());
529     str << std::endl << "#CpuFreq Usage (usage >=1%)" << std::endl << cpuInfo << std::endl;
530     std::string path = filePath + "," + cpuData.GetStackPath();
531     OHOS::SaveStringToFile(filePath, str.str(), false);
532     {
533         std::lock_guard<ffrt::mutex> lock(freezeInfoMutex_);
534         cpuInfoMap_.erase(key);
535     }
536     TAG_LOGW(AAFwkTag::APPDFR, "Write CpuInfo to file: %{public}s", path.c_str());
537     return path;
538 }
539 }  // namespace AppExecFwk
540 }  // namespace OHOS
541