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