• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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