1 /*
2 * Copyright (c) 2025 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_frame_voter.h"
17
18 #include "hgm_core.h"
19
20 namespace OHOS {
21 namespace Rosen {
22 namespace {
23 constexpr uint32_t DEFAULT_PRIORITY = 0;
24 constexpr uint32_t VOTER_SCENE_PRIORITY_BEFORE_PACKAGES = 1;
25 constexpr uint32_t VOTER_LTPO_PRIORITY_BEFORE_PACKAGES = 2;
26 // CAUTION: with priority
27 const std::string VOTER_NAME[] = {
28 "VOTER_THERMAL",
29 "VOTER_VIRTUALDISPLAY_FOR_CAR",
30 "VOTER_VIRTUALDISPLAY",
31 "VOTER_MUTIPHYSICALSCREEN",
32 "VOTER_MULTISELFOWNEDSCREEN",
33 "VOTER_POWER_MODE",
34 "VOTER_DISPLAY_ENGINE",
35 "VOTER_GAMES",
36 "VOTER_ANCO",
37
38 "VOTER_PAGE_URL",
39 "VOTER_PACKAGES",
40 "VOTER_LTPO",
41 "VOTER_TOUCH",
42 "VOTER_POINTER",
43 "VOTER_SCENE",
44 "VOTER_VIDEO",
45 "VOTER_IDLE"
46 };
47 }
48
HgmFrameVoter(HgmMultiAppStrategy & multiAppStrategy)49 HgmFrameVoter::HgmFrameVoter(HgmMultiAppStrategy& multiAppStrategy)
50 : voters_(std::begin(VOTER_NAME), std::end(VOTER_NAME)), multiAppStrategy_(multiAppStrategy)
51 {
52 HGM_LOGI("Construction of HgmFrameVoter");
53 for (auto& voter : voters_) {
54 voteRecord_[voter] = {{}, true};
55 }
56 }
57
CleanVote(pid_t pid)58 void HgmFrameVoter::CleanVote(pid_t pid)
59 {
60 if (pidRecord_.count(pid) == 0) {
61 return;
62 }
63 HGM_LOGW("CleanVote: i am [%{public}d], i died, clean my votes please.", pid);
64 pidRecord_.erase(pid);
65
66 for (auto& [voterName, voterInfo] : voteRecord_) {
67 for (auto iter = voterInfo.first.begin(); iter != voterInfo.first.end();) {
68 if (iter->pid == pid) {
69 auto voter = iter->voterName;
70 iter = voterInfo.first.erase(iter);
71 MarkVoteChange(voter);
72 break;
73 }
74 ++iter;
75 }
76 }
77 }
78
DeliverVote(const VoteInfo & voteInfo,bool eventStatus)79 void HgmFrameVoter::DeliverVote(const VoteInfo& voteInfo, bool eventStatus)
80 {
81 RS_TRACE_NAME_FMT("Deliver voter:%s(pid:%d extInfo:%s), status:%u, value:[%d-%d]",
82 voteInfo.voterName.c_str(), voteInfo.pid, voteInfo.extInfo.c_str(),
83 eventStatus, voteInfo.min, voteInfo.max);
84 if (voteInfo.min > voteInfo.max) {
85 HGM_LOGW("HgmFrameRateManager:invalid vote %{public}s(%{public}d %{public}s):[%{public}d, %{public}d]",
86 voteInfo.voterName.c_str(), voteInfo.pid, voteInfo.extInfo.c_str(), voteInfo.min, voteInfo.max);
87 return;
88 }
89
90 voteRecord_.try_emplace(voteInfo.voterName, std::pair<std::vector<VoteInfo>, bool>({{}, true}));
91 auto& vec = voteRecord_[voteInfo.voterName].first;
92
93 auto voter = voteInfo.voterName != "VOTER_PACKAGES" ? voteInfo.voterName : "";
94
95 // clear
96 if ((voteInfo.pid == 0) && (eventStatus == REMOVE_VOTE)) {
97 if (!vec.empty()) {
98 vec.clear();
99 MarkVoteChange(voter);
100 }
101 return;
102 }
103
104 for (auto it = vec.begin(); it != vec.end(); it++) {
105 if ((*it).pid != voteInfo.pid) {
106 continue;
107 }
108
109 if (eventStatus == REMOVE_VOTE) {
110 // remove
111 it = vec.erase(it);
112 MarkVoteChange(voter);
113 return;
114 }
115
116 if ((*it).min != voteInfo.min || (*it).max != voteInfo.max) {
117 // modify
118 vec.erase(it);
119 vec.push_back(voteInfo);
120 MarkVoteChange(voter);
121 } else if (voteInfo.voterName == "VOTER_PACKAGES") {
122 // force update cause VOTER_PACKAGES is flag of safe_voter
123 MarkVoteChange(voter);
124 }
125 return;
126 }
127
128 // add
129 if (eventStatus == ADD_VOTE) {
130 pidRecord_.insert(voteInfo.pid);
131 vec.push_back(voteInfo);
132 MarkVoteChange(voter);
133 }
134 }
135
ProcessVoteLog(const VoteInfo & curVoteInfo,bool isSkip)136 void HgmFrameVoter::ProcessVoteLog(const VoteInfo& curVoteInfo, bool isSkip)
137 {
138 RS_TRACE_NAME_FMT("Process voter:%s(pid:%d), value:[%d-%d]%s",
139 curVoteInfo.voterName.c_str(), curVoteInfo.pid, curVoteInfo.min, curVoteInfo.max, isSkip ? " skip" : "");
140 HGM_LOGD("Process: %{public}s(%{public}d):[%{public}d, %{public}d]%{public}s",
141 curVoteInfo.voterName.c_str(), curVoteInfo.pid, curVoteInfo.min, curVoteInfo.max, isSkip ? " skip" : "");
142 }
143
MergeLtpo2IdleVote(std::vector<std::string>::iterator & voterIter,VoteInfo & resultVoteInfo,VoteRange & mergedVoteRange)144 bool HgmFrameVoter::MergeLtpo2IdleVote(
145 std::vector<std::string>::iterator& voterIter, VoteInfo& resultVoteInfo, VoteRange& mergedVoteRange)
146 {
147 bool mergeSuccess = false;
148 bool existVoterLTPO = false;
149 // [VOTER_LTPO, VOTER_IDLE)
150 for (; voterIter != voters_.end() - 1; voterIter++) {
151 if (voteRecord_.find(*voterIter) == voteRecord_.end()) {
152 continue;
153 }
154 voteRecord_[*voterIter].second = true;
155 auto vec = voteRecord_[*voterIter].first;
156 if (vec.empty()) {
157 continue;
158 }
159
160 VoteInfo curVoteInfo = vec.back();
161 if (!multiAppStrategy_.CheckPidValid(curVoteInfo.pid)) {
162 ProcessVoteLog(curVoteInfo, true);
163 continue;
164 }
165 if (checkVote_ != nullptr && !checkVote_(*voterIter, curVoteInfo)) {
166 ProcessVoteLog(curVoteInfo, true);
167 continue;
168 }
169 if ((isDragScene_ || NeedSkipVoterTouch(existVoterLTPO)) && curVoteInfo.voterName == "VOTER_TOUCH") {
170 continue;
171 }
172 if (curVoteInfo.voterName == "VOTER_LTPO") {
173 existVoterLTPO = true;
174 }
175 ProcessVoteLog(curVoteInfo, false);
176 if (mergeSuccess) {
177 mergedVoteRange.first = mergedVoteRange.first > curVoteInfo.min ? mergedVoteRange.first : curVoteInfo.min;
178 if (curVoteInfo.max >= mergedVoteRange.second) {
179 mergedVoteRange.second = curVoteInfo.max;
180 resultVoteInfo.Merge(curVoteInfo);
181 }
182 } else {
183 resultVoteInfo.Merge(curVoteInfo);
184 mergedVoteRange = {curVoteInfo.min, curVoteInfo.max};
185 }
186 mergeSuccess = true;
187 }
188 return mergeSuccess;
189 }
190
ProcessVoteIter(std::vector<std::string>::iterator & voterIter,VoteInfo & resultVoteInfo,VoteRange & voteRange,bool & voterGamesEffective)191 bool HgmFrameVoter::ProcessVoteIter(std::vector<std::string>::iterator& voterIter,
192 VoteInfo& resultVoteInfo, VoteRange& voteRange, bool &voterGamesEffective)
193 {
194 VoteRange range;
195 VoteInfo info;
196 if (*voterIter == "VOTER_LTPO" && MergeLtpo2IdleVote(voterIter, info, range)) {
197 auto [mergeVoteRange, mergeVoteInfo] = HgmVoter::MergeRangeByPriority(voteRange, range);
198 if (mergeVoteInfo) {
199 resultVoteInfo.Merge(info);
200 }
201 if (mergeVoteRange) {
202 return true;
203 }
204 }
205
206 auto& voter = *voterIter;
207 if (voteRecord_.find(voter) == voteRecord_.end()) {
208 return false;
209 }
210 voteRecord_[voter].second = true;
211 auto& voteInfos = voteRecord_[voter].first;
212 auto firstValidVoteInfoIter = std::find_if(voteInfos.begin(), voteInfos.end(), [this](auto& voteInfo) {
213 if (!multiAppStrategy_.CheckPidValid(voteInfo.pid)) {
214 ProcessVoteLog(voteInfo, true);
215 return false;
216 }
217 return true;
218 });
219 if (firstValidVoteInfoIter == voteInfos.end()) {
220 return false;
221 }
222 auto curVoteInfo = *firstValidVoteInfoIter;
223 if (checkVote_ != nullptr && !checkVote_(voter, curVoteInfo)) {
224 ProcessVoteLog(curVoteInfo, true);
225 return false;
226 }
227 if (voter == "VOTER_GAMES") {
228 voterGamesEffective = true;
229 }
230 ProcessVoteLog(curVoteInfo, false);
231 auto [mergeVoteRange, mergeVoteInfo] =
232 HgmVoter::MergeRangeByPriority(voteRange, {curVoteInfo.min, curVoteInfo.max});
233 if (mergeVoteInfo) {
234 resultVoteInfo.Merge(curVoteInfo);
235 }
236 if (mergeVoteRange) {
237 return true;
238 }
239 return false;
240 }
241
ProcessVote(const std::string & curScreenStrategyId,ScreenId curScreenId,int32_t curRefreshRateMode)242 std::pair<VoteInfo, VoteRange> HgmFrameVoter::ProcessVote(const std::string& curScreenStrategyId,
243 ScreenId curScreenId, int32_t curRefreshRateMode)
244 {
245 if (updateVoteRule_ != nullptr) {
246 voters_ = std::vector<std::string>(std::begin(VOTER_NAME), std::end(VOTER_NAME));
247 updateVoteRule_(voters_);
248 }
249
250 VoteInfo resultVoteInfo;
251 VoteRange voteRange = { OLED_MIN_HZ, OLED_MAX_HZ };
252 auto& [min, max] = voteRange;
253
254 bool voterGamesEffective = false;
255 auto voterIter = voters_.begin();
256 for (; voterIter != voters_.end(); ++voterIter) {
257 if (ProcessVoteIter(voterIter, resultVoteInfo, voteRange, voterGamesEffective)) {
258 break;
259 }
260 }
261 voterGamesEffective_ = voterGamesEffective;
262 // update effective status
263 if (voterIter != voters_.end()) {
264 ++voterIter;
265 for (; voterIter != voters_.end(); ++voterIter) {
266 if (auto iter = voteRecord_.find(*voterIter); iter != voteRecord_.end()) {
267 iter->second.second = false;
268 }
269 }
270 }
271 if (voteRecord_["VOTER_PACKAGES"].second || voteRecord_["VOTER_LTPO"].second) {
272 voteRecord_["VOTER_SCENE"].second = true;
273 }
274 HGM_LOGD("Process: Strategy:%{public}s Screen:%{public}d Mode:%{public}d -- VoteResult:{%{public}d-%{public}d}",
275 curScreenStrategyId.c_str(), static_cast<int>(curScreenId), curRefreshRateMode, min, max);
276 return {resultVoteInfo, voteRange};
277 }
278 } // namespace Rosen
279 } // namespace OHOS
280