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