1/*
2 * Copyright (C) 2021 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 <cstdio>
16#include <algorithm>
17#include <iostream>
18#include <sstream>
19#include <queue>
20#include <string>
21#include <thread>
22#include <unistd.h>
23#include <ctime>
24#include <sys/time.h>
25#include "include/sp_utils.h"
26#include "include/ByTrace.h"
27#include "include/Capture.h"
28#include "include/FPS.h"
29#include "include/startup_delay.h"
30#include "include/profiler_fps.h"
31#include "include/sp_log.h"
32#include "include/common.h"
33#include <sys/wait.h>
34#include <sys/types.h>
35namespace OHOS {
36namespace SmartPerf {
37std::map<std::string, std::string> FPS::ItemData()
38{
39    std::map<std::string, std::string> result;
40    FpsInfo fpsInfoResult;
41    if (surfaceViewName.length() > 0) {
42        fpsInfoResult = GetDiffLayersFpsInfo(surfaceViewName);
43    } else {
44        fpsInfoResult = GetFpsInfo();
45    }
46    prevResultFpsInfo = fpsInfoResult;
47    std::string value = FindFpsRefreshrate();
48    result["refreshrate"] = value;
49    if (processFlag) {
50        result["fps"] = "NA";
51        result["fpsJitters"] = "NA";
52    } else {
53        int fullFrame = 120;
54        if (fpsInfoResult.fps > fullFrame) {
55            fpsInfoResult.fps = fullFrame;
56        }
57        result["fps"] = std::to_string(fpsInfoResult.fps);
58        LOGI("result.fps: %s", std::to_string(fpsInfoResult.fps).c_str());
59        LOGI("result.curTime: %s", std::to_string(fpsInfoResult.curTime).c_str());
60        std::string jitterStr = "";
61        std::string split = "";
62        for (size_t i = 0; i < fpsInfoResult.jitters.size(); i++) {
63            if (i > 0) {
64                split = ";;";
65            }
66            jitterStr += split + std::to_string(fpsInfoResult.jitters[i]);
67        }
68        result["fpsJitters"] = jitterStr;
69        LOGI("result.jitters: %s", jitterStr.c_str());
70        SetFpsCurrentFpsTime(fpsInfoResult);
71    }
72    return result;
73}
74
75void FPS::SetFpsCurrentFpsTime(FpsInfo fpsInfoResult)
76{
77    ffTime.fps = fpsInfoResult.fps;
78    if (!fpsInfoResult.jitters.empty()) {
79        auto maxElement = std::max_element(fpsInfoResult.jitters.begin(), fpsInfoResult.jitters.end());
80        ffTime.currentFpsTime = *maxElement;
81    }
82}
83
84FpsCurrentFpsTime FPS::GetFpsCurrentFpsTime()
85{
86    return ffTime;
87}
88
89void FPS::SetPackageName(std::string pName)
90{
91    pkgName = std::move(pName);
92}
93
94void FPS::SetProcessId(const std::string &pid)
95{
96    processId = pid;
97}
98
99void FPS::SetLayerName(std::string sName)
100{
101    surfaceViewName = std::move(sName);
102}
103FpsInfo FPS::GetDiffLayersFpsInfo(const std::string &sName)
104{
105    OHOS::SmartPerf::SPUtils::GetCurrentTime(fifty, prevResultFpsInfo.curTime);
106    fpsInfoMax = GetSurfaceFrame(sName);
107    return fpsInfoMax;
108}
109
110FpsInfo FPS::GetFpsInfo()
111{
112    processFlag = false;
113    fpsInfoMax.fps = 0;
114    if (pkgName.empty()) {
115        return fpsInfoMax;
116    }
117    bool onTop = OHOS::SmartPerf::SPUtils::IsForeGround(pkgName);
118    if (onTop) {
119        std::string uniteLayer;
120        if (!rkFlag) {
121            uniteLayer = "UniRender";
122        } else {
123            ProfilerFPS &profilerFps = ProfilerFPS::GetInstance();
124            uniteLayer = profilerFps.GetSurface();
125        }
126        OHOS::SmartPerf::SPUtils::GetCurrentTime(fifty, prevResultFpsInfo.curTime);
127        fpsInfoMax = GetSurfaceFrame(uniteLayer);
128    } else {
129        LOGI("FPS:app is in the background");
130        if (processId.empty()) {
131            processFlag = true;
132            fpsInfoMax.Clear();
133        } else {
134            fpsInfoMax.Clear();
135        }
136    }
137    return fpsInfoMax;
138}
139
140FpsInfo FPS::GetSurfaceFrame(std::string name)
141{
142    if (name == "") {
143        return FpsInfo();
144    }
145    static std::map<std::string, FpsInfo> fpsMap;
146    if (fpsMap.count(name) == 0) {
147        FpsInfo tmp;
148        tmp.fps = 0;
149        fpsMap[name] = tmp;
150    }
151    fpsInfo = fpsMap[name];
152    fpsInfo.fps = 0;
153    std::string command = "fps " + name;
154    const char* args[] = { "hidumper", "-s", "10", "-a", command.c_str(), nullptr };
155    int pipefd[2];
156    pid_t pid;
157    if (pipe(pipefd) == -1) {
158        LOGE("FPS::Failed to create pipe");
159        return fpsInfo;
160    }
161    pid = fork();
162    if (pid == -1) {
163        LOGE("FPS::Failed to fork");
164        return fpsInfo;
165    } else if (pid == 0) {
166        close(pipefd[0]);
167        dup2(pipefd[1], STDOUT_FILENO);
168        close(pipefd[1]);
169        if (execvp(args[0], const_cast<char *const*>(args)) == -1) {
170            LOGE("FPS::Failed to execute hidumper");
171            return fpsInfo;
172        }
173    } else {
174        close(pipefd[1]);
175        ReadDataFromPipe(pipefd[0]);
176        close(pipefd[0]);
177        waitpid(pid, nullptr, 0);
178    }
179    return fpsInfo;
180}
181
182void FPS::ReadDataFromPipe(int fd)
183{
184    char tmp[1024];
185    fpsNum = 0;
186    prevScreenTimestamp = -1;
187    LOGI("FPS::dump time: start!");
188    struct timespec time1 = { 0 };
189    clock_gettime(CLOCK_MONOTONIC, &time1);
190    fpsInfo.curTime = static_cast<int>(time1.tv_sec - 1);
191    fpsInfo.currTimeDump = (time1.tv_sec - 1) * mod + time1.tv_nsec;
192    LOGI("FPS:fpsInfo.curTime: %d", fpsInfo.curTime);
193    LOGI("FPS:psInfo.currTimeDump: %lld", fpsInfo.currTimeDump);
194    FILE *fp = fdopen(fd, "r");
195    if (!fp) {
196        LOGE("FPS::Failed to open file descriptor");
197        return;
198    }
199    while (fgets(tmp, sizeof(tmp), fp) != nullptr) {
200        std::string str(tmp);
201        LOGD("FPS::dump time: %s", str.c_str());
202        curScreenTimestamp = 0;
203        std::stringstream sstream;
204        sstream << tmp;
205        sstream >> curScreenTimestamp;
206        if (curScreenTimestamp == 0) {
207            continue;
208        }
209        CalcFpsAndJitters();
210    }
211    if (fclose(fp) == EOF) {
212        LOGE("FPS::Failed to close file descriptor");
213    }
214}
215
216void FPS::CalcFpsAndJitters()
217{
218    std::string onScreenTime = std::to_string(curScreenTimestamp / mod);
219    std::string fpsCurTime = std::to_string(fpsInfo.curTime);
220    if (onScreenTime.find(fpsCurTime) != std::string::npos) {
221        fpsNum++;
222        fpsInfo.currTimeStamps.push_back(curScreenTimestamp);
223    }
224    fpsInfo.fps = fpsNum;
225    if (onScreenTime == fpsCurTime) {
226        long long jitter;
227        if (prevScreenTimestamp != -1) {
228            jitter = curScreenTimestamp - prevScreenTimestamp;
229            fpsInfo.jitters.push_back(jitter);
230        } else {
231            if (prevlastScreenTimestamp != 0 && (curScreenTimestamp - prevlastScreenTimestamp) < mod) {
232                jitter = curScreenTimestamp - prevlastScreenTimestamp;
233                fpsInfo.jitters.push_back(jitter);
234            } else {
235                jitter = curScreenTimestamp - curScreenTimestamp / mod * mod;
236                fpsInfo.jitters.push_back(jitter);
237            }
238        }
239        prevScreenTimestamp = curScreenTimestamp;
240        prevlastScreenTimestamp = curScreenTimestamp;
241    }
242}
243
244void FPS::SetRkFlag()
245{
246    rkFlag = true;
247}
248
249std::string FPS::FindFpsRefreshrate()
250{
251    std::string screenInfo;
252    SPUtils::LoadFile(screenPath, screenInfo);
253    size_t pos = 0;
254    std::string token;
255    std::string value;
256    if (!rkFlag) {
257        while ((pos = screenInfo.find(";")) != std::string::npos) {
258            token = screenInfo.substr(0, pos);
259            screenInfo.erase(0, pos + 1);
260            if (token.find("current_fps:") != std::string::npos) {
261                value = token.substr(token.find(":") + 1);
262                break;
263            }
264        }
265    } else {
266            std::string screen = OHOS::SmartPerf::SPUtils::GetScreen();
267            std::string start = "refreshrate=";
268            size_t startPos = screen.find(start) + start.length();
269            size_t endPos = screen.length();
270            value = screen.substr(startPos, endPos - startPos);
271        }
272    return value;
273}
274}
275}
276
277