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