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 
16 #include "frame_report.h"
17 
18 #include <dlfcn.h>
19 #include <cstdio>
20 #include <securec.h>
21 #include <unistd.h>
22 #include <hilog/log.h>
23 
24 namespace OHOS {
25 namespace Rosen {
26 
27 #undef LOG_DOMAIN
28 #define LOG_DOMAIN 0xD005830
29 
30 #undef LOG_TAG
31 #define LOG_TAG "FrameReport"
32 
33 #define LOGF(format, ...) HILOG_FATAL(LOG_CORE, format, ##__VA_ARGS__)
34 #define LOGE(format, ...) HILOG_ERROR(LOG_CORE, format, ##__VA_ARGS__)
35 #define LOGW(format, ...) HILOG_WARN(LOG_CORE, format, ##__VA_ARGS__)
36 #define LOGI(format, ...) HILOG_INFO(LOG_CORE, format, ##__VA_ARGS__)
37 #define LOGD(format, ...) HILOG_DEBUG(LOG_CORE, format, ##__VA_ARGS__)
38 
39 const std::string GAME_ACCELERATE_SCHEDULE_SO_PATH = "libgame_acc_sched_client.z.so";
40 const std::string GAME_ACCELERATE_SCHEDULE_NOTIFYFRAMEINFO = "GAS_NotifyFrameInfo";
41 constexpr int32_t REPORT_BUFFER_SIZE = 256;
42 constexpr int32_t THOUSAND_COUNT = 1000;
43 constexpr int32_t SKIP_HINT_STATUS = 0;
44 constexpr int32_t FR_GAME_BACKGROUND = 0;
45 constexpr int32_t FR_GAME_FOREGROUND = 1;
46 constexpr int32_t FR_GAME_SCHED = 2;
47 
GetInstance()48 FrameReport& FrameReport::GetInstance()
49 {
50     static FrameReport instance;
51     return instance;
52 }
53 
FrameReport()54 FrameReport::FrameReport()
55 {
56 }
57 
~FrameReport()58 FrameReport::~FrameReport()
59 {
60     CloseLibrary();
61 }
62 
SetGameScene(int32_t pid,int32_t state)63 void FrameReport::SetGameScene(int32_t pid, int32_t state)
64 {
65     LOGI("FrameReport::SetGameScene pid = %{public}d state = %{public}d ", pid, state);
66     switch (state) {
67         case FR_GAME_BACKGROUND: {
68             if (IsActiveGameWithPid(pid)) {
69                 LOGI("FrameReport::SetGameScene Game Background Current Pid = %{public}d "
70                      "state = 0", pid);
71                 DeletePidInfo();
72             }
73             break;
74         }
75         case FR_GAME_FOREGROUND: {
76             LoadLibrary();
77             break;
78         }
79         case FR_GAME_SCHED: {
80             activelyPid_.store(pid);
81             break;
82         }
83         default: {
84             LOGW("FrameReport::SetGameScene state error!");
85             break;
86         }
87     }
88 }
89 
HasGameScene()90 bool FrameReport::HasGameScene()
91 {
92     return activelyPid_.load() != FR_DEFAULT_PID;
93 }
94 
IsActiveGameWithPid(int32_t pid)95 bool FrameReport::IsActiveGameWithPid(int32_t pid)
96 {
97     if (pid <= FR_DEFAULT_PID) {
98         return false;
99     }
100     return pid == activelyPid_.load();
101 }
102 
IsActiveGameWithUniqueId(uint64_t uniqueId)103 bool FrameReport::IsActiveGameWithUniqueId(uint64_t uniqueId)
104 {
105     if (uniqueId <= FR_DEFAULT_UNIQUEID) {
106         return false;
107     }
108     return uniqueId == activelyUniqueId_.load();
109 }
110 
SetLastSwapBufferTime(int64_t lastSwapBufferTime)111 void FrameReport::SetLastSwapBufferTime(int64_t lastSwapBufferTime)
112 {
113     lastSwapBufferTime_.store(lastSwapBufferTime);
114 }
115 
SetDequeueBufferTime(const std::string & layerName,int64_t dequeueBufferTime)116 void FrameReport::SetDequeueBufferTime(const std::string& layerName, int64_t dequeueBufferTime)
117 {
118     dequeueBufferTime_.store(dequeueBufferTime);
119 }
120 
SetQueueBufferTime(uint64_t uniqueId,const std::string & layerName,int64_t queueBufferTime)121 void FrameReport::SetQueueBufferTime(uint64_t uniqueId, const std::string& layerName, int64_t queueBufferTime)
122 {
123     queueBufferTime_.store(queueBufferTime);
124     activelyUniqueId_.store(uniqueId);
125 }
126 
SetPendingBufferNum(const std::string & layerName,int32_t pendingBufferNum)127 void FrameReport::SetPendingBufferNum(const std::string& layerName, int32_t pendingBufferNum)
128 {
129     pendingBufferNum_.store(pendingBufferNum);
130 }
131 
LoadLibrary()132 void FrameReport::LoadLibrary()
133 {
134     std::unique_lock lock(mutex_);
135     if (!isGameSoLoaded_) {
136         dlerror();
137         gameSoHandle_ = dlopen(GAME_ACCELERATE_SCHEDULE_SO_PATH.c_str(), RTLD_LAZY);
138         if (gameSoHandle_ == nullptr) {
139             LOGE("FrameReport::LoadLibrary dlopen libgame_acc_sched_client.z.so failed! error = %{public}s", dlerror());
140             return;
141         }
142         LOGI("FrameReport::LoadLibrary dlopen libgame_acc_sched_client.z.so success!");
143         notifyFrameInfoFunc_ = reinterpret_cast<NotifyFrameInfoFunc>(
144             LoadSymbol(GAME_ACCELERATE_SCHEDULE_NOTIFYFRAMEINFO));
145         if (notifyFrameInfoFunc_ == nullptr) {
146             if (dlclose(gameSoHandle_) != 0) {
147                 LOGE("FrameReport::CloseLibrary libgame_acc_sched_client.z.so close failed!");
148             } else {
149                 gameSoHandle_ = nullptr;
150                 LOGI("FrameReport::CloseLibrary libgame_acc_sched_client.z.so close success!");
151             }
152             return;
153         }
154         LOGI("FrameReport::LoadLibrary dlsym GAS_NotifyFrameInfo success!");
155         isGameSoLoaded_ = true;
156     }
157 }
158 
CloseLibrary()159 void FrameReport::CloseLibrary()
160 {
161     std::unique_lock lock(mutex_);
162     notifyFrameInfoFunc_ = nullptr;
163     if (gameSoHandle_ != nullptr) {
164         if (dlclose(gameSoHandle_) != 0) {
165             LOGE("FrameReport::CloseLibrary libgame_acc_sched_client.z.so close failed!");
166         } else {
167             gameSoHandle_ = nullptr;
168             isGameSoLoaded_ = false;
169             LOGI("FrameReport::CloseLibrary libgame_acc_sched_client.z.so close success!");
170         }
171     }
172 }
173 
LoadSymbol(const std::string & symName)174 void* FrameReport::LoadSymbol(const std::string& symName)
175 {
176     dlerror();
177     void *funcSym = dlsym(gameSoHandle_, symName.c_str());
178     if (funcSym == nullptr) {
179         LOGE("FrameReport::LoadSymbol Get %{public}s symbol failed: %{public}s", symName.c_str(), dlerror());
180         return nullptr;
181     }
182     return funcSym;
183 }
184 
DeletePidInfo()185 void FrameReport::DeletePidInfo()
186 {
187     activelyPid_.store(FR_DEFAULT_PID);
188     activelyUniqueId_.store(FR_DEFAULT_UNIQUEID);
189 }
190 
Report(const std::string & layerName)191 void FrameReport::Report(const std::string& layerName)
192 {
193     int64_t timeStamp = std::chrono::duration_cast<std::chrono::nanoseconds>(
194         std::chrono::steady_clock::now().time_since_epoch()).count();
195     std::string bufferMsg = "";
196     char msg[REPORT_BUFFER_SIZE] = { 0 };
197     int32_t ret = sprintf_s(msg, sizeof(msg),
198                             "{\"dequeueBufferTime\":\"%d\",\"queueBufferTime\":\"%d\",\"pendingBufferNum\":\"%d\","
199                             "\"swapBufferTime\":\"%d\", \"skipHint\":\"%d\"}",
200                             static_cast<int32_t>(dequeueBufferTime_.load() / THOUSAND_COUNT),
201                             static_cast<int32_t>(queueBufferTime_.load() / THOUSAND_COUNT),
202                             pendingBufferNum_.load(),
203                             static_cast<int32_t>(lastSwapBufferTime_.load() / THOUSAND_COUNT),
204                             SKIP_HINT_STATUS);
205     if (ret == -1) {
206         return;
207     }
208     bufferMsg = msg;
209     NotifyFrameInfo(activelyPid_.load(), layerName, timeStamp, bufferMsg);
210 }
211 
NotifyFrameInfo(int32_t pid,const std::string & layerName,int64_t timeStamp,const std::string & bufferMsg)212 void FrameReport::NotifyFrameInfo(int32_t pid, const std::string& layerName, int64_t timeStamp,
213                                   const std::string& bufferMsg)
214 {
215     std::shared_lock lock(mutex_);
216     if (notifyFrameInfoFunc_ == nullptr) {
217         return;
218     }
219     bool result = notifyFrameInfoFunc_(pid, layerName, timeStamp, bufferMsg);
220     if (!result) {
221         LOGW("FrameReport::NotifyFrameInfo Call GAS_NotifyFrameInfo Func Error");
222         DeletePidInfo();
223     }
224 }
225 } // namespace Rosen
226 } // namespace OHOS
227