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