1 /*
2 * Copyright (c) 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_multi_app_strategy.h"
17
18 #include <functional>
19 #include <limits>
20
21 #include "common/rs_common_hook.h"
22 #include "hgm_config_callback_manager.h"
23 #include "hgm_core.h"
24 #include "hgm_energy_consumption_policy.h"
25 #include "hgm_frame_rate_manager.h"
26 #include "rs_trace.h"
27 #include "xml_parser.h"
28
29 namespace OHOS {
30 namespace Rosen {
31 namespace {
32 PolicyConfigData::ScreenSetting defaultScreenSetting;
33 PolicyConfigData::StrategyConfigMap defaultStrategyConfigMap;
34 }
35
HgmMultiAppStrategy()36 HgmMultiAppStrategy::HgmMultiAppStrategy()
37 : screenSettingCache_(defaultScreenSetting), strategyConfigMapCache_(defaultStrategyConfigMap)
38 {
39 }
40
HandlePkgsEvent(const std::vector<std::string> & pkgs)41 HgmErrCode HgmMultiAppStrategy::HandlePkgsEvent(const std::vector<std::string>& pkgs)
42 {
43 RS_TRACE_FUNC();
44 // update pkgs
45 if (pkgs_ == pkgs) {
46 return HGM_ERROR;
47 }
48 pkgs_ = pkgs;
49 // update pid of pkg
50 for (auto& it : foregroundPidAppMap_) {
51 backgroundPid_.Put(it.first);
52 }
53 foregroundPidAppMap_.clear();
54 pidAppTypeMap_.clear();
55 CheckPackageInConfigList(pkgs_);
56 for (auto& param : pkgs_) {
57 RS_TRACE_NAME_FMT("pkg update:%s", param.c_str());
58 HGM_LOGI("pkg update:%{public}s", param.c_str());
59 auto [pkgName, pid, appType] = AnalyzePkgParam(param);
60
61 // DISPLAY ENGINE
62 RsCommonHook::Instance().SetCurrentPkgName(pkgName);
63
64 pidAppTypeMap_[pkgName] = { pid, appType };
65 if (pid > DEFAULT_PID) {
66 foregroundPidAppMap_[pid] = { appType, pkgName };
67 backgroundPid_.Erase(pid);
68 }
69 }
70 if (auto configCallbackManager = HgmConfigCallbackManager::GetInstance(); configCallbackManager != nullptr) {
71 configCallbackManager->SyncHgmConfigChangeCallback(foregroundPidAppMap_);
72 }
73
74 if (!pkgs_.empty()) {
75 touchInfo_.pkgName = std::get<0>(AnalyzePkgParam(pkgs_.front()));
76 }
77 touchInfo_.upExpectFps = OLED_NULL_HZ;
78 CalcVote();
79
80 return EXEC_SUCCESS;
81 }
82
HandleTouchInfo(const TouchInfo & touchInfo)83 void HgmMultiAppStrategy::HandleTouchInfo(const TouchInfo& touchInfo)
84 {
85 RS_TRACE_NAME_FMT("[HandleTouchInfo] pkgName:%s, touchState:%d, upExpectFps:%d",
86 touchInfo.pkgName.c_str(), touchInfo.touchState, touchInfo.upExpectFps);
87 HGM_LOGD("touch info update, pkgName:%{public}s, touchState:%{public}d, upExpectFps:%{public}d",
88 touchInfo.pkgName.c_str(), touchInfo.touchState, touchInfo.upExpectFps);
89 touchInfo_ = { touchInfo.pkgName, touchInfo.touchState, touchInfo.upExpectFps };
90 if (touchInfo.pkgName == "" && !pkgs_.empty()) {
91 auto [focusPkgName, pid, appType] = AnalyzePkgParam(pkgs_.front());
92 touchInfo_.pkgName = focusPkgName;
93 HGM_LOGD("auto change touch pkgName to focusPkgName:%{public}s", focusPkgName.c_str());
94 }
95 CalcVote();
96 }
97
HandleLightFactorStatus(int32_t state)98 void HgmMultiAppStrategy::HandleLightFactorStatus(int32_t state)
99 {
100 RS_TRACE_NAME_FMT("[HandleLightFactorStatus] state: %d", state);
101 if (lightFactorStatus_.load() == state) {
102 return;
103 }
104 lightFactorStatus_.store(state);
105 CalcVote();
106 }
107
SetScreenType(bool isLtpo)108 void HgmMultiAppStrategy::SetScreenType(bool isLtpo)
109 {
110 isLtpo_ = isLtpo;
111 }
112
HandleLowAmbientStatus(bool isEffect)113 void HgmMultiAppStrategy::HandleLowAmbientStatus(bool isEffect)
114 {
115 RS_TRACE_NAME_FMT("[HandleLowAmbientStatus] isEffect: %d", isEffect);
116 if (lowAmbientStatus_ == isEffect) {
117 return;
118 }
119 lowAmbientStatus_ = isEffect;
120 }
121
CalcVote()122 void HgmMultiAppStrategy::CalcVote()
123 {
124 RS_TRACE_FUNC();
125 HgmTaskHandleThread::Instance().DetectMultiThreadingCalls();
126 voteRes_ = { HGM_ERROR, {
127 .min = OLED_NULL_HZ, .max = OLED_120_HZ, .dynamicMode = DynamicModeType::TOUCH_ENABLED,
128 .idleFps = OLED_60_HZ, .isFactor = false, .drawMin = OLED_NULL_HZ,
129 .drawMax = OLED_120_HZ, .down = OLED_120_HZ,
130 }};
131 uniqueTouchInfo_ = std::make_unique<TouchInfo>(touchInfo_);
132
133 if (pkgs_.size() <= 1) {
134 FollowFocus();
135 } else {
136 switch (screenSettingCache_.multiAppStrategyType) {
137 case MultiAppStrategyType::USE_MAX:
138 UseMax();
139 break;
140 case MultiAppStrategyType::FOLLOW_FOCUS:
141 FollowFocus();
142 break;
143 case MultiAppStrategyType::USE_STRATEGY_NUM:
144 UseStrategyNum();
145 break;
146 default:
147 UseMax();
148 break;
149 }
150 }
151
152 if (voteRes_.first != EXEC_SUCCESS) {
153 // using setting mode when fail to calc vote
154 if (GetAppStrategyConfig("", voteRes_.second) == EXEC_SUCCESS) {
155 OnLightFactor(voteRes_.second);
156 }
157 }
158
159 UpdateStrategyByTouch(voteRes_.second, "", true);
160 uniqueTouchInfo_ = nullptr;
161
162 OnStrategyChange();
163 }
164
GetVoteRes(PolicyConfigData::StrategyConfig & strategyRes) const165 HgmErrCode HgmMultiAppStrategy::GetVoteRes(PolicyConfigData::StrategyConfig& strategyRes) const
166 {
167 strategyRes = voteRes_.second;
168 return voteRes_.first;
169 }
170
CheckPidValid(pid_t pid,bool onlyCheckForegroundApp)171 bool HgmMultiAppStrategy::CheckPidValid(pid_t pid, bool onlyCheckForegroundApp)
172 {
173 auto configData = HgmCore::Instance().GetPolicyConfigData();
174 if ((configData != nullptr && !configData->safeVoteEnabled) || disableSafeVote_) {
175 // disable safe vote
176 return true;
177 }
178 if (onlyCheckForegroundApp) {
179 return foregroundPidAppMap_.find(pid) != foregroundPidAppMap_.end();
180 }
181 return !backgroundPid_.Existed(pid);
182 }
183
GetGameNodeName(const std::string & pkgName)184 std::string HgmMultiAppStrategy::GetGameNodeName(const std::string& pkgName)
185 {
186 auto& appNodeMap = screenSettingCache_.gameAppNodeList;
187 if (appNodeMap.find(pkgName) != appNodeMap.end()) {
188 return appNodeMap.at(pkgName);
189 }
190 return "";
191 }
192
GetAppStrategyConfigName(const std::string & pkgName)193 std::string HgmMultiAppStrategy::GetAppStrategyConfigName(const std::string& pkgName)
194 {
195 auto& appConfigMap = screenSettingCache_.appList;
196 if (appConfigMap.find(pkgName) != appConfigMap.end()) {
197 return appConfigMap.at(pkgName);
198 }
199 if (pidAppTypeMap_.find(pkgName) != pidAppTypeMap_.end()) {
200 auto& appType = pidAppTypeMap_.at(pkgName).second;
201 auto& appTypes = screenSettingCache_.appTypes;
202 if (appTypes.find(appType) != appTypes.end()) {
203 return appTypes.at(appType);
204 }
205 }
206
207 return screenSettingCache_.strategy;
208 }
209
GetFocusAppStrategyConfig(PolicyConfigData::StrategyConfig & strategyRes)210 HgmErrCode HgmMultiAppStrategy::GetFocusAppStrategyConfig(PolicyConfigData::StrategyConfig& strategyRes)
211 {
212 auto [pkgName, pid, appType] = AnalyzePkgParam(pkgs_.empty() ? "" : pkgs_.front());
213 return GetAppStrategyConfig(pkgName, strategyRes);
214 }
215
CleanApp(pid_t pid)216 void HgmMultiAppStrategy::CleanApp(pid_t pid)
217 {
218 foregroundPidAppMap_.erase(pid);
219 backgroundPid_.Erase(pid);
220 }
221
UpdateXmlConfigCache()222 void HgmMultiAppStrategy::UpdateXmlConfigCache()
223 {
224 auto& hgmCore = HgmCore::Instance();
225 auto frameRateMgr = hgmCore.GetFrameRateMgr();
226
227 auto configData = hgmCore.GetPolicyConfigData();
228 if (configData == nullptr || frameRateMgr == nullptr) {
229 HGM_LOGD("configData or frameRateMgr is null");
230 return;
231 }
232
233 // udpate strategyConfigMapCache_
234 strategyConfigMapCache_ = configData->strategyConfigs_;
235
236 // update screenSettingCache_
237 auto curScreenStrategyId = frameRateMgr->GetCurScreenStrategyId();
238 if (configData->screenConfigs_.find(curScreenStrategyId) == configData->screenConfigs_.end()) {
239 HGM_LOGD("curScreenStrategyId not existed: %{public}s", curScreenStrategyId.c_str());
240 return;
241 }
242 auto& screenConfig = configData->screenConfigs_[curScreenStrategyId];
243
244 auto curRefreshRateMode = std::to_string(frameRateMgr->GetCurRefreshRateMode());
245 if (screenConfig.find(curRefreshRateMode) == screenConfig.end()) {
246 HGM_LOGD("curRefreshRateMode not existed: %{public}s", curRefreshRateMode.c_str());
247 return;
248 }
249
250 screenSettingCache_ = screenConfig[curRefreshRateMode];
251 }
252
GetStrategyConfig(const std::string & strategyName,PolicyConfigData::StrategyConfig & strategyRes)253 HgmErrCode HgmMultiAppStrategy::GetStrategyConfig(
254 const std::string& strategyName, PolicyConfigData::StrategyConfig& strategyRes)
255 {
256 if (strategyConfigMapCache_.find(strategyName) != strategyConfigMapCache_.end()) {
257 strategyRes = strategyConfigMapCache_.at(strategyName);
258 return EXEC_SUCCESS;
259 }
260 return HGM_ERROR;
261 }
262
GetAppStrategyConfig(const std::string & pkgName,PolicyConfigData::StrategyConfig & strategyRes)263 HgmErrCode HgmMultiAppStrategy::GetAppStrategyConfig(
264 const std::string& pkgName, PolicyConfigData::StrategyConfig& strategyRes)
265 {
266 auto configVisitor = HgmCore::Instance().GetPolicyConfigVisitor();
267 if (configVisitor != nullptr && configVisitor->GetDynamicAppStrategyConfig(pkgName, strategyRes) == EXEC_SUCCESS) {
268 return EXEC_SUCCESS;
269 }
270 return GetStrategyConfig(GetAppStrategyConfigName(pkgName), strategyRes);
271 }
272
UseStrategyNum()273 void HgmMultiAppStrategy::UseStrategyNum()
274 {
275 auto& strategyName = screenSettingCache_.multiAppStrategyName;
276 RS_TRACE_NAME_FMT("[UseStrategyNum] strategyName:%s", strategyName.c_str());
277 if (strategyConfigMapCache_.find(strategyName) != strategyConfigMapCache_.end()) {
278 voteRes_.first = EXEC_SUCCESS;
279 voteRes_.second = strategyConfigMapCache_.at(strategyName);
280 OnLightFactor(voteRes_.second);
281 UpdateStrategyByTouch(voteRes_.second, touchInfo_.pkgName);
282 }
283 }
284
FollowFocus()285 void HgmMultiAppStrategy::FollowFocus()
286 {
287 RS_TRACE_FUNC();
288 auto [pkgName, pid, appType] = AnalyzePkgParam(pkgs_.empty() ? "" : pkgs_.front());
289 if (voteRes_.first = GetAppStrategyConfig(pkgName, voteRes_.second); voteRes_.first == EXEC_SUCCESS) {
290 OnLightFactor(voteRes_.second);
291 UpdateStrategyByTouch(voteRes_.second, pkgName);
292 } else {
293 HGM_LOGD("[xml] not find pkg cfg: %{public}s", pkgName.c_str());
294 }
295 }
296
UseMax()297 void HgmMultiAppStrategy::UseMax()
298 {
299 RS_TRACE_FUNC();
300 PolicyConfigData::StrategyConfig pkgStrategyConfig;
301 for (const auto& param : pkgs_) {
302 auto [pkgName, pid, appType] = AnalyzePkgParam(param);
303 if (GetAppStrategyConfig(pkgName, pkgStrategyConfig) != EXEC_SUCCESS) {
304 continue;
305 }
306 auto isVoteSuccess = voteRes_.first;
307 OnLightFactor(pkgStrategyConfig);
308 UpdateStrategyByTouch(pkgStrategyConfig, pkgName);
309 HGM_LOGD("app %{public}s res: [%{public}d, %{public}d]",
310 pkgName.c_str(), voteRes_.second.min, voteRes_.second.max);
311 if (isVoteSuccess != EXEC_SUCCESS) {
312 voteRes_.first = EXEC_SUCCESS;
313 voteRes_.second = pkgStrategyConfig;
314 continue;
315 }
316 auto& strategyRes = voteRes_.second;
317 strategyRes.min = strategyRes.min > pkgStrategyConfig.min ? strategyRes.min : pkgStrategyConfig.min;
318 strategyRes.max = strategyRes.max > pkgStrategyConfig.max ? strategyRes.max : pkgStrategyConfig.max;
319 }
320 }
321
AnalyzePkgParam(const std::string & param)322 std::tuple<std::string, pid_t, int32_t> HgmMultiAppStrategy::AnalyzePkgParam(const std::string& param)
323 {
324 std::string pkgName = param;
325 pid_t pid = DEFAULT_PID;
326 int32_t appType = DEFAULT_APP_TYPE;
327
328 auto index = param.find(":");
329 if (index == std::string::npos) {
330 return { pkgName, pid, appType };
331 }
332
333 // split by : index
334 pkgName = param.substr(0, index);
335 auto pidAppType = param.substr(index + 1, param.size());
336 index = pidAppType.find(":");
337 if (index == std::string::npos) {
338 if (XMLParser::IsNumber(pidAppType)) {
339 pid = static_cast<pid_t>(std::stoi(pidAppType));
340 }
341 return { pkgName, pid, appType };
342 }
343
344 // split by : index
345 auto pidStr = pidAppType.substr(0, index);
346 if (XMLParser::IsNumber(pidStr)) {
347 pid = static_cast<pid_t>(std::stoi(pidStr));
348 }
349
350 auto appTypeStr = pidAppType.substr(index + 1, pidAppType.size());
351 if (XMLParser::IsNumber(appTypeStr)) {
352 appType = std::stoi(appTypeStr);
353 }
354
355 return { pkgName, pid, appType };
356 }
357
OnLightFactor(PolicyConfigData::StrategyConfig & strategyRes) const358 void HgmMultiAppStrategy::OnLightFactor(PolicyConfigData::StrategyConfig& strategyRes) const
359 {
360 HGM_LOGD("lightFactorStatus:%{public}d, isFactor:%{public}u, lowAmbientStatus:%{public}u",
361 lightFactorStatus_.load(), strategyRes.isFactor, lowAmbientStatus_);
362 if (!isLtpo_ && lowAmbientStatus_ && lightFactorStatus_.load() == LightFactorStatus::LOW_LEVEL) {
363 strategyRes.min = strategyRes.max;
364 return;
365 }
366 if (lightFactorStatus_.load() == LightFactorStatus::NORMAL_LOW && strategyRes.isFactor && !lowAmbientStatus_) {
367 RS_TRACE_NAME_FMT("OnLightFactor, strategy change: min -> max");
368 strategyRes.min = strategyRes.max;
369 }
370 }
371
UpdateStrategyByTouch(PolicyConfigData::StrategyConfig & strategy,const std::string & pkgName,bool forceUpdate)372 void HgmMultiAppStrategy::UpdateStrategyByTouch(
373 PolicyConfigData::StrategyConfig& strategy, const std::string& pkgName, bool forceUpdate)
374 {
375 auto frameRateMgr = HgmCore::Instance().GetFrameRateMgr();
376 if (uniqueTouchInfo_ == nullptr || frameRateMgr == nullptr) {
377 return;
378 }
379
380 if (uniqueTouchInfo_->touchState == TouchState::DOWN_STATE &&
381 (!HgmCore::Instance().GetEnableDynamicMode() || strategy.dynamicMode == DynamicModeType::TOUCH_DISENABLED)) {
382 return;
383 }
384
385 if (uniqueTouchInfo_->touchState == TouchState::IDLE_STATE) {
386 uniqueTouchInfo_ = nullptr;
387 frameRateMgr->HandleRefreshRateEvent(DEFAULT_PID, {"VOTER_TOUCH", false});
388 return;
389 }
390
391 auto voteTouchFunc = [this, frameRateMgr](const PolicyConfigData::StrategyConfig& strategy) {
392 auto touchInfo = std::move(uniqueTouchInfo_);
393 if (touchInfo->touchState == TouchState::DOWN_STATE) {
394 RS_TRACE_NAME_FMT("[UpdateStrategyByTouch] pkgName:%s, state:%d, downFps:%d",
395 touchInfo->pkgName.c_str(), touchInfo->touchState, strategy.down);
396 frameRateMgr->HandleRefreshRateEvent(DEFAULT_PID, {"VOTER_TOUCH", true, strategy.down, strategy.down});
397 } else if (touchInfo->touchState == TouchState::UP_STATE && touchInfo->upExpectFps > 0) {
398 RS_TRACE_NAME_FMT("[UpdateStrategyByTouch] pkgName:%s, state:%d, upExpectFps:%d",
399 touchInfo->pkgName.c_str(), touchInfo->touchState, touchInfo->upExpectFps);
400 frameRateMgr->HandleRefreshRateEvent(DEFAULT_PID,
401 {"VOTER_TOUCH", true, touchInfo->upExpectFps, touchInfo->upExpectFps});
402 }
403 };
404
405 if (forceUpdate) {
406 // click pkg which not config
407 HGM_LOGD("force update touch info");
408 PolicyConfigData::StrategyConfig settingStrategy;
409 if (GetAppStrategyConfig("", settingStrategy) != EXEC_SUCCESS ||
410 settingStrategy.dynamicMode == DynamicModeType::TOUCH_DISENABLED) {
411 return;
412 }
413 voteTouchFunc(settingStrategy);
414 } else {
415 if (uniqueTouchInfo_->touchState == TouchState::DOWN_STATE && pkgName != uniqueTouchInfo_->pkgName) {
416 return;
417 }
418 voteTouchFunc(strategy);
419 }
420 }
421
OnStrategyChange()422 void HgmMultiAppStrategy::OnStrategyChange()
423 {
424 HGM_LOGD("multi app strategy change: [%{public}d, %{public}d]", voteRes_.second.min, voteRes_.second.max);
425 for (const auto& callback : strategyChangeCallbacks_) {
426 if (callback != nullptr) {
427 callback(voteRes_.second);
428 }
429 }
430 }
431
432 // use in temporary scheme to check package name
CheckPackageInConfigList(const std::vector<std::string> & pkgs)433 void HgmMultiAppStrategy::CheckPackageInConfigList(const std::vector<std::string>& pkgs)
434 {
435 auto& rsCommonHook = RsCommonHook::Instance();
436 auto& hgmCore = HgmCore::Instance();
437 auto configData = hgmCore.GetPolicyConfigData();
438 if (configData == nullptr) {
439 return;
440 }
441 rsCommonHook.SetVideoSurfaceFlag(false);
442 rsCommonHook.SetHardwareEnabledByHwcnodeBelowSelfInAppFlag(false);
443 rsCommonHook.SetHardwareEnabledByBackgroundAlphaFlag(false);
444 rsCommonHook.SetIsWhiteListForSolidColorLayerFlag(false);
445 std::unordered_map<std::string, std::string>& videoConfigFromHgm = configData->sourceTuningConfig_;
446 std::unordered_map<std::string, std::string>& solidLayerConfigFromHgm = configData->solidLayerConfig_;
447 std::unordered_map<std::string, std::string>& hwcVideoConfigFromHgm = configData->hwcSourceTuningConfig_;
448 std::unordered_map<std::string, std::string>& hwcSolidLayerConfigFromHgm = configData->hwcSolidLayerConfig_;
449 HgmEnergyConsumptionPolicy::Instance().SetCurrentPkgName(pkgs);
450 if (pkgs.size() > 1) {
451 return;
452 }
453 for (auto& param: pkgs) {
454 std::string pkgNameForCheck = param.substr(0, param.find(':'));
455 // 1 means crop source tuning
456 auto videoIter = videoConfigFromHgm.find(pkgNameForCheck);
457 auto hwcVideoIter = hwcVideoConfigFromHgm.find(pkgNameForCheck);
458 if ((videoIter != videoConfigFromHgm.end() && videoIter->second == "1") ||
459 (hwcVideoIter != hwcVideoConfigFromHgm.end() && hwcVideoIter->second == "1")) {
460 rsCommonHook.SetVideoSurfaceFlag(true);
461 // 2 means skip hardware disabled by hwc node and background alpha
462 } else if ((videoIter != videoConfigFromHgm.end() && videoIter->second == "2") ||
463 (hwcVideoIter != hwcVideoConfigFromHgm.end() && hwcVideoIter->second == "2")) {
464 rsCommonHook.SetHardwareEnabledByHwcnodeBelowSelfInAppFlag(true);
465 rsCommonHook.SetHardwareEnabledByBackgroundAlphaFlag(true);
466 }
467 // 1 means enable dss by solid color layer
468 auto iter = solidLayerConfigFromHgm.find(pkgNameForCheck);
469 auto hwcIter = hwcSolidLayerConfigFromHgm.find(pkgNameForCheck);
470 if ((iter != solidLayerConfigFromHgm.end() && iter->second == "1") ||
471 (hwcIter != hwcSolidLayerConfigFromHgm.end() && hwcIter->second == "1")) {
472 rsCommonHook.SetIsWhiteListForSolidColorLayerFlag(true);
473 }
474 }
475 }
476 } // namespace Rosen
477 } // namespace OHOS