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