1 /*
2  * Copyright (c) 2023-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 "hgm_frame_rate_manager.h"
17 
18 #include <algorithm>
19 #include <chrono>
20 #include <ctime>
21 #include "common/rs_common_hook.h"
22 #include "common/rs_optional_trace.h"
23 #include "common/rs_thread_handler.h"
24 #include "pipeline/rs_uni_render_judgement.h"
25 #include "hgm_config_callback_manager.h"
26 #include "hgm_core.h"
27 #include "hgm_energy_consumption_policy.h"
28 #include "hgm_log.h"
29 #include "hgm_screen_info.h"
30 #include "parameters.h"
31 #include "rs_trace.h"
32 #include "sandbox_utils.h"
33 #include "frame_rate_report.h"
34 #include "hisysevent.h"
35 
36 namespace OHOS {
37 namespace Rosen {
38 namespace {
39     constexpr float MARGIN = 0.00001;
40     constexpr float MIN_DRAWING_DIVISOR = 10.0f;
41     constexpr float DIVISOR_TWO = 2.0f;
42     constexpr int32_t IDLE_TIMER_EXPIRED = 200; // ms
43     constexpr int64_t UNI_RENDER_VSYNC_OFFSET = 5000000; // ns
44     constexpr int64_t UNI_RENDER_VSYNC_OFFSET_DELAY_MODE = -3300000; // ns
45     constexpr uint32_t REPORT_VOTER_INFO_LIMIT = 20;
46     constexpr int32_t LAST_TOUCH_CNT = 1;
47 
48     constexpr uint32_t FIRST_FRAME_TIME_OUT = 50; // 50ms
49     constexpr uint32_t VOTER_SCENE_PRIORITY_BEFORE_PACKAGES = 1;
50     constexpr uint64_t ENERGY_ASSURANCE_TASK_DELAY_TIME = 1000; //1s
51     constexpr uint64_t UI_ENERGY_ASSURANCE_TASK_DELAY_TIME = 3000; // 3s
52     const static std::string ENERGY_ASSURANCE_TASK_ID = "ENERGY_ASSURANCE_TASK_ID";
53     const static std::string UI_ENERGY_ASSURANCE_TASK_ID = "UI_ENERGY_ASSURANCE_TASK_ID";
54     const static std::string UP_TIME_OUT_TASK_ID = "UP_TIME_OUT_TASK_ID";
55     // CAUTION: with priority
56     const std::string VOTER_NAME[] = {
57         "VOTER_THERMAL",
58         "VOTER_VIRTUALDISPLAY_FOR_CAR",
59         "VOTER_VIRTUALDISPLAY",
60         "VOTER_POWER_MODE",
61         "VOTER_DISPLAY_ENGIN",
62         "VOTER_GAMES",
63         "VOTER_ANCO",
64 
65         "VOTER_PACKAGES",
66         "VOTER_LTPO",
67         "VOTER_SCENE",
68         "VOTER_VIDEO",
69         "VOTER_IDLE"
70     };
71 }
72 
Init(sptr<VSyncController> rsController,sptr<VSyncController> appController,sptr<VSyncGenerator> vsyncGenerator)73 void HgmFrameRateManager::Init(sptr<VSyncController> rsController,
74     sptr<VSyncController> appController, sptr<VSyncGenerator> vsyncGenerator)
75 {
76     voters_ = std::vector<std::string>(std::begin(VOTER_NAME), std::end(VOTER_NAME));
77     auto& hgmCore = HgmCore::Instance();
78     curRefreshRateMode_ = hgmCore.GetCurrentRefreshRateMode();
79     multiAppStrategy_.UpdateXmlConfigCache();
80     UpdateEnergyConsumptionConfig();
81 
82     // hgm warning: get non active screenId in non-folding devices(from sceneboard)
83     auto screenList = hgmCore.GetScreenIds();
84     curScreenId_ = screenList.empty() ? 0 : screenList.front();
85     auto& hgmScreenInfo = HgmScreenInfo::GetInstance();
86     isLtpo_ = hgmScreenInfo.IsLtpoType(hgmScreenInfo.GetScreenType(curScreenId_));
87     std::string curScreenName = "screen" + std::to_string(curScreenId_) + "_" + (isLtpo_ ? "LTPO" : "LTPS");
88     auto configData = hgmCore.GetPolicyConfigData();
89     if (configData != nullptr) {
90         if (configData->screenStrategyConfigs_.find(curScreenName) != configData->screenStrategyConfigs_.end()) {
91             curScreenStrategyId_ = configData->screenStrategyConfigs_[curScreenName];
92         }
93         idleDetector_.UpdateSupportAppBufferList(configData->appBufferList_);
94         if (curScreenStrategyId_.empty()) {
95             curScreenStrategyId_ = "LTPO-DEFAULT";
96         }
97         if (curRefreshRateMode_ != HGM_REFRESHRATE_MODE_AUTO && configData->xmlCompatibleMode_) {
98             curRefreshRateMode_ = configData->SettingModeId2XmlModeId(curRefreshRateMode_);
99         }
100         multiAppStrategy_.UpdateXmlConfigCache();
101         UpdateEnergyConsumptionConfig();
102         multiAppStrategy_.CalcVote();
103         HandleIdleEvent(ADD_VOTE);
104     }
105 
106     RegisterCoreCallbacksAndInitController(rsController, appController, vsyncGenerator);
107     multiAppStrategy_.RegisterStrategyChangeCallback([this] (const PolicyConfigData::StrategyConfig& strategy) {
108         DeliverRefreshRateVote({"VOTER_PACKAGES", strategy.min, strategy.max}, ADD_VOTE);
109         idleFps_ = std::max(strategy.min, static_cast<int32_t>(OLED_60_HZ));
110         HandleIdleEvent(true);
111     });
112     InitTouchManager();
113     multiAppStrategy_.CalcVote();
114 }
115 
RegisterCoreCallbacksAndInitController(sptr<VSyncController> rsController,sptr<VSyncController> appController,sptr<VSyncGenerator> vsyncGenerator)116 void HgmFrameRateManager::RegisterCoreCallbacksAndInitController(sptr<VSyncController> rsController,
117     sptr<VSyncController> appController, sptr<VSyncGenerator> vsyncGenerator)
118 {
119     if (rsController == nullptr || appController == nullptr) {
120         HGM_LOGE("HgmFrameRateManager::rsController or appController is nullptr");
121         return;
122     }
123     auto& hgmCore = HgmCore::Instance();
124     hgmCore.RegisterRefreshRateModeChangeCallback([rsController, appController](int32_t mode) {
125         if (HgmCore::Instance().IsLTPOSwitchOn()) {
126             rsController->SetPhaseOffset(0);
127             appController->SetPhaseOffset(0);
128             CreateVSyncGenerator()->SetVSyncMode(VSYNC_MODE_LTPO);
129         } else {
130             if (RSUniRenderJudgement::IsUniRender()) {
131                 int64_t offset = HgmCore::Instance().IsDelayMode() ?
132                     UNI_RENDER_VSYNC_OFFSET_DELAY_MODE : UNI_RENDER_VSYNC_OFFSET;
133                 rsController->SetPhaseOffset(offset);
134                 appController->SetPhaseOffset(offset);
135             }
136             CreateVSyncGenerator()->SetVSyncMode(VSYNC_MODE_LTPS);
137         }
138     });
139 
140     hgmCore.RegisterRefreshRateUpdateCallback([](int32_t refreshRate) {
141         HgmConfigCallbackManager::GetInstance()->SyncRefreshRateUpdateCallback(refreshRate);
142     });
143 
144     controller_ = std::make_shared<HgmVSyncGeneratorController>(rsController, appController, vsyncGenerator);
145 }
146 
InitTouchManager()147 void HgmFrameRateManager::InitTouchManager()
148 {
149     static std::once_flag createFlag;
150     std::call_once(createFlag, [this]() {
151         touchManager_.RegisterEventCallback(TouchEvent::UP_TIMEOUT_EVENT, [this] (TouchEvent event) {
152             SetSchedulerPreferredFps(OLED_60_HZ);
153             SetIsNeedUpdateAppOffset(true);
154             touchManager_.ChangeState(TouchState::IDLE_STATE);
155         });
156         touchManager_.RegisterEventCallback(TouchEvent::DOWN_EVENT, [this] (TouchEvent event) {
157             SetSchedulerPreferredFps(OLED_120_HZ);
158             touchManager_.ChangeState(TouchState::DOWN_STATE);
159         });
160         touchManager_.RegisterEnterStateCallback(TouchState::DOWN_STATE,
161             [this] (TouchState lastState, TouchState newState) {
162             if (lastState == TouchState::IDLE_STATE) {
163                 HgmMultiAppStrategy::TouchInfo touchInfo = {
164                     .pkgName = touchManager_.GetPkgName(),
165                     .touchState = newState,
166                     .upExpectFps = OLED_120_HZ,
167                 };
168                 multiAppStrategy_.HandleTouchInfo(touchInfo);
169             }
170             startCheck_.store(false);
171         });
172         touchManager_.RegisterEnterStateCallback(TouchState::IDLE_STATE,
173             [this] (TouchState lastState, TouchState newState) {
174             startCheck_.store(false);
175             HgmMultiAppStrategy::TouchInfo touchInfo = {
176                 .pkgName = touchManager_.GetPkgName(),
177                 .touchState = newState,
178             };
179             multiAppStrategy_.HandleTouchInfo(touchInfo);
180         });
181         touchManager_.RegisterEnterStateCallback(TouchState::UP_STATE,
182             [this] (TouchState lastState, TouchState newState) {
183             HgmTaskHandleThread::Instance().PostEvent(UP_TIME_OUT_TASK_ID, [this] () { startCheck_.store(true); },
184                 FIRST_FRAME_TIME_OUT);
185         });
186         touchManager_.RegisterExitStateCallback(TouchState::UP_STATE,
187             [this] (TouchState lastState, TouchState newState) {
188             HgmTaskHandleThread::Instance().RemoveEvent(UP_TIME_OUT_TASK_ID);
189             startCheck_.store(false);
190         });
191     });
192 }
193 
ProcessPendingRefreshRate(uint64_t timestamp,uint32_t rsRate,const DvsyncInfo & dvsyncInfo)194 void HgmFrameRateManager::ProcessPendingRefreshRate(uint64_t timestamp, uint32_t rsRate, const DvsyncInfo& dvsyncInfo)
195 {
196     auto &hgmCore = HgmCore::Instance();
197     hgmCore.SetTimestamp(timestamp);
198     if (pendingRefreshRate_ != nullptr) {
199         hgmCore.SetPendingConstraintRelativeTime(pendingConstraintRelativeTime_);
200         hgmCore.SetPendingScreenRefreshRate(*pendingRefreshRate_);
201         RS_TRACE_NAME_FMT("ProcessHgmFrameRate pendingRefreshRate: %d", *pendingRefreshRate_);
202         pendingRefreshRate_.reset();
203         pendingConstraintRelativeTime_ = 0;
204     }
205     if (curRefreshRateMode_ == HGM_REFRESHRATE_MODE_AUTO &&
206         dvsyncInfo.isUiDvsyncOn && GetCurScreenStrategyId().find("LTPO") != std::string::npos) {
207         RS_TRACE_NAME_FMT("ProcessHgmFrameRate pendingRefreshRate: %d ui-dvsync", rsRate);
208         hgmCore.SetPendingScreenRefreshRate(rsRate);
209     }
210 }
211 
UpdateSurfaceTime(const std::string & surfaceName,uint64_t timestamp,pid_t pid)212 void HgmFrameRateManager::UpdateSurfaceTime(const std::string& surfaceName, uint64_t timestamp,  pid_t pid)
213 {
214     idleDetector_.UpdateSurfaceTime(surfaceName, timestamp, pid);
215 }
216 
UpdateAppSupportedState()217 void HgmFrameRateManager::UpdateAppSupportedState()
218 {
219     bool appNeedHighRefresh = false;
220     idleDetector_.ClearAppBufferList();
221     idleDetector_.ClearAppBufferBlackList();
222     PolicyConfigData::StrategyConfig config;
223     if (multiAppStrategy_.GetFocusAppStrategyConfig(config) == EXEC_SUCCESS) {
224         if (config.dynamicMode == DynamicModeType::TOUCH_EXT_ENABLED) {
225             appNeedHighRefresh = true;
226         }
227     }
228     idleDetector_.UpdateAppBufferList(config.appBufferList);
229     idleDetector_.UpdateAppBufferBlackList(config.appBufferBlackList);
230     idleDetector_.SetAppSupportedState(appNeedHighRefresh);
231 }
232 
SetAceAnimatorVote(const std::shared_ptr<RSRenderFrameRateLinker> & linker,bool & needCheckAceAnimatorStatus)233 void HgmFrameRateManager::SetAceAnimatorVote(const std::shared_ptr<RSRenderFrameRateLinker>& linker,
234     bool& needCheckAceAnimatorStatus)
235 {
236     if (!needCheckAceAnimatorStatus || linker == nullptr) {
237         return;
238     }
239     if (linker->GetAceAnimatorExpectedFrameRate() >= 0) {
240         needCheckAceAnimatorStatus = false;
241         RS_TRACE_NAME_FMT("SetAceAnimatorVote PID = [%d]  linkerId = [%" PRIu64 "]  SetAceAnimatorIdleState[false] "
242             "AnimatorExpectedFrameRate = [%d]", ExtractPid(linker->GetId()), linker->GetId(),
243             linker->GetAceAnimatorExpectedFrameRate());
244         idleDetector_.SetAceAnimatorIdleState(false);
245         idleDetector_.UpdateAceAnimatorExpectedFrameRate(linker->GetAceAnimatorExpectedFrameRate());
246         return;
247     }
248     RS_OPTIONAL_TRACE_NAME_FMT("SetAceAnimatorVote PID = [%d]  linkerId = [%" PRIu64 "] "
249         "SetAceAnimatorIdleState[true] AnimatorExpectedFrameRate = [%d]", ExtractPid(linker->GetId()),
250         linker->GetId(), linker->GetAceAnimatorExpectedFrameRate());
251     idleDetector_.SetAceAnimatorIdleState(true);
252 }
253 
UpdateGuaranteedPlanVote(uint64_t timestamp)254 void HgmFrameRateManager::UpdateGuaranteedPlanVote(uint64_t timestamp)
255 {
256     if (!idleDetector_.GetAppSupportedState()) {
257         return;
258     }
259     RS_TRACE_NAME_FMT("HgmFrameRateManager:: TouchState = [%d]  SurFaceIdleStatus = [%d]  AceAnimatorIdleState = [%d]",
260         touchManager_.GetState(), idleDetector_.GetSurfaceIdleState(timestamp),
261         idleDetector_.GetAceAnimatorIdleState());
262 
263     // Wait touch up FIRST_FRAME_TIME_OUT ms
264     if (!startCheck_.load() || touchManager_.GetState() == TouchState::IDLE_STATE) {
265         needHighRefresh_ = false;
266         lastTouchUpExpectFps_ = 0;
267         return;
268     }
269 
270     // Check if needed third frame need high refresh
271     if (!needHighRefresh_) {
272         needHighRefresh_ = true;
273         if (!idleDetector_.ThirdFrameNeedHighRefresh()) {
274             touchManager_.HandleThirdFrameIdle();
275             return;
276         }
277     }
278 
279     //Third frame need high refresh vote
280     if (idleDetector_.GetSurfaceIdleState(timestamp) && idleDetector_.GetAceAnimatorIdleState()) {
281         RS_TRACE_NAME_FMT("UpdateGuaranteedPlanVote:: Surface And Animator Idle, Vote Idle");
282         touchManager_.HandleThirdFrameIdle();
283     } else {
284         int32_t currTouchUpExpectedFPS = idleDetector_.GetTouchUpExpectedFPS();
285         if (currTouchUpExpectedFPS == lastTouchUpExpectFps_) {
286             return;
287         }
288 
289         lastTouchUpExpectFps_ = currTouchUpExpectedFPS;
290         HgmMultiAppStrategy::TouchInfo touchInfo = {
291             .touchState = TouchState::UP_STATE,
292             .upExpectFps = currTouchUpExpectedFPS,
293         };
294         multiAppStrategy_.HandleTouchInfo(touchInfo);
295     }
296 }
297 
ProcessLtpoVote(const FrameRateRange & finalRange,bool idleTimerExpired)298 void HgmFrameRateManager::ProcessLtpoVote(const FrameRateRange& finalRange, bool idleTimerExpired)
299 {
300     if (finalRange.IsValid()) {
301         ResetScreenTimer(curScreenId_);
302         CalcRefreshRate(curScreenId_, finalRange);
303         DeliverRefreshRateVote(
304             {"VOTER_LTPO", currRefreshRate_, currRefreshRate_, DEFAULT_PID, finalRange.GetExtInfo()}, ADD_VOTE);
305     } else if (idleTimerExpired) {
306         // idle in ltpo
307         HandleIdleEvent(ADD_VOTE);
308         DeliverRefreshRateVote({"VOTER_LTPO"}, REMOVE_VOTE);
309     } else {
310         StartScreenTimer(curScreenId_, IDLE_TIMER_EXPIRED, nullptr, [this]() {
311             if (forceUpdateCallback_ != nullptr) {
312                 forceUpdateCallback_(true, false);
313             }
314         });
315     }
316 }
317 
UniProcessDataForLtpo(uint64_t timestamp,std::shared_ptr<RSRenderFrameRateLinker> rsFrameRateLinker,const FrameRateLinkerMap & appFrameRateLinkers,bool idleTimerExpired,const DvsyncInfo & dvsyncInfo)318 void HgmFrameRateManager::UniProcessDataForLtpo(uint64_t timestamp,
319                                                 std::shared_ptr<RSRenderFrameRateLinker> rsFrameRateLinker,
320                                                 const FrameRateLinkerMap& appFrameRateLinkers, bool idleTimerExpired,
321                                                 const DvsyncInfo& dvsyncInfo)
322 {
323     RS_TRACE_FUNC();
324     Reset();
325 
326     auto& hgmCore = HgmCore::Instance();
327     FrameRateRange finalRange;
328     if (curRefreshRateMode_ == HGM_REFRESHRATE_MODE_AUTO) {
329         finalRange = rsFrameRateLinker->GetExpectedRange();
330         bool needCheckAceAnimatorStatus = true;
331         for (auto linker : appFrameRateLinkers) {
332             if (!multiAppStrategy_.CheckPidValid(ExtractPid(linker.first))) {
333                 continue;
334             }
335             SetAceAnimatorVote(linker.second, needCheckAceAnimatorStatus);
336             auto expectedRange = linker.second->GetExpectedRange();
337             HgmEnergyConsumptionPolicy::Instance().GetUiIdleFps(expectedRange);
338             finalRange.Merge(expectedRange);
339         }
340         ProcessLtpoVote(finalRange, idleTimerExpired);
341     }
342 
343     UpdateGuaranteedPlanVote(timestamp);
344     idleDetector_.ResetAceAnimatorExpectedFrameRate();
345     VoteInfo resultVoteInfo = ProcessRefreshRateVote();
346     // max used here
347     finalRange = {resultVoteInfo.max, resultVoteInfo.max, resultVoteInfo.max};
348     CalcRefreshRate(curScreenId_, finalRange);
349 
350     bool frameRateChanged = CollectFrameRateChange(finalRange, rsFrameRateLinker, appFrameRateLinkers);
351     if (hgmCore.GetLtpoEnabled() && frameRateChanged) {
352         HandleFrameRateChangeForLTPO(timestamp);
353     } else {
354         pendingRefreshRate_ = std::make_shared<uint32_t>(currRefreshRate_);
355         if (currRefreshRate_ != hgmCore.GetPendingScreenRefreshRate()) {
356             if (forceUpdateCallback_ != nullptr) {
357                 forceUpdateCallback_(false, true);
358             }
359             schedulePreferredFpsChange_ = true;
360         }
361         FrameRateReport();
362     }
363     ReportHiSysEvent(resultVoteInfo);
364     lastVoteInfo_ = resultVoteInfo;
365 }
366 
ReportHiSysEvent(const VoteInfo & frameRateVoteInfo)367 void HgmFrameRateManager::ReportHiSysEvent(const VoteInfo& frameRateVoteInfo)
368 {
369     if (frameRateVoteInfo.voterName.empty()) {
370         return;
371     }
372     std::lock_guard<std::mutex> locker(frameRateVoteInfoMutex_);
373     bool needAdd = frameRateVoteInfoVec_.empty() || frameRateVoteInfoVec_.back().second != frameRateVoteInfo;
374     if (frameRateVoteInfoVec_.size() >= REPORT_VOTER_INFO_LIMIT) {
375         std::string msg;
376         for (auto& [timestamp, voteInfo] : frameRateVoteInfoVec_) {
377             msg += voteInfo.ToString(timestamp);
378         }
379         HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::GRAPHIC, "HGM_VOTER_INFO",
380             OHOS::HiviewDFX::HiSysEvent::EventType::STATISTIC, "MSG", msg);
381         frameRateVoteInfoVec_.clear();
382     }
383     if (needAdd) {
384         auto currentTime = std::chrono::time_point_cast<std::chrono::milliseconds>(
385             std::chrono::system_clock::now()).time_since_epoch().count();
386         frameRateVoteInfoVec_.push_back({currentTime, frameRateVoteInfo});
387         HGM_LOGD("ReportHiSysEvent: %{public}s", frameRateVoteInfo.ToString(currentTime).c_str());
388     }
389 }
390 
UniProcessDataForLtps(bool idleTimerExpired)391 void HgmFrameRateManager::UniProcessDataForLtps(bool idleTimerExpired)
392 {
393     RS_TRACE_FUNC();
394     Reset();
395 
396     if (idleTimerExpired) {
397         // idle in ltps
398         HandleIdleEvent(ADD_VOTE);
399     } else {
400         StartScreenTimer(curScreenId_, IDLE_TIMER_EXPIRED, nullptr, [this]() {
401             if (forceUpdateCallback_ != nullptr) {
402                 forceUpdateCallback_(true, false);
403             }
404         });
405     }
406 
407     FrameRateRange finalRange;
408     VoteInfo resultVoteInfo = ProcessRefreshRateVote();
409     auto& hgmCore = HgmCore::Instance();
410     // max used here
411     finalRange = {resultVoteInfo.max, resultVoteInfo.max, resultVoteInfo.max};
412     CalcRefreshRate(curScreenId_, finalRange);
413     RS_TRACE_INT("PreferredFrameRate", static_cast<int>(currRefreshRate_));
414     pendingRefreshRate_ = std::make_shared<uint32_t>(currRefreshRate_);
415     if (currRefreshRate_ != hgmCore.GetPendingScreenRefreshRate()) {
416         if (forceUpdateCallback_ != nullptr) {
417             forceUpdateCallback_(false, true);
418         }
419         schedulePreferredFpsChange_ = true;
420     }
421     FrameRateReport();
422     ReportHiSysEvent(resultVoteInfo);
423     lastVoteInfo_ = resultVoteInfo;
424 }
425 
FrameRateReport()426 void HgmFrameRateManager::FrameRateReport()
427 {
428     if (!schedulePreferredFpsChange_) {
429         return;
430     }
431     std::unordered_map<pid_t, uint32_t> rates;
432     rates[GetRealPid()] = currRefreshRate_;
433     if (curRefreshRateMode_ != HGM_REFRESHRATE_MODE_AUTO) {
434         rates[UNI_APP_PID] = currRefreshRate_;
435     } else if (schedulePreferredFps_ == OLED_60_HZ && currRefreshRate_ == OLED_60_HZ) {
436         rates[UNI_APP_PID] = OLED_60_HZ;
437     } else {
438         rates[UNI_APP_PID] = OLED_120_HZ;
439     }
440     HGM_LOGD("FrameRateReport: RS(%{public}d) = %{public}d, APP(%{public}d) = %{public}d",
441         GetRealPid(), rates[GetRealPid()], UNI_APP_PID, rates[UNI_APP_PID]);
442     FRAME_TRACE::FrameRateReport::GetInstance().SendFrameRates(rates);
443     FRAME_TRACE::FrameRateReport::GetInstance().SendFrameRatesToRss(rates);
444     schedulePreferredFpsChange_ = false;
445 }
446 
CollectFrameRateChange(FrameRateRange finalRange,std::shared_ptr<RSRenderFrameRateLinker> rsFrameRateLinker,const FrameRateLinkerMap & appFrameRateLinkers)447 bool HgmFrameRateManager::CollectFrameRateChange(FrameRateRange finalRange,
448                                                  std::shared_ptr<RSRenderFrameRateLinker> rsFrameRateLinker,
449                                                  const FrameRateLinkerMap& appFrameRateLinkers)
450 {
451     if (controller_ == nullptr) {
452         HGM_LOGE("no valid controller, cannot work correctly, maybe Init() wasn't executed correctly.");
453         return false;
454     }
455     bool frameRateChanged = false;
456     bool controllerRateChanged = false;
457     auto rsFrameRate = GetDrawingFrameRate(currRefreshRate_, finalRange);
458     controllerRate_ = rsFrameRate > 0 ? rsFrameRate : controller_->GetCurrentRate();
459     if (controllerRate_ != controller_->GetCurrentRate()) {
460         rsFrameRateLinker->SetFrameRate(controllerRate_);
461         controllerRateChanged = true;
462         frameRateChanged = true;
463     }
464 
465     auto& hgmCore = HgmCore::Instance();
466     auto screenCurrentRefreshRate = hgmCore.GetScreenCurrentRefreshRate(hgmCore.GetActiveScreenId());
467     RS_TRACE_NAME_FMT("CollectFrameRateChange refreshRate: %d, rsFrameRate: %d, finalRange = (%d, %d, %d)",
468         screenCurrentRefreshRate, rsFrameRate, finalRange.min_, finalRange.max_, finalRange.preferred_);
469     RS_TRACE_INT("PreferredFrameRate", static_cast<int>(finalRange.preferred_));
470 
471     for (auto linker : appFrameRateLinkers) {
472         if (linker.second == nullptr) {
473             continue;
474         }
475         const auto& expectedRange = linker.second->GetExpectedRange();
476         auto appFrameRate = GetDrawingFrameRate(currRefreshRate_, expectedRange);
477         if (touchManager_.GetState() != TouchState::IDLE_STATE) {
478             appFrameRate = OLED_NULL_HZ;
479         }
480         if (appFrameRate != linker.second->GetFrameRate() || controllerRateChanged) {
481             linker.second->SetFrameRate(appFrameRate);
482             std::lock_guard<std::mutex> lock(appChangeDataMutex_);
483             appChangeData_.emplace_back(linker.second->GetId(), appFrameRate);
484             HGM_LOGD("HgmFrameRateManager: appChangeData linkerId = %{public}" PRIu64 ", %{public}d",
485                 linker.second->GetId(), appFrameRate);
486             frameRateChanged = true;
487         }
488         if (expectedRange.min_ == OLED_NULL_HZ && expectedRange.max_ == OLED_144_HZ &&
489             expectedRange.preferred_ == OLED_NULL_HZ) {
490             continue;
491         }
492         RS_TRACE_NAME_FMT("HgmFrameRateManager::UniProcessData multiAppFrameRate: pid = %d, linkerId = %ld, "\
493             "appFrameRate = %d, appRange = (%d, %d, %d)", ExtractPid(linker.first), linker.second->GetId(),
494             appFrameRate, expectedRange.min_, expectedRange.max_, expectedRange.preferred_);
495     }
496     return frameRateChanged;
497 }
498 
HandleFrameRateChangeForLTPO(uint64_t timestamp)499 void HgmFrameRateManager::HandleFrameRateChangeForLTPO(uint64_t timestamp)
500 {
501     auto& hgmCore = HgmCore::Instance();
502     auto lastRefreshRate = hgmCore.GetPendingScreenRefreshRate();
503     uint64_t targetTime = 0;
504     // low refresh rate switch to high refresh rate immediately.
505     if (lastRefreshRate < OLED_60_HZ && currRefreshRate_ > lastRefreshRate) {
506         hgmCore.SetPendingScreenRefreshRate(currRefreshRate_);
507         hgmCore.SetScreenRefreshRateImme(currRefreshRate_);
508         if (hgmCore.IsLowRateToHighQuickEnabled() && controller_) {
509             targetTime = controller_->CalcVSyncQuickTriggerTime(timestamp, lastRefreshRate);
510             if (targetTime > timestamp && targetTime > 0) {
511                 pendingConstraintRelativeTime_ = targetTime - timestamp;
512             } else {
513                 pendingConstraintRelativeTime_ = 0;
514             }
515             hgmCore.SetPendingConstraintRelativeTime(pendingConstraintRelativeTime_);
516             pendingConstraintRelativeTime_ = 0;
517         }
518     }
519 
520     RSTaskMessage::RSTask task = [this, lastRefreshRate, targetTime]() {
521         std::lock_guard<std::mutex> lock(appChangeDataMutex_);
522         if (controller_) {
523             controller_->ChangeGeneratorRate(controllerRate_, appChangeData_, targetTime, isNeedUpdateAppOffset_);
524         }
525         isNeedUpdateAppOffset_ = false;
526         pendingRefreshRate_ = std::make_shared<uint32_t>(currRefreshRate_);
527         if (currRefreshRate_ != lastRefreshRate) {
528             if (forceUpdateCallback_ != nullptr) {
529                 forceUpdateCallback_(false, true);
530             }
531             schedulePreferredFpsChange_ = true;
532         }
533         FrameRateReport();
534     };
535     HgmTaskHandleThread::Instance().PostTask(task);
536 }
537 
CalcRefreshRate(const ScreenId id,const FrameRateRange & range)538 void HgmFrameRateManager::CalcRefreshRate(const ScreenId id, const FrameRateRange& range)
539 {
540     // Find current refreshRate by FrameRateRange. For example:
541     // 1. FrameRateRange[min, max, preferred] is [24, 48, 48], supported refreshRates
542     // of current screen are {30, 60, 90}, the result should be 30, not 60.
543     // 2. FrameRateRange[min, max, preferred] is [150, 150, 150], supported refreshRates
544     // of current screen are {30, 60, 90}, the result will be 90.
545     auto supportRefreshRateVec = HgmCore::Instance().GetScreenSupportedRefreshRates(id);
546     if (supportRefreshRateVec.empty()) {
547         return;
548     }
549     std::sort(supportRefreshRateVec.begin(), supportRefreshRateVec.end());
550     auto iter = std::lower_bound(supportRefreshRateVec.begin(), supportRefreshRateVec.end(), range.preferred_);
551     if (iter != supportRefreshRateVec.end()) {
552         currRefreshRate_ = *iter;
553         if (currRefreshRate_ > static_cast<uint32_t>(range.max_) &&
554             (iter - supportRefreshRateVec.begin()) > 0) {
555             iter--;
556             if (*iter >= static_cast<uint32_t>(range.min_) &&
557                 *iter <= static_cast<uint32_t>(range.max_)) {
558                 currRefreshRate_ = *iter;
559             }
560         }
561     } else {
562         currRefreshRate_ = supportRefreshRateVec.back();
563     }
564 }
565 
GetDrawingFrameRate(const uint32_t refreshRate,const FrameRateRange & range)566 uint32_t HgmFrameRateManager::GetDrawingFrameRate(const uint32_t refreshRate, const FrameRateRange& range)
567 {
568     // We will find a drawing fps, which is divisible by refreshRate.
569     // If the refreshRate is 60, the options of drawing fps are 60, 30, 15, 12, etc.
570     // 1. The preferred fps is divisible by refreshRate.
571     const float currRefreshRate = static_cast<float>(refreshRate);
572     const float preferredFps = static_cast<float>(range.preferred_);
573     if (preferredFps < MARGIN || currRefreshRate < MARGIN) {
574         return 0;
575     }
576     if (std::fmodf(currRefreshRate, range.preferred_) < MARGIN) {
577         return static_cast<uint32_t>(preferredFps);
578     }
579     // 2. FrameRateRange is not dynamic, we will find the closest drawing fps to preferredFps.
580     // e.g. If the FrameRateRange of a surfaceNode is [50, 50, 50], the refreshRate is
581     // 90, the drawing fps of the surfaceNode should be 45.
582     if (!range.IsDynamic()) {
583         return static_cast<uint32_t>(currRefreshRate / std::round(refreshRate / preferredFps));
584     }
585     // 3. FrameRateRange is dynamic. We will find a divisible result in the range if possible.
586     // If several divisible options are in the range, the smoother, the better.
587     // The KPI of "smooth" is the ratio of lack.
588     // e.g. The preferred fps is 58, the refreshRate is 60. When the drawing fps is 60,
589     // we lack the least(the ratio is 2/60).
590     // The preferred fps is 34, the refreshRate is 60, the drawing fps will be 30(the ratio is 4/30).
591     int divisor = 1;
592     float drawingFps = currRefreshRate;
593     float dividedFps = currRefreshRate;
594     float currRatio = std::abs(dividedFps - preferredFps) / preferredFps;
595     float ratio = currRatio;
596     const float minDrawingFps = currRefreshRate / MIN_DRAWING_DIVISOR;
597     while (dividedFps > minDrawingFps - MARGIN) {
598         if (dividedFps < range.min_ || dividedFps <= static_cast<float>(range.preferred_) / DIVISOR_TWO) {
599             break;
600         }
601         if (dividedFps > range.max_) {
602             divisor++;
603             float preDividedFps = dividedFps;
604             dividedFps = currRefreshRate / static_cast<float>(divisor);
605             // If we cannot find a divisible result, the closer to the preferred, the better.
606             // e.g.FrameRateRange is [50, 80, 80], refreshrate is
607             // 90, the drawing frame rate is 90.
608             if (dividedFps < range.min_ && (preferredFps - dividedFps) > (preDividedFps - preferredFps)) {
609                 drawingFps = preDividedFps;
610                 break;
611             }
612             currRatio = std::abs(dividedFps - preferredFps) / preferredFps;
613             if (currRatio < ratio) {
614                 ratio = currRatio;
615                 drawingFps = dividedFps;
616             }
617             continue;
618         }
619         currRatio = std::min(std::fmodf(preferredFps, dividedFps),
620             std::fmodf(std::abs(dividedFps - preferredFps), dividedFps)) / dividedFps;
621         // When currRatio is almost zero, dividedFps is the perfect result
622         if (currRatio < MARGIN) {
623             drawingFps = dividedFps;
624             break;
625         }
626         if (currRatio < ratio) {
627             ratio = currRatio;
628             drawingFps = dividedFps;
629         }
630         divisor++;
631         dividedFps = currRefreshRate / static_cast<float>(divisor);
632     }
633     return static_cast<uint32_t>(std::round(drawingFps));
634 }
635 
GetPendingRefreshRate()636 std::shared_ptr<uint32_t> HgmFrameRateManager::GetPendingRefreshRate()
637 {
638     return pendingRefreshRate_;
639 }
640 
ResetPendingRefreshRate()641 void HgmFrameRateManager::ResetPendingRefreshRate()
642 {
643     pendingRefreshRate_.reset();
644 }
645 
Reset()646 void HgmFrameRateManager::Reset()
647 {
648     currRefreshRate_ = 0;
649     controllerRate_ = 0;
650     pendingConstraintRelativeTime_ = 0;
651     pendingRefreshRate_.reset();
652 
653     std::lock_guard<std::mutex> lock(appChangeDataMutex_);
654     appChangeData_.clear();
655 }
656 
GetExpectedFrameRate(const RSPropertyUnit unit,float velocity) const657 int32_t HgmFrameRateManager::GetExpectedFrameRate(const RSPropertyUnit unit, float velocity) const
658 {
659     switch (unit) {
660         case RSPropertyUnit::PIXEL_POSITION:
661             return GetPreferredFps("translate", PixelToMM(velocity));
662         case RSPropertyUnit::PIXEL_SIZE:
663         case RSPropertyUnit::RATIO_SCALE:
664             return GetPreferredFps("scale", PixelToMM(velocity));
665         case RSPropertyUnit::ANGLE_ROTATION:
666             return GetPreferredFps("rotation", PixelToMM(velocity));
667         default:
668             return 0;
669     }
670 }
671 
GetPreferredFps(const std::string & type,float velocity) const672 int32_t HgmFrameRateManager::GetPreferredFps(const std::string& type, float velocity) const
673 {
674     auto &configData = HgmCore::Instance().GetPolicyConfigData();
675     if (!configData) {
676         return 0;
677     }
678     if (ROSEN_EQ(velocity, 0.f)) {
679         return 0;
680     }
681     const std::string settingMode = std::to_string(curRefreshRateMode_);
682     if (configData->screenConfigs_.count(curScreenStrategyId_) &&
683         configData->screenConfigs_[curScreenStrategyId_].count(settingMode) &&
684         configData->screenConfigs_[curScreenStrategyId_][settingMode].animationDynamicSettings.count(type)) {
685         auto& config = configData->screenConfigs_[curScreenStrategyId_][settingMode].animationDynamicSettings[type];
686         auto iter = std::find_if(config.begin(), config.end(), [&velocity](const auto& pair) {
687             return velocity >= pair.second.min && (velocity < pair.second.max || pair.second.max == -1);
688         });
689         if (iter != config.end()) {
690             RS_OPTIONAL_TRACE_NAME_FMT("GetPreferredFps: type: %s, speed: %f, rate: %d",
691                 type.c_str(), velocity, iter->second.preferred_fps);
692             return iter->second.preferred_fps;
693         }
694     }
695     return 0;
696 }
697 
PixelToMM(float velocity)698 float HgmFrameRateManager::PixelToMM(float velocity)
699 {
700     float velocityMM = 0.0f;
701     auto& hgmCore = HgmCore::Instance();
702     sptr<HgmScreen> hgmScreen = hgmCore.GetScreen(hgmCore.GetActiveScreenId());
703     if (hgmScreen && hgmScreen->GetPpi() > 0.f) {
704         velocityMM = velocity / hgmScreen->GetPpi() * INCH_2_MM;
705     }
706     return velocityMM;
707 }
708 
GetScreenTimer(ScreenId screenId) const709 std::shared_ptr<HgmOneShotTimer> HgmFrameRateManager::GetScreenTimer(ScreenId screenId) const
710 {
711     if (auto timer = screenTimerMap_.find(screenId); timer != screenTimerMap_.end()) {
712         return timer->second;
713     }
714     return nullptr;
715 }
716 
StartScreenTimer(ScreenId screenId,int32_t interval,std::function<void ()> resetCallback,std::function<void ()> expiredCallback)717 void HgmFrameRateManager::StartScreenTimer(ScreenId screenId, int32_t interval,
718     std::function<void()> resetCallback, std::function<void()> expiredCallback)
719 {
720     if (auto oldtimer = GetScreenTimer(screenId); oldtimer == nullptr) {
721         auto newTimer = std::make_shared<HgmOneShotTimer>("idle_timer" + std::to_string(screenId),
722             std::chrono::milliseconds(interval), resetCallback, expiredCallback);
723         screenTimerMap_[screenId] = newTimer;
724         newTimer->Start();
725     }
726 }
727 
ResetScreenTimer(ScreenId screenId) const728 void HgmFrameRateManager::ResetScreenTimer(ScreenId screenId) const
729 {
730     if (auto timer = GetScreenTimer(screenId); timer != nullptr) {
731         timer->Reset();
732     }
733 }
734 
StopScreenTimer(ScreenId screenId)735 void HgmFrameRateManager::StopScreenTimer(ScreenId screenId)
736 {
737     if (auto timer = screenTimerMap_.find(screenId); timer != screenTimerMap_.end()) {
738         screenTimerMap_.erase(timer);
739     }
740 }
741 
HandleLightFactorStatus(pid_t pid,bool isSafe)742 void HgmFrameRateManager::HandleLightFactorStatus(pid_t pid, bool isSafe)
743 {
744     // based on the light determine whether allowed to reduce the screen refresh rate to avoid screen flicker
745     HGM_LOGI("HandleLightFactorStatus status:%{public}u", isSafe);
746     if (pid != DEFAULT_PID) {
747         std::lock_guard<std::mutex> lock(cleanPidCallbackMutex_);
748         cleanPidCallback_[pid].insert(CleanPidCallbackType::LIGHT_FACTOR);
749     }
750     HgmTaskHandleThread::Instance().PostTask([this, isSafeParam = isSafe] () {
751         multiAppStrategy_.HandleLightFactorStatus(isSafeParam);
752     });
753 }
754 
HandlePackageEvent(pid_t pid,const std::vector<std::string> & packageList)755 void HgmFrameRateManager::HandlePackageEvent(pid_t pid, const std::vector<std::string>& packageList)
756 {
757     if (pid != DEFAULT_PID) {
758         std::lock_guard<std::mutex> lock(cleanPidCallbackMutex_);
759         cleanPidCallback_[pid].insert(CleanPidCallbackType::PACKAGE_EVENT);
760     }
761     HgmTaskHandleThread::Instance().PostTask([this, packageList] () {
762         if (multiAppStrategy_.HandlePkgsEvent(packageList) == EXEC_SUCCESS) {
763             std::lock_guard<std::mutex> locker(pkgSceneMutex_);
764             sceneStack_.clear();
765         }
766         UpdateAppSupportedState();
767     });
768 }
769 
HandleRefreshRateEvent(pid_t pid,const EventInfo & eventInfo)770 void HgmFrameRateManager::HandleRefreshRateEvent(pid_t pid, const EventInfo& eventInfo)
771 {
772     std::string eventName = eventInfo.eventName;
773     std::lock_guard<std::mutex> lock(voteNameMutex_);
774     auto event = std::find(voters_.begin(), voters_.end(), eventName);
775     if (event == voters_.end()) {
776         HGM_LOGW("HgmFrameRateManager:unknown event, eventName is %{public}s", eventName.c_str());
777         return;
778     }
779 
780     HGM_LOGI("%{public}s(%{public}d) %{public}s", eventName.c_str(), pid, eventInfo.description.c_str());
781     if (eventName == "VOTER_SCENE") {
782         HandleSceneEvent(pid, eventInfo);
783     } else if (eventName == "VOTER_VIRTUALDISPLAY") {
784         HandleVirtualDisplayEvent(pid, eventInfo);
785     } else if (eventName == "VOTER_GAMES") {
786         HandleGamesEvent(pid, eventInfo);
787     } else {
788         DeliverRefreshRateVote({eventName, eventInfo.minRefreshRate, eventInfo.maxRefreshRate, pid},
789             eventInfo.eventStatus);
790     }
791 }
792 
HandleTouchEvent(pid_t pid,int32_t touchStatus,int32_t touchCnt)793 void HgmFrameRateManager::HandleTouchEvent(pid_t pid, int32_t touchStatus, int32_t touchCnt)
794 {
795     HGM_LOGD("HandleTouchEvent status:%{public}d", touchStatus);
796     if (pid != DEFAULT_PID) {
797         std::lock_guard<std::mutex> lock(cleanPidCallbackMutex_);
798         cleanPidCallback_[pid].insert(CleanPidCallbackType::TOUCH_EVENT);
799     }
800 
801     static std::mutex hgmTouchEventMutex;
802     std::unique_lock<std::mutex> eventLock(hgmTouchEventMutex);
803     if (touchStatus == TOUCH_DOWN || touchStatus == TOUCH_PULL_DOWN) {
804         HGM_LOGI("[touch manager] down");
805         PolicyConfigData::StrategyConfig strategyRes;
806         ExitEnergyConsumptionAssuranceMode();
807         if (multiAppStrategy_.GetFocusAppStrategyConfig(strategyRes) == EXEC_SUCCESS &&
808             strategyRes.dynamicMode != DynamicModeType::TOUCH_DISENABLED) {
809                 touchManager_.HandleTouchEvent(TouchEvent::DOWN_EVENT, "");
810         }
811     } else if (touchStatus == TOUCH_UP || touchStatus == TOUCH_PULL_UP) {
812         if (touchCnt != LAST_TOUCH_CNT) {
813             return;
814         }
815         std::lock_guard<std::mutex> lock(voteMutex_);
816         if (auto iter = voteRecord_.find("VOTER_GAMES"); iter != voteRecord_.end() && !iter->second.empty() &&
817             gameScenes_.empty() && multiAppStrategy_.CheckPidValid(iter->second.front().pid)) {
818             HGM_LOGI("[touch manager] keep down in games");
819             return;
820         }
821         if (touchCnt == LAST_TOUCH_CNT) {
822             HGM_LOGI("[touch manager] up");
823             EnterEnergyConsumptionAssuranceMode();
824             touchManager_.HandleTouchEvent(TouchEvent::UP_EVENT, "");
825         }
826     } else {
827         HGM_LOGD("[touch manager] other touch status not support");
828     }
829 }
830 
HandleDynamicModeEvent(bool enableDynamicModeEvent)831 void HgmFrameRateManager::HandleDynamicModeEvent(bool enableDynamicModeEvent)
832 {
833     HGM_LOGE("HandleDynamicModeEvent status:%{public}u", enableDynamicModeEvent);
834     HgmCore::Instance().SetEnableDynamicMode(enableDynamicModeEvent);
835     multiAppStrategy_.CalcVote();
836 }
837 
HandleIdleEvent(bool isIdle)838 void HgmFrameRateManager::HandleIdleEvent(bool isIdle)
839 {
840     if (isIdle) {
841         HGM_LOGD("HandleIdleEvent status:%{public}u", isIdle);
842         DeliverRefreshRateVote({"VOTER_IDLE", idleFps_, idleFps_}, ADD_VOTE);
843     } else {
844         DeliverRefreshRateVote({"VOTER_IDLE"}, REMOVE_VOTE);
845     }
846 }
847 
HandleRefreshRateMode(int32_t refreshRateMode)848 void HgmFrameRateManager::HandleRefreshRateMode(int32_t refreshRateMode)
849 {
850     HGM_LOGI("HandleRefreshRateMode curMode:%{public}d", refreshRateMode);
851     if (curRefreshRateMode_ == refreshRateMode) {
852         return;
853     }
854 
855     curRefreshRateMode_ = refreshRateMode;
856     DeliverRefreshRateVote({"VOTER_LTPO"}, REMOVE_VOTE);
857     multiAppStrategy_.UpdateXmlConfigCache();
858     UpdateEnergyConsumptionConfig();
859     multiAppStrategy_.CalcVote();
860     HgmCore::Instance().SetLtpoConfig();
861     schedulePreferredFpsChange_ = true;
862     FrameRateReport();
863     HgmConfigCallbackManager::GetInstance()->SyncHgmConfigChangeCallback();
864 }
865 
HandleScreenPowerStatus(ScreenId id,ScreenPowerStatus status)866 void HgmFrameRateManager::HandleScreenPowerStatus(ScreenId id, ScreenPowerStatus status)
867 {
868     // hgm warning: strategy for screen off
869     HGM_LOGI("curScreen:%{public}d status:%{public}d", static_cast<int>(id), static_cast<int>(status));
870     if (status == ScreenPowerStatus::POWER_STATUS_ON) {
871         ReportHiSysEvent({.voterName = "SCREEN_POWER", .extInfo = "ON"});
872     } else if (status == ScreenPowerStatus::POWER_STATUS_SUSPEND) {
873         ReportHiSysEvent({.voterName = "SCREEN_POWER", .extInfo = "OFF"});
874     }
875     static std::mutex lastScreenIdMutex;
876     std::unique_lock<std::mutex> lock(lastScreenIdMutex);
877     static ScreenId lastScreenId = 12345; // init value diff with any real screen id
878     if (status != ScreenPowerStatus::POWER_STATUS_ON || lastScreenId == id) {
879         return;
880     }
881     lastScreenId = id;
882 
883     auto& hgmCore = HgmCore::Instance();
884     auto screenList = hgmCore.GetScreenIds();
885     auto screenPos = find(screenList.begin(), screenList.end(), id);
886     auto lastCurScreenId = curScreenId_;
887     curScreenId_ = (screenPos == screenList.end()) ? 0 : id;
888     if (lastCurScreenId == curScreenId_) {
889         return;
890     }
891     HGM_LOGI("HandleScreenPowerStatus curScreen:%{public}d", static_cast<int>(curScreenId_));
892     auto& hgmScreenInfo = HgmScreenInfo::GetInstance();
893     isLtpo_ = hgmScreenInfo.IsLtpoType(hgmScreenInfo.GetScreenType(curScreenId_));
894     std::string curScreenName = "screen" + std::to_string(curScreenId_) + "_" + (isLtpo_ ? "LTPO" : "LTPS");
895 
896     auto configData = hgmCore.GetPolicyConfigData();
897     if (configData != nullptr) {
898         if (configData->screenStrategyConfigs_.find(curScreenName) != configData->screenStrategyConfigs_.end()) {
899             curScreenStrategyId_ = configData->screenStrategyConfigs_[curScreenName];
900         }
901         if (curScreenStrategyId_.empty()) {
902             curScreenStrategyId_ = "LTPO-DEFAULT";
903         }
904         multiAppStrategy_.UpdateXmlConfigCache();
905         UpdateEnergyConsumptionConfig();
906     }
907 
908     multiAppStrategy_.CalcVote();
909     hgmCore.SetLtpoConfig();
910     MarkVoteChange();
911     schedulePreferredFpsChange_ = true;
912     FrameRateReport();
913     HgmConfigCallbackManager::GetInstance()->SyncHgmConfigChangeCallback();
914 
915     // hgm warning: use !isLtpo_ instead after GetDisplaySupportedModes ready
916     if (curScreenStrategyId_.find("LTPO") == std::string::npos) {
917         DeliverRefreshRateVote({"VOTER_LTPO"}, REMOVE_VOTE);
918     }
919 }
920 
HandleSceneEvent(pid_t pid,EventInfo eventInfo)921 void HgmFrameRateManager::HandleSceneEvent(pid_t pid, EventInfo eventInfo)
922 {
923     std::string sceneName = eventInfo.description;
924     auto screenSetting = multiAppStrategy_.GetScreenSetting();
925     auto &gameSceneList = screenSetting.gameSceneList;
926     auto &ancoSceneList = screenSetting.ancoSceneList;
927 
928     std::lock_guard<std::mutex> locker(pkgSceneMutex_);
929     std::lock_guard<std::mutex> lock(voteMutex_);
930     if (gameSceneList.find(sceneName) != gameSceneList.end()) {
931         if (eventInfo.eventStatus == ADD_VOTE) {
932             if (gameScenes_.insert(sceneName).second) {
933                 MarkVoteChange();
934             }
935         } else {
936             if (gameScenes_.erase(sceneName)) {
937                 MarkVoteChange();
938             }
939         }
940     }
941     if (ancoSceneList.find(sceneName) != ancoSceneList.end()) {
942         if (eventInfo.eventStatus == ADD_VOTE) {
943             if (ancoScenes_.insert(sceneName).second) {
944                 MarkVoteChange();
945             }
946         } else {
947             if (ancoScenes_.erase(sceneName)) {
948                 MarkVoteChange();
949             }
950         }
951     }
952 
953     std::pair<std::string, pid_t> info = std::make_pair(sceneName, pid);
954     auto scenePos = find(sceneStack_.begin(), sceneStack_.end(), info);
955     if (eventInfo.eventStatus == ADD_VOTE) {
956         if (scenePos == sceneStack_.end()) {
957             sceneStack_.push_back(info);
958             MarkVoteChange();
959         }
960     } else {
961         if (scenePos != sceneStack_.end()) {
962             sceneStack_.erase(scenePos);
963             MarkVoteChange();
964         }
965     }
966 }
967 
HandleVirtualDisplayEvent(pid_t pid,EventInfo eventInfo)968 void HgmFrameRateManager::HandleVirtualDisplayEvent(pid_t pid, EventInfo eventInfo)
969 {
970     std::string virtualDisplayName = eventInfo.description;
971     auto configData = HgmCore::Instance().GetPolicyConfigData();
972     if (configData == nullptr || !configData->virtualDisplaySwitch_) {
973         // disable vote from virtual display in xml
974         return;
975     }
976 
977     auto virtualDisplayConfig = configData->virtualDisplayConfigs_;
978     if (virtualDisplayConfig.count(virtualDisplayName) == 0 ||
979         configData->strategyConfigs_.count(virtualDisplayConfig[virtualDisplayName]) == 0) {
980         HGM_LOGW("HandleVirtualDisplayEvent:unknow virtual display [%{public}s]", virtualDisplayName.c_str());
981         DeliverRefreshRateVote({"VOTER_VIRTUALDISPLAY", OLED_60_HZ, OLED_60_HZ, pid}, eventInfo.eventStatus);
982     } else {
983         auto curStrategy = configData->strategyConfigs_[virtualDisplayConfig[virtualDisplayName]];
984         DeliverRefreshRateVote({"VOTER_VIRTUALDISPLAY", curStrategy.min, curStrategy.max, pid}, ADD_VOTE);
985     }
986 }
987 
HandleGamesEvent(pid_t pid,EventInfo eventInfo)988 void HgmFrameRateManager::HandleGamesEvent(pid_t pid, EventInfo eventInfo)
989 {
990     if (!eventInfo.eventStatus) {
991         DeliverRefreshRateVote({"VOTER_GAMES"}, false);
992         return;
993     }
994     auto [pkgName, gamePid, appType] = HgmMultiAppStrategy::AnalyzePkgParam(eventInfo.description);
995     if (gamePid == DEFAULT_PID) {
996         HGM_LOGE("unknow game pid: %{public}s, skip", eventInfo.description.c_str());
997         return;
998     }
999     if (pid != DEFAULT_PID) {
1000         std::lock_guard<std::mutex> lock(cleanPidCallbackMutex_);
1001         cleanPidCallback_[pid].insert(CleanPidCallbackType::GAMES);
1002     }
1003     DeliverRefreshRateVote(
1004         {"VOTER_GAMES", eventInfo.minRefreshRate, eventInfo.maxRefreshRate, gamePid}, eventInfo.eventStatus);
1005 }
1006 
MarkVoteChange()1007 void HgmFrameRateManager::MarkVoteChange()
1008 {
1009     isRefreshNeed_ = true;
1010     if (forceUpdateCallback_ != nullptr) {
1011         forceUpdateCallback_(false, true);
1012     }
1013 }
1014 
DeliverRefreshRateVote(const VoteInfo & voteInfo,bool eventStatus)1015 void HgmFrameRateManager::DeliverRefreshRateVote(const VoteInfo& voteInfo, bool eventStatus)
1016 {
1017     RS_TRACE_NAME_FMT("Deliver voter:%s(pid:%d extInfo:%s), status:%u, value:[%d-%d]",
1018         voteInfo.voterName.c_str(), voteInfo.pid, voteInfo.extInfo.c_str(),
1019         eventStatus, voteInfo.min, voteInfo.max);
1020     if (voteInfo.min > voteInfo.max) {
1021         HGM_LOGW("HgmFrameRateManager:invalid vote %{public}s(%{public}d %{public}s):[%{public}d, %{public}d]",
1022             voteInfo.voterName.c_str(), voteInfo.pid, voteInfo.extInfo.c_str(), voteInfo.min, voteInfo.max);
1023         return;
1024     }
1025 
1026     std::lock_guard<std::mutex> lock(voteMutex_);
1027     voteRecord_.try_emplace(voteInfo.voterName, std::vector<VoteInfo>());
1028     auto& vec = voteRecord_[voteInfo.voterName];
1029 
1030     // clear
1031     if ((voteInfo.pid == 0) && (eventStatus == REMOVE_VOTE)) {
1032         if (!vec.empty()) {
1033             vec.clear();
1034             MarkVoteChange();
1035         }
1036         return;
1037     }
1038 
1039     for (auto it = vec.begin(); it != vec.end(); it++) {
1040         if ((*it).pid != voteInfo.pid) {
1041             continue;
1042         }
1043 
1044         if (eventStatus == REMOVE_VOTE) {
1045             // remove
1046             it = vec.erase(it);
1047             MarkVoteChange();
1048             return;
1049         } else {
1050             if ((*it).min != voteInfo.min || (*it).max != voteInfo.max) {
1051                 // modify
1052                 vec.erase(it);
1053                 vec.push_back(voteInfo);
1054                 MarkVoteChange();
1055             } else if (voteInfo.voterName == "VOTER_PACKAGES") {
1056                 // force update cause VOTER_PACKAGES is flag of safe_voter
1057                 MarkVoteChange();
1058             }
1059             return;
1060         }
1061     }
1062 
1063     // add
1064     if (eventStatus == ADD_VOTE) {
1065         pidRecord_.insert(voteInfo.pid);
1066         vec.push_back(voteInfo);
1067         MarkVoteChange();
1068     }
1069 }
1070 
MergeRangeByPriority(VoteRange & rangeRes,const VoteRange & curVoteRange)1071 std::pair<bool, bool> HgmFrameRateManager::MergeRangeByPriority(VoteRange& rangeRes, const VoteRange& curVoteRange)
1072 {
1073     auto &[min, max] = rangeRes;
1074     auto &[minTemp, maxTemp] = curVoteRange;
1075     bool needMergeVoteInfo = false;
1076     if (minTemp > min) {
1077         min = minTemp;
1078         if (min >= max) {
1079             min = max;
1080             return {true, needMergeVoteInfo};
1081         }
1082     }
1083     if (maxTemp < max) {
1084         max = maxTemp;
1085         needMergeVoteInfo = true;
1086         if (min >= max) {
1087             max = min;
1088             return {true, needMergeVoteInfo};
1089         }
1090     }
1091     if (min == max) {
1092         return {true, needMergeVoteInfo};
1093     }
1094     return {false, needMergeVoteInfo};
1095 }
1096 
MergeLtpo2IdleVote(std::vector<std::string>::iterator & voterIter,VoteInfo & resultVoteInfo,VoteRange & mergedVoteRange)1097 bool HgmFrameRateManager::MergeLtpo2IdleVote(
1098     std::vector<std::string>::iterator &voterIter, VoteInfo& resultVoteInfo, VoteRange &mergedVoteRange)
1099 {
1100     bool mergeSuccess = false;
1101     // [VOTER_LTPO, VOTER_IDLE)
1102     for (; voterIter != voters_.end() - 1; voterIter++) {
1103         if (voteRecord_.find(*voterIter) == voteRecord_.end()) {
1104             continue;
1105         }
1106         auto vec = voteRecord_[*voterIter];
1107         if (vec.empty()) {
1108             continue;
1109         }
1110 
1111         VoteInfo curVoteInfo = vec.back();
1112         if (!multiAppStrategy_.CheckPidValid(curVoteInfo.pid)) {
1113             ProcessVoteLog(curVoteInfo, true);
1114             continue;
1115         }
1116         if (curVoteInfo.voterName == "VOTER_VIDEO") {
1117             auto foregroundPidApp = multiAppStrategy_.GetForegroundPidApp();
1118             if (foregroundPidApp.find(curVoteInfo.pid) == foregroundPidApp.end()) {
1119                 ProcessVoteLog(curVoteInfo, true);
1120                 continue;
1121             }
1122             auto configData = HgmCore::Instance().GetPolicyConfigData();
1123             if (configData != nullptr && configData->videoFrameRateList_.find(
1124                 foregroundPidApp[curVoteInfo.pid].second) == configData->videoFrameRateList_.end()) {
1125                 ProcessVoteLog(curVoteInfo, true);
1126                 continue;
1127             }
1128         }
1129         ProcessVoteLog(curVoteInfo, false);
1130         if (mergeSuccess) {
1131             mergedVoteRange.first = mergedVoteRange.first > curVoteInfo.min ? mergedVoteRange.first : curVoteInfo.min;
1132             if (curVoteInfo.max >= mergedVoteRange.second) {
1133                 mergedVoteRange.second = curVoteInfo.max;
1134                 resultVoteInfo.Merge(curVoteInfo);
1135             }
1136         } else {
1137             resultVoteInfo.Merge(curVoteInfo);
1138             mergedVoteRange = {curVoteInfo.min, curVoteInfo.max};
1139         }
1140         mergeSuccess = true;
1141     }
1142     return mergeSuccess;
1143 }
1144 
CheckRefreshNeed()1145 bool HgmFrameRateManager::CheckRefreshNeed()
1146 {
1147     if (!isRefreshNeed_) {
1148         const auto& packages = multiAppStrategy_.GetPackages();
1149         RS_TRACE_NAME_FMT("Process nothing, lastVoteInfo: %s[%d, %d] curPackage: %s, touchState: %d",
1150             lastVoteInfo_.voterName.c_str(), lastVoteInfo_.min, lastVoteInfo_.max,
1151             packages.empty() ? "" : packages.front().c_str(), touchManager_.GetState());
1152         return false;
1153     }
1154     return true;
1155 }
1156 
ProcessAncoRefreshRateVote(const std::string & voter,VoteInfo & curVoteInfo)1157 void HgmFrameRateManager::ProcessAncoRefreshRateVote(const std::string& voter, VoteInfo& curVoteInfo)
1158 {
1159     if (voter == "VOTER_ANCO" && !ancoScenes_.empty()) {
1160         // Multiple scene are not considered at this time
1161         auto configData = HgmCore::Instance().GetPolicyConfigData();
1162         auto screenSetting = multiAppStrategy_.GetScreenSetting();
1163         auto ancoSceneIt = screenSetting.ancoSceneList.find(*ancoScenes_.begin());
1164         uint32_t min = OLED_60_HZ;
1165         uint32_t max = OLED_90_HZ;
1166         if (configData != nullptr && ancoSceneIt != screenSetting.ancoSceneList.end() &&
1167             configData->strategyConfigs_.find(ancoSceneIt->second.strategy) != configData->strategyConfigs_.end()) {
1168             min = static_cast<uint32_t>(configData->strategyConfigs_[ancoSceneIt->second.strategy].min);
1169             max = static_cast<uint32_t>(configData->strategyConfigs_[ancoSceneIt->second.strategy].max);
1170         }
1171         curVoteInfo.SetRange(min, max);
1172     }
1173 }
1174 
ProcessRefreshRateVote()1175 VoteInfo HgmFrameRateManager::ProcessRefreshRateVote()
1176 {
1177     if (!CheckRefreshNeed()) {
1178         return lastVoteInfo_;
1179     }
1180     UpdateVoteRule();
1181     std::lock_guard<std::mutex> voteNameLock(voteNameMutex_);
1182     std::lock_guard<std::mutex> voteLock(voteMutex_);
1183 
1184     VoteInfo resultVoteInfo;
1185     VoteRange voteRange = { OLED_MIN_HZ, OLED_MAX_HZ };
1186     auto &[min, max] = voteRange;
1187 
1188     for (auto voterIter = voters_.begin(); voterIter != voters_.end(); voterIter++) {
1189         VoteRange range;
1190         VoteInfo info;
1191         if (*voterIter == "VOTER_LTPO" && MergeLtpo2IdleVote(voterIter, info, range)) {
1192             auto [mergeVoteRange, mergeVoteInfo] = MergeRangeByPriority(voteRange, range);
1193             if (mergeVoteInfo) {
1194                 resultVoteInfo.Merge(info);
1195             }
1196             if (mergeVoteRange) {
1197                 break;
1198             }
1199         }
1200 
1201         auto &voter = *voterIter;
1202         if (voteRecord_.find(voter) == voteRecord_.end() || voteRecord_[voter].empty()) {
1203             continue;
1204         }
1205         VoteInfo curVoteInfo = voteRecord_[voter].back();
1206         if ((voter == "VOTER_GAMES" && !gameScenes_.empty()) || !multiAppStrategy_.CheckPidValid(curVoteInfo.pid)) {
1207             ProcessVoteLog(curVoteInfo, true);
1208             continue;
1209         }
1210         ProcessAncoRefreshRateVote(voter, curVoteInfo);
1211         ProcessVoteLog(curVoteInfo, false);
1212         auto [mergeVoteRange, mergeVoteInfo] = MergeRangeByPriority(voteRange, {curVoteInfo.min, curVoteInfo.max});
1213         if (mergeVoteInfo) {
1214             resultVoteInfo.Merge(curVoteInfo);
1215         }
1216         if (mergeVoteRange) {
1217             break;
1218         }
1219     }
1220     isRefreshNeed_ = false;
1221     HGM_LOGI("Process: Strategy:%{public}s Screen:%{public}d Mode:%{public}d -- VoteResult:{%{public}d-%{public}d}",
1222         curScreenStrategyId_.c_str(), static_cast<int>(curScreenId_), curRefreshRateMode_, min, max);
1223     SetResultVoteInfo(resultVoteInfo, min, max);
1224     return resultVoteInfo;
1225 }
1226 
UpdateVoteRule()1227 void HgmFrameRateManager::UpdateVoteRule()
1228 {
1229     // dynamic priority for scene
1230     if (sceneStack_.empty()) {
1231         // no active scene
1232         DeliverRefreshRateVote({"VOTER_SCENE"}, REMOVE_VOTE);
1233         return;
1234     }
1235     auto configData = HgmCore::Instance().GetPolicyConfigData();
1236     if (configData == nullptr) {
1237         return;
1238     }
1239     if (configData->screenConfigs_.count(curScreenStrategyId_) == 0 ||
1240         configData->screenConfigs_[curScreenStrategyId_].count(std::to_string(curRefreshRateMode_)) == 0) {
1241         return;
1242     }
1243     auto curScreenSceneList =
1244         configData->screenConfigs_[curScreenStrategyId_][std::to_string(curRefreshRateMode_)].sceneList;
1245     if (curScreenSceneList.empty()) {
1246         // no scene configed in cur screen
1247         return;
1248     }
1249 
1250     std::string lastScene;
1251     auto scenePos = sceneStack_.rbegin();
1252     for (; scenePos != sceneStack_.rend(); scenePos++) {
1253         lastScene = (*scenePos).first;
1254         if (curScreenSceneList.count(lastScene) != 0) {
1255             break;
1256         }
1257     }
1258     if (scenePos == sceneStack_.rend()) {
1259         // no valid scene
1260         DeliverRefreshRateVote({"VOTER_SCENE"}, REMOVE_VOTE);
1261         return;
1262     }
1263     auto curSceneConfig = curScreenSceneList[lastScene];
1264     if (!XMLParser::IsNumber(curSceneConfig.priority) ||
1265         configData->strategyConfigs_.find(curSceneConfig.strategy) == configData->strategyConfigs_.end()) {
1266         return;
1267     }
1268     uint32_t curScenePriority = static_cast<uint32_t>(std::stoi(curSceneConfig.priority));
1269     uint32_t min = static_cast<uint32_t>(configData->strategyConfigs_[curSceneConfig.strategy].min);
1270     uint32_t max = static_cast<uint32_t>(configData->strategyConfigs_[curSceneConfig.strategy].max);
1271     HGM_LOGI("UpdateVoteRule: SceneName:%{public}s", lastScene.c_str());
1272     DeliverRefreshRateVote({"VOTER_SCENE", min, max, (*scenePos).second, lastScene}, ADD_VOTE);
1273 
1274     // restore
1275     std::lock_guard<std::mutex> lock(voteNameMutex_);
1276     voters_ = std::vector<std::string>(std::begin(VOTER_NAME), std::end(VOTER_NAME));
1277 
1278     if (curScenePriority == VOTER_SCENE_PRIORITY_BEFORE_PACKAGES) {
1279         auto srcPos = find(voters_.begin(), voters_.end(), "VOTER_SCENE");
1280         voters_.erase(srcPos);
1281         auto dstPos = find(voters_.begin(), voters_.end(), "VOTER_PACKAGES");
1282         voters_.insert(dstPos, "VOTER_SCENE");
1283     }
1284 }
1285 
CleanVote(pid_t pid)1286 void HgmFrameRateManager::CleanVote(pid_t pid)
1287 {
1288     if (pid == DEFAULT_PID) {
1289         return;
1290     }
1291     multiAppStrategy_.CleanApp(pid);
1292     {
1293         std::lock_guard<std::mutex> lock(cleanPidCallbackMutex_);
1294         if (auto iter = cleanPidCallback_.find(pid); iter != cleanPidCallback_.end()) {
1295             for (auto cleanPidCallbackType : iter->second) {
1296                 switch (cleanPidCallbackType) {
1297                     case CleanPidCallbackType::LIGHT_FACTOR:
1298                         HandleLightFactorStatus(DEFAULT_PID, false);
1299                         break;
1300                     case CleanPidCallbackType::PACKAGE_EVENT:
1301                         HandlePackageEvent(DEFAULT_PID, {}); // handle empty pkg
1302                         break;
1303                     case CleanPidCallbackType::TOUCH_EVENT:
1304                         HandleTouchEvent(DEFAULT_PID, TouchStatus::TOUCH_UP, LAST_TOUCH_CNT);
1305                         break;
1306                     case CleanPidCallbackType::GAMES:
1307                         DeliverRefreshRateVote({"VOTER_GAMES"}, false);
1308                         break;
1309                     default:
1310                         break;
1311                 }
1312             }
1313             iter->second.clear();
1314         }
1315     }
1316 
1317     if (pidRecord_.count(pid) == 0) {
1318         return;
1319     }
1320     std::lock_guard<std::mutex> lock(voteMutex_);
1321     HGM_LOGW("CleanVote: i am [%{public}d], i died, clean my votes please.", pid);
1322     pidRecord_.erase(pid);
1323 
1324     for (auto& [key, value] : voteRecord_) {
1325         for (auto it = value.begin(); it != value.end(); it++) {
1326             if ((*it).pid == pid) {
1327                 it = value.erase(it);
1328                 MarkVoteChange();
1329                 break;
1330             }
1331         }
1332     }
1333 }
1334 
SetResultVoteInfo(VoteInfo & voteInfo,uint32_t min,uint32_t max)1335 void HgmFrameRateManager::SetResultVoteInfo(VoteInfo& voteInfo, uint32_t min, uint32_t max)
1336 {
1337     voteInfo.min = min;
1338     voteInfo.max = max;
1339     if (voteInfo.voterName == "VOTER_PACKAGES" && touchManager_.GetState() != TouchState::IDLE_STATE) {
1340         voteInfo.extInfo = "ONTOUCH";
1341     }
1342     if (auto packages = multiAppStrategy_.GetPackages(); packages.size() > 0) {
1343         const auto& package = packages.front();
1344         const auto& pos = package.find(":");
1345         if (pos != package.npos) {
1346             voteInfo.bundleName = package.substr(0, pos);
1347         } else {
1348             voteInfo.bundleName = packages.front();
1349         }
1350     }
1351 }
1352 
UpdateEnergyConsumptionConfig()1353 void HgmFrameRateManager::UpdateEnergyConsumptionConfig()
1354 {
1355     HgmEnergyConsumptionPolicy::Instance().SetEnergyConsumptionConfig(
1356         multiAppStrategy_.GetScreenSetting().animationPowerConfig);
1357     HgmEnergyConsumptionPolicy::Instance().SetUiEnergyConsumptionConfig(
1358         multiAppStrategy_.GetScreenSetting().uiPowerConfig);
1359 }
1360 
EnterEnergyConsumptionAssuranceMode()1361 void HgmFrameRateManager::EnterEnergyConsumptionAssuranceMode()
1362 {
1363     auto task = []() { HgmEnergyConsumptionPolicy::Instance().SetAnimationEnergyConsumptionAssuranceMode(true); };
1364     HgmTaskHandleThread::Instance().PostEvent(ENERGY_ASSURANCE_TASK_ID, task, ENERGY_ASSURANCE_TASK_DELAY_TIME);
1365     auto uiTask = []() { HgmEnergyConsumptionPolicy::Instance().SetUiEnergyConsumptionAssuranceMode(true); };
1366     HgmTaskHandleThread::Instance().PostEvent(UI_ENERGY_ASSURANCE_TASK_ID, uiTask, UI_ENERGY_ASSURANCE_TASK_DELAY_TIME);
1367 }
1368 
ExitEnergyConsumptionAssuranceMode()1369 void HgmFrameRateManager::ExitEnergyConsumptionAssuranceMode()
1370 {
1371     HgmTaskHandleThread::Instance().RemoveEvent(ENERGY_ASSURANCE_TASK_ID);
1372     HgmTaskHandleThread::Instance().RemoveEvent(UI_ENERGY_ASSURANCE_TASK_ID);
1373     HgmEnergyConsumptionPolicy::Instance().SetAnimationEnergyConsumptionAssuranceMode(false);
1374     HgmEnergyConsumptionPolicy::Instance().SetUiEnergyConsumptionAssuranceMode(false);
1375 }
1376 
ProcessVoteLog(const VoteInfo & curVoteInfo,bool isSkip)1377 void HgmFrameRateManager::ProcessVoteLog(const VoteInfo& curVoteInfo, bool isSkip)
1378 {
1379     RS_TRACE_NAME_FMT("Process voter:%s(pid:%d), value:[%d-%d] skip: %s",
1380         curVoteInfo.voterName.c_str(), curVoteInfo.pid, curVoteInfo.min, curVoteInfo.max, isSkip ? "true" : "false");
1381     HGM_LOGI("Process: %{public}s(%{public}d):[%{public}d, %{public}d] skip: %{public}s",
1382         curVoteInfo.voterName.c_str(), curVoteInfo.pid, curVoteInfo.min, curVoteInfo.max, isSkip ? "true" : "false");
1383 }
1384 } // namespace Rosen
1385 } // namespace OHOS