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