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 #pragma once
18 
19 #include <optional>
20 #include <string>
21 
22 #include "../display/common/CommonDisplayContextProvider.h"
23 #include "PowerStatsProfile.h"
24 
25 namespace android::hardware::graphics::composer {
26 
27 struct StateNameComparator {
operatorStateNameComparator28     bool operator()(const std::string& a, const std::string& b) const {
29         // 1. Find the last '@' in both strings
30         size_t posA = a.rfind('@');
31         size_t posB = b.rfind('@');
32 
33         // 2. Extract the parts before and after the '@'
34         std::string prefixA = (posA != std::string::npos) ? a.substr(0, posA) : a;
35         std::string suffixA = (posA != std::string::npos) ? a.substr(posA + 1) : "";
36         std::string prefixB = (posB != std::string::npos) ? b.substr(0, posB) : b;
37         std::string suffixB = (posB != std::string::npos) ? b.substr(posB + 1) : "";
38 
39         // 3. Compare prefixes first
40         if (prefixA != prefixB) {
41             return prefixA < prefixB;
42         }
43 
44         // 4. If prefixes are the same, check for "np" and extract numeric parts
45         bool hasNpA = suffixA.find("np") == 0;
46         bool hasNpB = suffixB.find("np") == 0;
47         std::string numPartA = hasNpA ? suffixA.substr(2) : suffixA;
48         std::string numPartB = hasNpB ? suffixB.substr(2) : suffixB;
49 
50         // 5. Compare based on "np" presence
51         if (hasNpA != hasNpB) {
52             return !hasNpA; // "np" prefixes come after non-"np" prefixes
53         }
54 
55         // 6. If both have "np" or neither has it, compare numeric parts
56         bool isNumA = std::all_of(numPartA.begin(), numPartA.end(), ::isdigit);
57         bool isNumB = std::all_of(numPartB.begin(), numPartB.end(), ::isdigit);
58 
59         if (isNumA && isNumB) {
60             char* endPtrA;
61             char* endPtrB;
62 
63             long numA = strtol(numPartA.c_str(), &endPtrA, 10);
64             long numB = strtol(numPartB.c_str(), &endPtrB, 10);
65 
66             if (*endPtrA != '\0' || *endPtrB != '\0' || numA < std::numeric_limits<int>::min() ||
67                 numA > std::numeric_limits<int>::max() || numB < std::numeric_limits<int>::min() ||
68                 numB > std::numeric_limits<int>::max()) {
69                 ALOGE("Error parsing numeric parts in KeyComparator");
70 
71                 return false;
72             }
73 
74             return numA < numB;
75         } else {
76             return suffixA < suffixB;
77         }
78     }
79 };
80 
81 class PowerStatsProfileTokenGenerator {
82 public:
83     PowerStatsProfileTokenGenerator();
84 
85     std::optional<std::string> generateToken(const std::string& tokenLabel,
86                                              PowerStatsProfile* profile);
87 
88     std::string generateStateName(PowerStatsProfile* profile, bool enableMapping = true);
89 
90 private:
91     // The format of pattern is: ([token label]'delimiter'?)*
92     static constexpr std::string_view kPresentDisplayStateResidencyPattern =
93             "[mode](:)[width](x)[height](@)[fps]()";
94 
95     // The format of pattern is: ([token label]'delimiter'?)*
96     static constexpr std::string_view kNonPresentDisplayStateResidencyPattern =
97             "[mode](:)[width](x)[height](@)[refreshSource]()";
98 
99     static constexpr char kTokenLabelStart = '[';
100     static constexpr char kTokenLabelEnd = ']';
101     static constexpr char kDelimiterStart = '(';
102     static constexpr char kDelimiterEnd = ')';
103 
104     bool parseDisplayStateResidencyPattern();
105 
106     bool parseResidencyPattern(
107             std::vector<std::pair<std::string, std::string>>& residencyPatternMap,
108             const std::string_view residencyPattern);
109 
110     std::string generateRefreshSourceToken(PowerStatsProfile* profile) const;
111 
112     std::string generateModeToken(PowerStatsProfile* profile) const;
113 
114     std::string generateWidthToken(PowerStatsProfile* profile) const;
115 
116     std::string generateHeightToken(PowerStatsProfile* profile) const;
117 
118     std::string generateFpsToken(PowerStatsProfile* profile) const;
119 
120     std::vector<std::pair<std::string, std::string>> mNonPresentDisplayStateResidencyPatternList;
121     std::vector<std::pair<std::string, std::string>> mPresentDisplayStateResidencyPatternList;
122 };
123 
124 } // namespace android::hardware::graphics::composer
125