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_energy_consumption_policy.h"
17
18 #include <functional>
19
20 #include "hgm_core.h"
21 #include "hgm_log.h"
22 #include "hgm_task_handle_thread.h"
23 #include "rs_trace.h"
24 #include "xml_parser.h"
25
26 #include "common/rs_common_hook.h"
27
28 namespace OHOS::Rosen {
29
30 const static std::string RS_ENERGY_ASSURANCE_TASK_ID = "RS_ENERGY_ASSURANCE_TASK_ID";
31 const static std::string DESCISION_VIDEO_CALL_TASK_ID = "DESCISION_VIDEO_CALL_TASK_ID";
32 static const std::unordered_map<std::string, uint32_t> UI_RATE_TYPE_NAME_MAP = {
33 {"ui_animation", UI_ANIMATION_FRAME_RATE_TYPE },
34 {"display_sync", DISPLAY_SYNC_FRAME_RATE_TYPE },
35 {"ace_component", ACE_COMPONENT_FRAME_RATE_TYPE },
36 {"display_soloist", DISPLAY_SOLOIST_FRAME_RATE_TYPE },
37 };
38 constexpr int DEFAULT_ENERGY_ASSURANCE_IDLE_FPS = 60;
39 constexpr int DEFAULT_ANIMATION_IDLE_DURATION = 2000;
40 constexpr int64_t DEFAULT_RS_ANIMATION_TOUCH_UP_TIME = 1000;
41 constexpr int32_t UNKNOWN_IDLE_FPS = -1;
42 constexpr int64_t DESCISION_VIDEO_CALL_TIME = 1000;
43
HgmEnergyConsumptionPolicy()44 HgmEnergyConsumptionPolicy::HgmEnergyConsumptionPolicy()
45 {
46 RsCommonHook::Instance().RegisterStartNewAnimationListener([this](const std::string& componentName) {
47 if (isAnimationEnergyConsumptionAssuranceMode_) {
48 HgmTaskHandleThread::Instance().PostTask([this, componentName]() { StartNewAnimation(componentName); });
49 }
50 });
51 RsCommonHook::Instance().SetComponentPowerFpsFunc(
52 std::bind(&HgmEnergyConsumptionPolicy::GetComponentFps, this, std::placeholders::_1));
53 }
54
Instance()55 HgmEnergyConsumptionPolicy& HgmEnergyConsumptionPolicy::Instance()
56 {
57 static HgmEnergyConsumptionPolicy hlpp;
58 return hlpp;
59 }
60
ConverStrToInt(int & targetNum,std::string sourceStr,int defaultValue)61 void HgmEnergyConsumptionPolicy::ConverStrToInt(int& targetNum, std::string sourceStr, int defaultValue)
62 {
63 if (!XMLParser::IsNumber(sourceStr)) {
64 targetNum = defaultValue;
65 return;
66 }
67 targetNum = std::stoi(sourceStr.c_str());
68 }
69
SetEnergyConsumptionConfig(std::unordered_map<std::string,std::string> animationPowerConfig)70 void HgmEnergyConsumptionPolicy::SetEnergyConsumptionConfig(
71 std::unordered_map<std::string, std::string> animationPowerConfig)
72 {
73 auto isEnable = animationPowerConfig.find("animation_energy_assurance_enable");
74 isAnimationEnergyAssuranceEnable_ = false;
75 if (isEnable != animationPowerConfig.end() && isEnable->second == "true") {
76 isAnimationEnergyAssuranceEnable_ = true;
77 }
78
79 if (!isAnimationEnergyAssuranceEnable_) {
80 HGM_LOGD("HgmEnergyConsumptionPolicy::SetEnergyConsumptionConfig isAnimationLtpoPowerEnable is false");
81 return;
82 }
83
84 auto idleFps = animationPowerConfig.find("animation_idle_fps");
85 animationIdleFps_ = DEFAULT_ENERGY_ASSURANCE_IDLE_FPS;
86 if (idleFps != animationPowerConfig.end()) {
87 ConverStrToInt(animationIdleFps_, idleFps->second, DEFAULT_ENERGY_ASSURANCE_IDLE_FPS);
88 }
89
90 auto idleDuration = animationPowerConfig.find("animation_idle_duration");
91 animationIdleDuration_ = DEFAULT_ANIMATION_IDLE_DURATION;
92 if (idleDuration != animationPowerConfig.end()) {
93 ConverStrToInt(animationIdleDuration_, idleDuration->second, DEFAULT_ANIMATION_IDLE_DURATION);
94 }
95
96 auto touchUpTime = animationPowerConfig.find("animation_touch_up_duration");
97 rsAnimationTouchIdleTime_ = DEFAULT_RS_ANIMATION_TOUCH_UP_TIME;
98 if (touchUpTime != animationPowerConfig.end()) {
99 int delayTime = 0;
100 ConverStrToInt(delayTime, touchUpTime->second, DEFAULT_RS_ANIMATION_TOUCH_UP_TIME);
101 rsAnimationTouchIdleTime_ = delayTime;
102 }
103 HGM_LOGD("HgmEnergyConsumptionPolicy::SetEnergyConsumptionConfig update config success");
104 }
105
SetUiEnergyConsumptionConfig(std::unordered_map<std::string,std::string> uiPowerConfig)106 void HgmEnergyConsumptionPolicy::SetUiEnergyConsumptionConfig(
107 std::unordered_map<std::string, std::string> uiPowerConfig)
108 {
109 uiEnergyAssuranceMap_.clear();
110 for (auto config : uiPowerConfig) {
111 std::string rateTypeName = config.first;
112 auto it = UI_RATE_TYPE_NAME_MAP.find(rateTypeName);
113 if (it == UI_RATE_TYPE_NAME_MAP.end()) {
114 HGM_LOGD("HgmEnergyConsumptionPolicy::SetUiEnergyConsumptionConfig the rateType is invalid");
115 continue;
116 }
117 int idleFps = 60;
118 ConverStrToInt(idleFps, config.second, DEFAULT_ENERGY_ASSURANCE_IDLE_FPS);
119 uiEnergyAssuranceMap_[it->second] = std::make_pair(true, idleFps);
120 }
121 }
122
SetAnimationEnergyConsumptionAssuranceMode(bool isEnergyConsumptionAssuranceMode)123 void HgmEnergyConsumptionPolicy::SetAnimationEnergyConsumptionAssuranceMode(bool isEnergyConsumptionAssuranceMode)
124 {
125 if (!isAnimationEnergyAssuranceEnable_ ||
126 isAnimationEnergyConsumptionAssuranceMode_ == isEnergyConsumptionAssuranceMode) {
127 return;
128 }
129 isAnimationEnergyConsumptionAssuranceMode_ = isEnergyConsumptionAssuranceMode;
130 firstAnimationTimestamp_ = HgmCore::Instance().GetCurrentTimestamp() / NS_PER_MS;
131 lastAnimationTimestamp_ = firstAnimationTimestamp_.load();
132 }
133
StatisticAnimationTime(uint64_t timestamp)134 void HgmEnergyConsumptionPolicy::StatisticAnimationTime(uint64_t timestamp)
135 {
136 if (!isAnimationEnergyAssuranceEnable_ || !isAnimationEnergyConsumptionAssuranceMode_) {
137 return;
138 }
139 lastAnimationTimestamp_ = timestamp;
140 }
141
StartNewAnimation(const std::string & componentName)142 void HgmEnergyConsumptionPolicy::StartNewAnimation(const std::string &componentName)
143 {
144 auto idleFps = GetComponentEnergyConsumptionConfig(componentName);
145 if (idleFps != UNKNOWN_IDLE_FPS) {
146 return;
147 }
148 if (!isAnimationEnergyAssuranceEnable_ || !isAnimationEnergyConsumptionAssuranceMode_) {
149 return;
150 }
151 firstAnimationTimestamp_ = HgmCore::Instance().GetCurrentTimestamp() / NS_PER_MS;
152 lastAnimationTimestamp_ = firstAnimationTimestamp_.load();
153 }
154
SetTouchState(TouchState touchState)155 void HgmEnergyConsumptionPolicy::SetTouchState(TouchState touchState)
156 {
157 if (touchState == TouchState::IDLE_STATE) {
158 isTouchIdle_ = true;
159 return;
160 }
161
162 HgmTaskHandleThread::Instance().RemoveEvent(RS_ENERGY_ASSURANCE_TASK_ID);
163 // touch
164 if (touchState == TouchState::DOWN_STATE) {
165 isTouchIdle_ = false;
166 SetAnimationEnergyConsumptionAssuranceMode(false);
167 } else if (touchState == TouchState::UP_STATE) {
168 HgmTaskHandleThread::Instance().PostEvent(
169 RS_ENERGY_ASSURANCE_TASK_ID, [this]() { SetAnimationEnergyConsumptionAssuranceMode(true); },
170 rsAnimationTouchIdleTime_);
171 }
172 }
173
GetComponentFps(FrameRateRange & range)174 void HgmEnergyConsumptionPolicy::GetComponentFps(FrameRateRange& range)
175 {
176 if (!isTouchIdle_) {
177 return;
178 }
179 auto idleFps = GetComponentEnergyConsumptionConfig(range.GetComponentName());
180 if (idleFps != UNKNOWN_IDLE_FPS) {
181 SetEnergyConsumptionRateRange(range, idleFps);
182 }
183 }
184
GetAnimationIdleFps(FrameRateRange & rsRange)185 void HgmEnergyConsumptionPolicy::GetAnimationIdleFps(FrameRateRange& rsRange)
186 {
187 if (!isAnimationEnergyAssuranceEnable_ || !isAnimationEnergyConsumptionAssuranceMode_) {
188 return;
189 }
190 // The animation takes effect after a certain period of time
191 if (lastAnimationTimestamp_ <= firstAnimationTimestamp_ ||
192 (lastAnimationTimestamp_ - firstAnimationTimestamp_) < static_cast<uint64_t>(animationIdleDuration_)) {
193 return;
194 }
195 SetEnergyConsumptionRateRange(rsRange, animationIdleFps_);
196 }
197
GetUiIdleFps(FrameRateRange & rsRange)198 bool HgmEnergyConsumptionPolicy::GetUiIdleFps(FrameRateRange& rsRange)
199 {
200 if (!isTouchIdle_) {
201 return false;
202 }
203 auto it = uiEnergyAssuranceMap_.find(rsRange.type_ & ~ANIMATION_STATE_FIRST_FRAME);
204 if (it == uiEnergyAssuranceMap_.end()) {
205 HGM_LOGD("HgmEnergyConsumptionPolicy::GetUiIdleFps the rateType = %{public}d is invalid", rsRange.type_);
206 return false;
207 }
208 bool isEnergyAssuranceEnable = it->second.first;
209 int idleFps = it->second.second;
210 if (isEnergyAssuranceEnable) {
211 SetEnergyConsumptionRateRange(rsRange, idleFps);
212 }
213 return true;
214 }
215
SetRefreshRateMode(int32_t currentRefreshMode,std::string curScreenStrategyId)216 void HgmEnergyConsumptionPolicy::SetRefreshRateMode(int32_t currentRefreshMode, std::string curScreenStrategyId)
217 {
218 currentRefreshMode_ = currentRefreshMode;
219 curScreenStrategyId_ = curScreenStrategyId;
220 }
221
SetEnergyConsumptionRateRange(FrameRateRange & rsRange,int idleFps)222 void HgmEnergyConsumptionPolicy::SetEnergyConsumptionRateRange(FrameRateRange& rsRange, int idleFps)
223 {
224 if (rsRange.preferred_ > idleFps) {
225 rsRange.isEnergyAssurance_ = true;
226 }
227 rsRange.max_ = std::min(rsRange.max_, idleFps);
228 rsRange.min_ = std::min(rsRange.min_, idleFps);
229 rsRange.preferred_ = std::min(rsRange.preferred_, idleFps);
230 }
231
PrintEnergyConsumptionLog(const FrameRateRange & rsRange)232 void HgmEnergyConsumptionPolicy::PrintEnergyConsumptionLog(const FrameRateRange& rsRange)
233 {
234 std::string lastAssuranceLog = "NO_CONSUMPTION_ASSURANCE";
235 if (!rsRange.isEnergyAssurance_) {
236 if (lastAssuranceLog_ == lastAssuranceLog) {
237 return;
238 }
239 lastAssuranceLog_ = lastAssuranceLog;
240 RS_TRACE_NAME_FMT("SetEnergyConsumptionRateRange rateType:%s", lastAssuranceLog_.c_str());
241 HGM_LOGD("change power policy is %{public}s", lastAssuranceLog.c_str());
242 return;
243 }
244
245 if (rsRange.GetComponentName() != "UNKNOWN_SCENE") {
246 lastAssuranceLog = std::string("COMPONENT_ASSURANCE[ ") + rsRange.GetComponentName() + "]";
247 if (lastAssuranceLog_ == lastAssuranceLog) {
248 return;
249 }
250 lastAssuranceLog_ = lastAssuranceLog;
251 RS_TRACE_NAME_FMT("SetEnergyConsumptionRateRange rateType:%s", lastAssuranceLog_.c_str());
252 HGM_LOGD("change power policy is %{public}s", lastAssuranceLog.c_str());
253 return;
254 }
255
256 lastAssuranceLog = rsRange.GetExtInfo();
257 if (lastAssuranceLog == "" || lastAssuranceLog_ == lastAssuranceLog) {
258 return;
259 }
260 lastAssuranceLog_ = lastAssuranceLog;
261 RS_TRACE_NAME_FMT("SetEnergyConsumptionRateRange rateType:%s", lastAssuranceLog_.c_str());
262 HGM_LOGD("change power policy is %{public}s", lastAssuranceLog.c_str());
263 }
264
SetVideoCallSceneInfo(const EventInfo & eventInfo)265 void HgmEnergyConsumptionPolicy::SetVideoCallSceneInfo(const EventInfo &eventInfo)
266 {
267 if (isEnableVideoCall_.load() && !eventInfo.eventStatus) {
268 videoCallVsyncName_ = "";
269 videoCallPid_.store(DEFAULT_PID);
270 videoCallMaxFrameRate_ = 0;
271 isEnableVideoCall_.store(false);
272 isVideoCallVsyncChange_.store(false);
273 }
274 if (eventInfo.eventStatus) {
275 auto [vsyncName, pid, _] = HgmMultiAppStrategy::AnalyzePkgParam(eventInfo.description);
276 if (pid == DEFAULT_PID) {
277 HGM_LOGD("SetVideoCallSceneInfo set videoCall pid error");
278 return;
279 }
280 videoCallVsyncName_ = vsyncName;
281 videoCallPid_ = pid;
282 isEnableVideoCall_.store(true);
283 videoCallMaxFrameRate_ = static_cast<int>(eventInfo.maxRefreshRate);
284 isVideoCallVsyncChange_.store(true);
285 HGM_LOGD("SetVideoCallSceneInfo set videoCall VsyncName = %s, pid = %d", vsyncName.c_str(),
286 (int)videoCallPid_.load());
287 }
288 isSubmitDecisionTask_.store(false);
289 isOnlyVideoCallExist_.store(false);
290 videoBufferCount_.store(0);
291 }
292
StatisticsVideoCallBufferCount(pid_t pid,const std::string & surfaceName)293 void HgmEnergyConsumptionPolicy::StatisticsVideoCallBufferCount(pid_t pid, const std::string &surfaceName)
294 {
295 if (!isEnableVideoCall_.load() || pid != videoCallPid_.load()) {
296 return;
297 }
298 std::string videoCallLayerName;
299 {
300 std::lock_guard<std::mutex> lock(videoCallLock_);
301 videoCallLayerName = videoCallLayerName_;
302 }
303 if (videoCallLayerName != "" && surfaceName.find(videoCallLayerName) != std::string::npos) {
304 videoBufferCount_.fetch_add(1);
305 }
306 }
307
CheckOnlyVideoCallExist()308 void HgmEnergyConsumptionPolicy::CheckOnlyVideoCallExist()
309 {
310 if (!isEnableVideoCall_.load()) {
311 return;
312 }
313 if (videoBufferCount_.load() > 1 && (isOnlyVideoCallExist_.load() || isSubmitDecisionTask_.load())) {
314 HgmTaskHandleThread::Instance().RemoveEvent(DESCISION_VIDEO_CALL_TASK_ID);
315 isSubmitDecisionTask_.store(false);
316 if (isOnlyVideoCallExist_.load()) {
317 isOnlyVideoCallExist_.store(false);
318 isVideoCallVsyncChange_.store(true);
319 }
320 return;
321 }
322 if (videoBufferCount_.load() == 1 && !isOnlyVideoCallExist_.load() && !isSubmitDecisionTask_.load()) {
323 HgmTaskHandleThread::Instance().PostEvent(
324 DESCISION_VIDEO_CALL_TASK_ID,
325 [this]() {
326 isOnlyVideoCallExist_.store(true);
327 isVideoCallVsyncChange_.store(true);
328 },
329 DESCISION_VIDEO_CALL_TIME);
330 isSubmitDecisionTask_.store(true);
331 }
332 videoBufferCount_.store(0);
333 }
334
GetVideoCallVsyncChange()335 bool HgmEnergyConsumptionPolicy::GetVideoCallVsyncChange()
336 {
337 auto result = isVideoCallVsyncChange_.load();
338 isVideoCallVsyncChange_.store(false);
339 return result;
340 }
341
GetVideoCallFrameRate(pid_t pid,const std::string & vsyncName,FrameRateRange & finalRange)342 void HgmEnergyConsumptionPolicy::GetVideoCallFrameRate(
343 pid_t pid, const std::string& vsyncName, FrameRateRange& finalRange)
344 {
345 if (!isEnableVideoCall_.load() || pid != videoCallPid_.load() || vsyncName != videoCallVsyncName_ ||
346 !isOnlyVideoCallExist_.load() || videoCallMaxFrameRate_ == 0) {
347 return;
348 }
349 finalRange.Merge({ OLED_NULL_HZ, OLED_144_HZ, videoCallMaxFrameRate_ });
350 RS_TRACE_NAME_FMT("GetVideoCallFrameRate limit video call frame rate %d", finalRange.preferred_);
351 }
352
SetCurrentPkgName(const std::vector<std::string> & pkgs)353 void HgmEnergyConsumptionPolicy::SetCurrentPkgName(const std::vector<std::string>& pkgs)
354 {
355 if (pkgs.size() != 1) {
356 std::lock_guard<std::mutex> lock(videoCallLock_);
357 videoCallLayerName_ = "";
358 return;
359 }
360 auto configData = HgmCore::Instance().GetPolicyConfigData();
361 if (configData == nullptr) {
362 return;
363 }
364 std::string pkgName = pkgs[0].substr(0, pkgs[0].find(":"));
365 auto& videoCallLayerConfig = configData->videoCallLayerConfig_;
366 auto videoCallLayerName = videoCallLayerConfig.find(pkgName);
367 std::lock_guard<std::mutex> lock(videoCallLock_);
368 videoCallLayerName_ = videoCallLayerName == videoCallLayerConfig.end() ? "" : videoCallLayerName->second;
369 }
370
GetComponentEnergyConsumptionConfig(const std::string & componentName)371 int32_t HgmEnergyConsumptionPolicy::GetComponentEnergyConsumptionConfig(const std::string& componentName)
372 {
373 const auto& configData = HgmCore::Instance().GetPolicyConfigData();
374 if (!configData) {
375 return UNKNOWN_IDLE_FPS;
376 }
377 const auto settingMode = std::to_string(currentRefreshMode_);
378 const auto curScreenStrategyId = curScreenStrategyId_;
379 if (configData->screenConfigs_.count(curScreenStrategyId_) &&
380 configData->screenConfigs_[curScreenStrategyId_].count(settingMode)) {
381 auto& screenConfig = configData->screenConfigs_[curScreenStrategyId_][settingMode];
382 auto idleFps = UNKNOWN_IDLE_FPS;
383 if (screenConfig.componentPowerConfig.count(componentName)) {
384 idleFps = screenConfig.componentPowerConfig[componentName];
385 }
386 return idleFps;
387 }
388 return UNKNOWN_IDLE_FPS;
389 }
390
391 } // namespace OHOS::Rosen