1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "PowerStatsProfileTokenGenerator.h"
18 
19 #include <string>
20 #include <unordered_map>
21 
22 namespace android::hardware::graphics::composer {
23 
PowerStatsProfileTokenGenerator()24 PowerStatsProfileTokenGenerator::PowerStatsProfileTokenGenerator() {
25     parseDisplayStateResidencyPattern();
26 }
27 
generateRefreshSourceToken(PowerStatsProfile * profile) const28 std::string PowerStatsProfileTokenGenerator::generateRefreshSourceToken(
29         PowerStatsProfile* profile) const {
30     if (profile->isOff()) {
31         return "";
32     }
33 
34     if (isPresentRefresh(profile->mRefreshSource)) {
35         return "p";
36     } else {
37         return "np";
38     }
39 }
40 
generateModeToken(PowerStatsProfile * profile) const41 std::string PowerStatsProfileTokenGenerator::generateModeToken(PowerStatsProfile* profile) const {
42     if (profile->isOff()) {
43         return "OFF";
44     } else {
45         if (profile->mPowerMode == HWC_POWER_MODE_DOZE) {
46             return "LPM";
47         }
48         return (profile->mBrightnessMode == BrightnessMode::kHighBrightnessMode) ? "HBM" : "NBM";
49     }
50 }
51 
generateWidthToken(PowerStatsProfile * profile) const52 std::string PowerStatsProfileTokenGenerator::generateWidthToken(PowerStatsProfile* profile) const {
53     if (profile->isOff()) {
54         return "";
55     }
56     return std::to_string(profile->mWidth);
57 }
58 
generateHeightToken(PowerStatsProfile * profile) const59 std::string PowerStatsProfileTokenGenerator::generateHeightToken(PowerStatsProfile* profile) const {
60     if (profile->isOff()) {
61         return "";
62     }
63     return std::to_string(profile->mHeight);
64 }
65 
generateFpsToken(PowerStatsProfile * profile) const66 std::string PowerStatsProfileTokenGenerator::generateFpsToken(PowerStatsProfile* profile) const {
67     if (profile->isOff()) {
68         return "";
69     }
70     if (profile->mFps == 0) {
71         return "oth";
72     }
73     return std::to_string(profile->mFps);
74 }
75 
generateToken(const std::string & tokenLabel,PowerStatsProfile * profile)76 std::optional<std::string> PowerStatsProfileTokenGenerator::generateToken(
77         const std::string& tokenLabel, PowerStatsProfile* profile) {
78     static std::unordered_map<std::string, std::function<std::string(PowerStatsProfile*)>>
79             functors = {{"refreshSource",
80                          std::bind(&PowerStatsProfileTokenGenerator::generateRefreshSourceToken,
81                                    this, std::placeholders::_1)},
82                         {"mode",
83                          std::bind(&PowerStatsProfileTokenGenerator::generateModeToken, this,
84                                    std::placeholders::_1)},
85                         {"width",
86                          std::bind(&PowerStatsProfileTokenGenerator::generateWidthToken, this,
87                                    std::placeholders::_1)},
88                         {"height",
89                          std::bind(&PowerStatsProfileTokenGenerator::generateHeightToken, this,
90                                    std::placeholders::_1)},
91                         {"fps",
92                          std::bind(&PowerStatsProfileTokenGenerator::generateFpsToken, this,
93                                    std::placeholders::_1)}};
94 
95     if (functors.find(tokenLabel) != functors.end()) {
96         return (functors[tokenLabel])(profile);
97     } else {
98         ALOGE("%s syntax error: unable to find token label = %s", __func__, tokenLabel.c_str());
99         return std::nullopt;
100     }
101 }
102 
generateStateName(PowerStatsProfile * profile,bool enableMapping)103 std::string PowerStatsProfileTokenGenerator::generateStateName(PowerStatsProfile* profile,
104                                                                bool enableMapping) {
105     std::string stateName;
106     const std::vector<std::pair<std::string, std::string>>& residencyPattern =
107             !isPresentRefresh(profile->mRefreshSource) ? mNonPresentDisplayStateResidencyPatternList
108                                                        : mPresentDisplayStateResidencyPatternList;
109 
110     for (const auto& pattern : residencyPattern) {
111         const auto token = generateToken(pattern.first, profile);
112         if (token.has_value()) {
113             stateName += token.value();
114             if (pattern.first == "mode" && token.value() == "OFF") {
115                 break;
116             }
117         } else {
118             ALOGE("DisplayStateResidencyProvider %s(): cannot find token with label %s", __func__,
119                   pattern.first.c_str());
120             continue;
121         }
122         stateName += pattern.second;
123     }
124     if (!enableMapping && !isPresentRefresh(profile->mRefreshSource)) {
125         stateName += generateFpsToken(profile);
126     }
127     return stateName;
128 }
129 
parseResidencyPattern(std::vector<std::pair<std::string,std::string>> & residencyPatternMap,const std::string_view residencyPattern)130 bool PowerStatsProfileTokenGenerator::parseResidencyPattern(
131         std::vector<std::pair<std::string, std::string>>& residencyPatternMap,
132         const std::string_view residencyPattern) {
133     size_t start, end;
134     start = 0;
135     end = -1;
136     while (true) {
137         start = residencyPattern.find_first_of(kTokenLabelStart, end + 1);
138         if (start == std::string::npos) {
139             break;
140         }
141         ++start;
142         end = residencyPattern.find_first_of(kTokenLabelEnd, start);
143         if (end == std::string::npos) {
144             break;
145         }
146         std::string tokenLabel(residencyPattern.substr(start, end - start));
147 
148         start = residencyPattern.find_first_of(kDelimiterStart, end + 1);
149         if (start == std::string::npos) {
150             break;
151         }
152         ++start;
153         end = residencyPattern.find_first_of(kDelimiterEnd, start);
154         if (end == std::string::npos) {
155             break;
156         }
157         std::string delimiter(residencyPattern.substr(start, end - start));
158         residencyPatternMap.emplace_back(std::make_pair(tokenLabel, delimiter));
159     }
160     return (end == residencyPattern.length() - 1);
161 }
162 
parseDisplayStateResidencyPattern()163 bool PowerStatsProfileTokenGenerator::parseDisplayStateResidencyPattern() {
164     return parseResidencyPattern(mPresentDisplayStateResidencyPatternList,
165                                  kPresentDisplayStateResidencyPattern) &&
166             parseResidencyPattern(mNonPresentDisplayStateResidencyPatternList,
167                                   kNonPresentDisplayStateResidencyPattern);
168 }
169 
170 } // namespace android::hardware::graphics::composer
171