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