• 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 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