• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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