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 ¶m : 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 ¶m : 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 ¶m: 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