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