1 /*
2  * Copyright (c) 2023 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_core.h"
17 
18 #include <algorithm>
19 #include <cstddef>
20 #include <cstdint>
21 #include <string>
22 #include <unistd.h>
23 
24 #include "hgm_frame_rate_manager.h"
25 #include "hgm_config_callback_manager.h"
26 #include "hgm_log.h"
27 #include "vsync_generator.h"
28 #include "platform/common/rs_system_properties.h"
29 #include "parameters.h"
30 #include "frame_rate_report.h"
31 #include "sandbox_utils.h"
32 
33 namespace OHOS::Rosen {
34 static std::map<uint32_t, int64_t> IDEAL_PERIOD = {
35     { 144, 6944444 },
36     { 120, 8333333 },
37     { 90, 11111111 },
38     { 80, 12500000 },
39     { 72, 13888888 },
40     { 60, 16666666 },
41     { 48, 20833333 },
42     { 45, 22222222 },
43     { 40, 25000000 },
44     { 36, 27777777 },
45     { 30, 33333333 },
46     { 24, 41666666 },
47     { 20, 50000000 },
48     { 15, 66666666 },
49     { 10, 100000000 },
50 };
51 
Instance()52 HgmCore& HgmCore::Instance()
53 {
54     static HgmCore instance;
55     static std::mutex mtx;
56     if (instance.IsInit()) {
57         return instance;
58     }
59 
60     std::lock_guard<std::mutex> lock(mtx);
61     if (instance.IsInit()) {
62         return instance;
63     }
64 
65     if (instance.Init() == false) {
66         HGM_LOGI("HgmCore initialization failed");
67     }
68 
69     return instance;
70 }
71 
HgmCore()72 HgmCore::HgmCore()
73 {
74     HGM_LOGI("Construction of Hgmcore");
75 }
76 
Init()77 bool HgmCore::Init()
78 {
79     if (!isEnabled_) {
80         HGM_LOGE("HgmCore Hgm is desactivated");
81         return false;
82     }
83 
84     if (InitXmlConfig() != EXEC_SUCCESS) {
85         HGM_LOGE("HgmCore falied to parse");
86         return false;
87     }
88 
89     // ensure that frameRateManager init after XML parsed.
90     hgmFrameRateMgr_ = std::make_unique<HgmFrameRateManager>();
91 
92     auto newRateMode = static_cast<int32_t>(RSSystemProperties::GetHgmRefreshRateModesEnabled());
93     if (newRateMode == 0) {
94         HGM_LOGI("HgmCore No customer refreshrate mode found, set to xml default");
95         if (mPolicyConfigData_ == nullptr || !XMLParser::IsNumber(mPolicyConfigData_->defaultRefreshRateMode_)) {
96             HGM_LOGE("HgmCore failed to get parsed data");
97         } else {
98             customFrameRateMode_ = std::stoi(mPolicyConfigData_->defaultRefreshRateMode_);
99         }
100     } else {
101         HGM_LOGI("HgmCore No customer refreshrate mode found: %{public}d", newRateMode);
102         customFrameRateMode_ = newRateMode;
103         if (customFrameRateMode_ != HGM_REFRESHRATE_MODE_AUTO &&
104             mPolicyConfigData_ != nullptr && mPolicyConfigData_->xmlCompatibleMode_) {
105             customFrameRateMode_ = mPolicyConfigData_->SettingModeId2XmlModeId(customFrameRateMode_);
106         }
107         CheckCustomFrameRateModeValid();
108     }
109 
110     SetLtpoConfig();
111 
112     isInit_.store(true);
113     isDelayMode_ = RSSystemProperties::IsPhoneType() || RSSystemProperties::IsTabletType();
114     HGM_LOGI("HgmCore initialization success!!! delayMode: %{public}d", isDelayMode_);
115     return isInit_;
116 }
117 
CheckCustomFrameRateModeValid()118 void HgmCore::CheckCustomFrameRateModeValid()
119 {
120     if (hgmFrameRateMgr_ == nullptr || mPolicyConfigData_ == nullptr) {
121         return;
122     }
123 
124     auto curScreenStrategyId = hgmFrameRateMgr_->GetCurScreenStrategyId();
125     auto &screenConfigs = mPolicyConfigData_->screenConfigs_;
126     if (screenConfigs.find(curScreenStrategyId) == screenConfigs.end()) {
127         return;
128     }
129 
130     auto &screenConfig = screenConfigs[curScreenStrategyId];
131     auto modeStr = std::to_string(customFrameRateMode_);
132     if (screenConfig.find(modeStr) != screenConfig.end() || screenConfig.empty()) {
133         return;
134     }
135 
136     int32_t maxMode = HGM_REFRESHRATE_MODE_AUTO;
137     for (auto &[modeStr, _] : screenConfig) {
138         if (!XMLParser::IsNumber(modeStr)) {
139             continue;
140         }
141         auto mode = std::stoi(modeStr);
142         if (maxMode < mode) {
143             maxMode = mode;
144         }
145     }
146     HGM_LOGE("auto repair mode: %{public}d -> %{public}d", customFrameRateMode_, maxMode);
147     customFrameRateMode_ = maxMode;
148 }
149 
InitXmlConfig()150 int32_t HgmCore::InitXmlConfig()
151 {
152     HGM_LOGD("HgmCore is parsing xml configuration");
153     if (!mParser_) {
154         mParser_ = std::make_unique<XMLParser>();
155     }
156 
157     if (mParser_->LoadConfiguration(configFileProduct) != EXEC_SUCCESS) {
158         HGM_LOGW("HgmCore failed to load prod xml configuration file");
159     }
160     if (mParser_->Parse() != EXEC_SUCCESS) {
161         HGM_LOGW("HgmCore failed to parse prod xml configuration");
162     }
163 
164     if (!mPolicyConfigData_) {
165         mPolicyConfigData_ = mParser_->GetParsedData();
166     }
167 
168     return EXEC_SUCCESS;
169 }
170 
SetLtpoConfig()171 void HgmCore::SetLtpoConfig()
172 {
173     if ((hgmFrameRateMgr_ == nullptr) || (mPolicyConfigData_ == nullptr)) {
174         return;
175     }
176     auto curScreenStrategyId = hgmFrameRateMgr_->GetCurScreenStrategyId();
177     if (mPolicyConfigData_->screenConfigs_.count(curScreenStrategyId) == 0 ||
178         mPolicyConfigData_->screenConfigs_[curScreenStrategyId].count(std::to_string(customFrameRateMode_)) == 0) {
179         return;
180     }
181     auto curScreenSetting =
182         mPolicyConfigData_->screenConfigs_[curScreenStrategyId][std::to_string(customFrameRateMode_)];
183     if (curScreenSetting.ltpoConfig.find("switch") != curScreenSetting.ltpoConfig.end() &&
184         XMLParser::IsNumber(curScreenSetting.ltpoConfig["switch"])) {
185         ltpoEnabled_ = std::stoi(curScreenSetting.ltpoConfig["switch"]);
186     } else {
187         ltpoEnabled_ = 0;
188         HGM_LOGW("HgmCore failed to find switch strategy for LTPO");
189     }
190 
191     if (curScreenSetting.ltpoConfig.find("maxTE") != curScreenSetting.ltpoConfig.end()) {
192         maxTE_ = std::stoul(curScreenSetting.ltpoConfig["maxTE"]);
193     } else {
194         maxTE_ = 0;
195         HGM_LOGW("HgmCore failed to find TE strategy for LTPO");
196     }
197 
198     if (curScreenSetting.ltpoConfig.find("alignRate") != curScreenSetting.ltpoConfig.end()) {
199         alignRate_ = std::stoul(curScreenSetting.ltpoConfig["alignRate"]);
200     } else {
201         alignRate_ = 0;
202         HGM_LOGW("HgmCore failed to find alignRate strategy for LTPO");
203     }
204 
205     if (curScreenSetting.ltpoConfig.find("pipelineOffsetPulseNum") != curScreenSetting.ltpoConfig.end() &&
206         XMLParser::IsNumber(curScreenSetting.ltpoConfig["pipelineOffsetPulseNum"])) {
207         pipelineOffsetPulseNum_ = std::stoi(curScreenSetting.ltpoConfig["pipelineOffsetPulseNum"]);
208         CreateVSyncGenerator()->SetVSyncPhaseByPulseNum(pipelineOffsetPulseNum_);
209     } else {
210         pipelineOffsetPulseNum_ = 0;
211         HGM_LOGW("HgmCore failed to find pipelineOffset strategy for LTPO");
212     }
213 
214     SetScreenConstraintConfig();
215     HGM_LOGI("HgmCore LTPO strategy ltpoEnabled: %{public}d, maxTE: %{public}d, alignRate: %{public}d, " \
216         "pipelineOffsetPulseNum: %{public}d, vBlankIdleCorrectSwitch: %{public}d, lowRateToHighQuickSwitch: %{public}d",
217         ltpoEnabled_, maxTE_, alignRate_, pipelineOffsetPulseNum_, vBlankIdleCorrectSwitch_, lowRateToHighQuickSwitch_);
218 }
219 
SetScreenConstraintConfig()220 void HgmCore::SetScreenConstraintConfig()
221 {
222     auto curScreenStrategyId = hgmFrameRateMgr_->GetCurScreenStrategyId();
223     if (mPolicyConfigData_->screenConfigs_.count(curScreenStrategyId) == 0 ||
224         mPolicyConfigData_->screenConfigs_[curScreenStrategyId].count(std::to_string(customFrameRateMode_)) == 0) {
225         return;
226     }
227     auto curScreenSetting =
228         mPolicyConfigData_->screenConfigs_[curScreenStrategyId][std::to_string(customFrameRateMode_)];
229     if (curScreenSetting.ltpoConfig.find("vBlankIdleCorrectSwitch") != curScreenSetting.ltpoConfig.end() &&
230         XMLParser::IsNumber(curScreenSetting.ltpoConfig["vBlankIdleCorrectSwitch"])) {
231         vBlankIdleCorrectSwitch_ =  std::stoi(curScreenSetting.ltpoConfig["vBlankIdleCorrectSwitch"]);
232     } else {
233         vBlankIdleCorrectSwitch_ = 0;
234         HGM_LOGW("HgmCore failed to find vBlankIdleCorrectSwitch strategy for LTPO");
235     }
236 
237     if (curScreenSetting.ltpoConfig.find("lowRateToHighQuickSwitch") != curScreenSetting.ltpoConfig.end() &&
238         XMLParser::IsNumber(curScreenSetting.ltpoConfig["lowRateToHighQuickSwitch"])) {
239         lowRateToHighQuickSwitch_ =  std::stoi(curScreenSetting.ltpoConfig["lowRateToHighQuickSwitch"]);
240     } else {
241         lowRateToHighQuickSwitch_ = 0;
242         HGM_LOGW("HgmCore failed to find lowRateToHighQuickSwitch strategy for LTPO");
243     }
244 }
245 
RegisterRefreshRateModeChangeCallback(const RefreshRateModeChangeCallback & callback)246 void HgmCore::RegisterRefreshRateModeChangeCallback(const RefreshRateModeChangeCallback& callback)
247 {
248     refreshRateModeChangeCallback_ = callback;
249     if (refreshRateModeChangeCallback_ != nullptr) {
250         auto refreshRateModeName = GetCurrentRefreshRateModeName();
251         refreshRateModeChangeCallback_(refreshRateModeName);
252     }
253 }
254 
SetCustomRateMode(int32_t mode)255 int32_t HgmCore::SetCustomRateMode(int32_t mode)
256 {
257     customFrameRateMode_ = mode;
258     return EXEC_SUCCESS;
259 }
260 
RegisterRefreshRateUpdateCallback(const RefreshRateUpdateCallback & callback)261 void HgmCore::RegisterRefreshRateUpdateCallback(const RefreshRateUpdateCallback& callback)
262 {
263     ScreenId screenId = HgmCore::Instance().GetActiveScreenId();
264     uint32_t refreshRate = HgmCore::Instance().GetScreenCurrentRefreshRate(screenId);
265     refreshRateUpdateCallback_ = callback;
266     if (refreshRateUpdateCallback_ != nullptr) {
267         refreshRateUpdateCallback_(refreshRate);
268     }
269 }
270 
SetScreenRefreshRate(ScreenId id,int32_t sceneId,int32_t rate)271 int32_t HgmCore::SetScreenRefreshRate(ScreenId id, int32_t sceneId, int32_t rate)
272 {
273     // set the screen to the desired refreshrate
274     HGM_LOGD("HgmCore setting screen " PUBU64 " to the rate of %{public}d", id, rate);
275     auto screen = GetScreen(id);
276     if (!screen) {
277         HGM_LOGW("HgmCore failed to get screen of : " PUBU64 "", id);
278         return HGM_ERROR;
279     }
280 
281     if (rate <= 0) {
282         HGM_LOGW("HgmCore refuse an illegal framerate: %{public}d", rate);
283         return HGM_ERROR;
284     }
285     sceneId = static_cast<int32_t>(screenSceneSet_.size());
286     int32_t modeToSwitch = screen->SetActiveRefreshRate(sceneId, static_cast<uint32_t>(rate));
287     if (modeToSwitch < 0) {
288         return modeToSwitch;
289     }
290 
291     std::lock_guard<std::mutex> lock(modeListMutex_);
292 
293     // the rate is accepted and passed to a list, will be applied by hardwarethread before sending the composition
294     HGM_LOGI("HgmCore the rate of %{public}d is accepted, the target mode is %{public}d", rate, modeToSwitch);
295     if (modeListToApply_ == nullptr) {
296         HGM_LOGD("HgmCore modeListToApply_ is invalid, buiding a new mode list");
297         modeListToApply_ = std::make_unique<std::unordered_map<ScreenId, int32_t>>();
298     }
299     auto modeList = modeListToApply_.get();
300     (*modeList)[id] = modeToSwitch;
301 
302     if (refreshRateUpdateCallback_) {
303         refreshRateUpdateCallback_(rate);
304         HGM_LOGD("refresh rate changed, notify to app");
305     }
306     return modeToSwitch;
307 }
308 
SetRateAndResolution(ScreenId id,int32_t sceneId,int32_t rate,int32_t width,int32_t height)309 int32_t HgmCore::SetRateAndResolution(ScreenId id, int32_t sceneId, int32_t rate, int32_t width, int32_t height)
310 {
311     // reserved
312     return HGM_ERROR;
313 }
314 
SetRefreshRateMode(int32_t refreshRateMode)315 int32_t HgmCore::SetRefreshRateMode(int32_t refreshRateMode)
316 {
317     // setting mode to xml modeid
318     if (refreshRateMode != HGM_REFRESHRATE_MODE_AUTO
319         && mPolicyConfigData_ != nullptr && mPolicyConfigData_->xmlCompatibleMode_) {
320         refreshRateMode = mPolicyConfigData_->SettingModeId2XmlModeId(refreshRateMode);
321     }
322     HGM_LOGD("HgmCore set refreshrate mode to : %{public}d", refreshRateMode);
323     // change refreshrate mode by setting application
324     if (SetCustomRateMode(refreshRateMode) != EXEC_SUCCESS) {
325         return HGM_ERROR;
326     }
327 
328     hgmFrameRateMgr_->HandleRefreshRateMode(refreshRateMode);
329 
330     auto refreshRateModeName = GetCurrentRefreshRateModeName();
331     if (refreshRateModeChangeCallback_ != nullptr) {
332         refreshRateModeChangeCallback_(refreshRateModeName);
333     }
334     HgmConfigCallbackManager::GetInstance()->SyncRefreshRateModeChangeCallback(refreshRateModeName);
335     return EXEC_SUCCESS;
336 }
337 
NotifyScreenPowerStatus(ScreenId id,ScreenPowerStatus status)338 void HgmCore::NotifyScreenPowerStatus(ScreenId id, ScreenPowerStatus status)
339 {
340     if (hgmFrameRateMgr_ != nullptr) {
341         hgmFrameRateMgr_->HandleScreenPowerStatus(id, status);
342     }
343 
344     if (refreshRateModeChangeCallback_ != nullptr) {
345         auto refreshRateModeName = GetCurrentRefreshRateModeName();
346         refreshRateModeChangeCallback_(refreshRateModeName);
347     }
348 }
349 
AddScreen(ScreenId id,int32_t defaultMode,ScreenSize & screenSize)350 int32_t HgmCore::AddScreen(ScreenId id, int32_t defaultMode, ScreenSize& screenSize)
351 {
352     // add a physical screen to hgm during hotplug event
353     HGM_LOGI("HgmCore adding screen : " PUBI64 "", id);
354     bool removeId = std::any_of(screenIds_.begin(), screenIds_.end(),
355         [id](const ScreenId screen) { return screen == id; });
356     if (removeId) {
357         if (RemoveScreen(id) != EXEC_SUCCESS) {
358             HGM_LOGW("HgmCore failed to remove the existing screen, not adding : " PUBI64 "", id);
359             return HGM_BASE_REMOVE_FAILED;
360         }
361     }
362 
363     sptr<HgmScreen> newScreen = new HgmScreen(id, defaultMode, screenSize);
364 
365     std::lock_guard<std::mutex> lock(listMutex_);
366     screenList_.push_back(newScreen);
367     screenIds_.push_back(id);
368 
369     int32_t screenNum = GetScreenListSize();
370     HGM_LOGI("HgmCore num of screen is %{public}d", screenNum);
371     return EXEC_SUCCESS;
372 }
373 
RemoveScreen(ScreenId id)374 int32_t HgmCore::RemoveScreen(ScreenId id)
375 {
376     std::lock_guard<std::mutex> lock(listMutex_);
377     // delete a screen during a hotplug event
378     HGM_LOGD("HgmCore deleting the screen : " PUBU64 "", id);
379     for (auto screen = screenIds_.begin(); screen != screenIds_.end(); ++screen) {
380         if (*screen == id) {
381             screenIds_.erase(screen);
382             break;
383         }
384     }
385     for (auto screen = screenList_.begin(); screen != screenList_.end(); ++screen) {
386         if ((*screen)->GetId() == id) {
387             screenList_.erase(screen);
388             break;
389         }
390     }
391     return EXEC_SUCCESS;
392 }
393 
AddScreenInfo(ScreenId id,int32_t width,int32_t height,uint32_t rate,int32_t mode)394 int32_t HgmCore::AddScreenInfo(ScreenId id, int32_t width, int32_t height, uint32_t rate, int32_t mode)
395 {
396     // add a supported screen mode to the screen
397     auto screen = GetScreen(id);
398     if (!screen) {
399         HGM_LOGW("HgmCore failed to get screen of : " PUBU64 "", id);
400         return HGM_NO_SCREEN;
401     }
402 
403     if (screen->AddScreenModeInfo(width, height, rate, mode) == EXEC_SUCCESS) {
404         return EXEC_SUCCESS;
405     }
406 
407     HGM_LOGW("HgmCore failed to add screen mode info of screen : " PUBU64 "", id);
408     return HGM_SCREEN_PARAM_ERROR;
409 }
410 
RefreshBundleName(const std::string & name)411 int32_t HgmCore::RefreshBundleName(const std::string& name)
412 {
413     if (name == currentBundleName_) {
414         return EXEC_SUCCESS;
415     }
416 
417     currentBundleName_ = name;
418 
419     if (customFrameRateMode_ == HGM_REFRESHRATE_MODE_AUTO) {
420         return EXEC_SUCCESS;
421     }
422 
423     int resetResult = SetRefreshRateMode(customFrameRateMode_);
424     if (resetResult == EXEC_SUCCESS) {
425         HGM_LOGI("HgmCore reset current refreshrate mode: %{public}d due to bundlename: %{public}s",
426             customFrameRateMode_, currentBundleName_.c_str());
427     }
428     return EXEC_SUCCESS;
429 }
430 
GetScreenCurrentRefreshRate(ScreenId id) const431 uint32_t HgmCore::GetScreenCurrentRefreshRate(ScreenId id) const
432 {
433     auto screen = GetScreen(id);
434     if (!screen) {
435         HGM_LOGW("HgmCore failed to find screen " PUBU64 "", id);
436         return static_cast<uint32_t>(EXEC_SUCCESS);
437     }
438 
439     return screen->GetActiveRefreshRate();
440 }
441 
GetCurrentRefreshRateMode() const442 int32_t HgmCore::GetCurrentRefreshRateMode() const
443 {
444     if (customFrameRateMode_ != HGM_REFRESHRATE_MODE_AUTO
445         && mPolicyConfigData_ != nullptr && mPolicyConfigData_->xmlCompatibleMode_) {
446         return mPolicyConfigData_->XmlModeId2SettingModeId(customFrameRateMode_);
447     }
448     return customFrameRateMode_;
449 }
450 
GetCurrentRefreshRateModeName() const451 int32_t HgmCore::GetCurrentRefreshRateModeName() const
452 {
453     if (mPolicyConfigData_ != nullptr && mPolicyConfigData_->xmlCompatibleMode_) {
454         return mPolicyConfigData_->GetRefreshRateModeName(customFrameRateMode_);
455     }
456     std::map<int32_t, int32_t> modeIdRateMap = {{-1, -1}, {1, 60}, {2, 90}, {3, 120}};
457     if (modeIdRateMap.find(customFrameRateMode_) != modeIdRateMap.end()) {
458         return modeIdRateMap[customFrameRateMode_];
459     }
460     return customFrameRateMode_;
461 }
462 
GetScreen(ScreenId id) const463 sptr<HgmScreen> HgmCore::GetScreen(ScreenId id) const
464 {
465     std::lock_guard<std::mutex> lock(listMutex_);
466     for (auto screen = screenList_.begin(); screen != screenList_.end(); ++screen) {
467         if ((*screen)->GetId() == id) {
468             return *screen;
469         }
470     }
471 
472     return nullptr;
473 }
474 
GetScreenSupportedRefreshRates(ScreenId id)475 std::vector<uint32_t> HgmCore::GetScreenSupportedRefreshRates(ScreenId id)
476 {
477     HgmTaskHandleThread::Instance().DetectMultiThreadingCalls();
478     auto screen = GetScreen(id);
479     if (!screen) {
480         HGM_LOGW("HgmCore failed to find screen " PUBU64 "", id);
481         return std::vector<uint32_t>(static_cast<uint32_t>(EXEC_SUCCESS));
482     }
483 
484     auto supportedRates = screen->GetSupportedRates();
485     std::vector<uint32_t> retVec;
486     retVec.assign(supportedRates.begin(), supportedRates.end());
487     return retVec;
488 }
489 
GetScreenComponentRefreshRates(ScreenId id)490 std::vector<int32_t> HgmCore::GetScreenComponentRefreshRates(ScreenId id)
491 {
492     if (!mPolicyConfigData_) {
493         HGM_LOGW("HgmCore no parsed component data, returning default value");
494         return std::vector<int32_t>(static_cast<uint32_t>(EXEC_SUCCESS));
495     }
496 
497     std::vector<int32_t> retVec;
498     for (const auto& [rate, _] : mPolicyConfigData_->refreshRateForSettings_) {
499         retVec.emplace_back(rate);
500         HGM_LOGE("HgmCore Adding component rate: %{public}d", rate);
501     }
502     return retVec;
503 }
504 
GetModesToApply()505 std::unique_ptr<std::unordered_map<ScreenId, int32_t>> HgmCore::GetModesToApply()
506 {
507     std::lock_guard<std::mutex> lock(modeListMutex_);
508     return std::move(modeListToApply_);
509 }
510 
SetActiveScreenId(ScreenId id)511 void HgmCore::SetActiveScreenId(ScreenId id)
512 {
513     activeScreenId_ = id;
514 }
515 
GetActiveScreen() const516 sptr<HgmScreen> HgmCore::GetActiveScreen() const
517 {
518     if (activeScreenId_ == INVALID_SCREEN_ID) {
519         HGM_LOGE("HgmScreen activeScreenId_ noset");
520         return nullptr;
521     }
522     return GetScreen(activeScreenId_);
523 }
524 
GetIdealPeriod(uint32_t rate)525 int64_t HgmCore::GetIdealPeriod(uint32_t rate)
526 {
527     if (IDEAL_PERIOD.count(rate)) {
528         return IDEAL_PERIOD[rate];
529     }
530     return 0;
531 }
532 } // namespace OHOS::Rosen
533