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