1 /*
2  * Copyright (C) 2021 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 package android.car.cts.powerpolicy;
18 
19 import com.android.car.power.CarPowerDumpProto.PolicyReaderProto;
20 import com.android.car.power.CarPowerDumpProto.PolicyReaderProto.IdToPolicyGroup;
21 import com.android.car.power.CarPowerDumpProto.PolicyReaderProto.IdToPolicyGroup.PolicyGroup;
22 import com.android.car.power.CarPowerDumpProto.PolicyReaderProto.IdToPolicyGroup.PolicyGroup.StateToDefaultPolicy;
23 import com.android.tradefed.log.LogUtil;
24 
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Objects;
28 import java.util.Set;
29 
30 public final class PowerPolicyGroups {
31     private final HashMap<String, PowerPolicyGroupDef> mPolicyGroups = new HashMap<>();
32 
PowerPolicyGroups()33     public PowerPolicyGroups() { }
34 
PowerPolicyGroups(PowerPolicyGroupDef[] defs)35     public PowerPolicyGroups(PowerPolicyGroupDef[] defs) {
36         for (int i = 0; i < defs.length; i++) {
37             mPolicyGroups.put(defs[i].mGroupId, defs[i]);
38         }
39     }
40 
41     /**
42      * Add a policy group
43      * @param id policy group ID
44      * @param waitForVHALPolicy ID of default policy for wait for VHAL power state
45      * @param onPolicy ID of default policy for on power state
46      * @throws IllegalArgumentException if a policy group with {@code id} already exists
47      */
add(String id, String waitForVHALPolicy, String onPolicy)48     public void add(String id, String waitForVHALPolicy, String onPolicy)
49             throws IllegalArgumentException {
50         if (mPolicyGroups.containsKey(id)) {
51             throw new IllegalArgumentException(id + " policy group already exists");
52         }
53         PowerPolicyGroupDef groupDef = new PowerPolicyGroupDef(id, waitForVHALPolicy, onPolicy);
54         mPolicyGroups.put(id, groupDef);
55     }
56 
57     @Override
toString()58     public String toString() {
59         StringBuilder str = new StringBuilder();
60         str.append("Power policy groups:\n");
61         mPolicyGroups.forEach((k, v) -> str.append(v.toString()));
62         return str.toString();
63     }
64 
65     @Override
hashCode()66     public int hashCode() {
67         return mPolicyGroups.hashCode();
68     }
69 
70     @Override
equals(Object o)71     public boolean equals(Object o) {
72         if (this == o) return true;
73         if (o == null || getClass() != o.getClass()) return false;
74         PowerPolicyGroups peer = (PowerPolicyGroups) o;
75         return mPolicyGroups.equals(peer.mPolicyGroups);
76     }
77 
78     /**
79      * Parse an array of strings representing power policy groups in order to define them
80      * @param defStrs strings representing power policy group definitions
81      * @return the {@code PowerPolicyGroups} object with the new power policy group definitions
82      */
parse(List<String> defStrs)83     public static PowerPolicyGroups parse(List<String> defStrs) {
84         PowerPolicyGroups policyGroups = new PowerPolicyGroups();
85         String groupId = null;
86         String waitForVHALPolicy = null;
87         String onPolicy = null;
88 
89         String groupDefDelimiter = "-->";
90         for (int i = 0; i < defStrs.size(); ++i) {
91             String line = defStrs.get(i);
92             if (line.contains(groupDefDelimiter)) {
93                 // this is policy group definition
94                 if (line.contains("WaitForVHAL")) {
95                     waitForVHALPolicy = parsePolicyGroupDef("WaitForVHAL", line);
96                 } else if (line.contains("On")) {
97                     onPolicy = parsePolicyGroupDef("On", line);
98                 } else {
99                     LogUtil.CLog.d("Policy group is ignored: " + line);
100                 }
101             } else {
102                 // Found name, if name is not empty, another group was already found
103                 // add previous group to the policyGroups before proceeding with current one
104                 if (groupId != null) {
105                     policyGroups.add(groupId, waitForVHALPolicy, onPolicy);
106                     waitForVHALPolicy = null;
107                     onPolicy = null;
108                 }
109                 groupId = line.trim();
110             }
111         }
112         // If group wasn't saved (indicated by non-null values of policies), save it
113         if (groupId != null && (waitForVHALPolicy != null || onPolicy != null)) {
114             policyGroups.add(groupId, waitForVHALPolicy, onPolicy);
115         }
116         return policyGroups;
117     }
118 
parseProto(PolicyReaderProto policyReaderProto)119     static PowerPolicyGroups parseProto(PolicyReaderProto policyReaderProto)
120             throws Exception {
121         PowerPolicyGroups policyGroups = new PowerPolicyGroups();
122         int numPolicyGroups = policyReaderProto.getPowerPolicyGroupMappingsCount();
123         for (int i = 0; i < numPolicyGroups; i++) {
124             IdToPolicyGroup policyGroupMapping = policyReaderProto.getPowerPolicyGroupMappings(i);
125             String policyGroupId = policyGroupMapping.getPolicyGroupId();
126             PolicyGroup policyGroup = policyGroupMapping.getPolicyGroup();
127             int numPolicies = policyGroup.getDefaultPolicyMappingsCount();
128             String waitForVhalPolicy = null;
129             String onPolicy = null;
130             for (int j = 0; j < numPolicies; j++) {
131                 StateToDefaultPolicy policyMapping = policyGroup.getDefaultPolicyMappings(j);
132                 String state = policyMapping.getState();
133                 String policyId = policyMapping.getDefaultPolicyId();
134                 if (state.equals("WaitForVHAL") && waitForVhalPolicy == null) {
135                     waitForVhalPolicy = policyId;
136                 } else if (state.equals("On") && onPolicy == null) {
137                     onPolicy = policyId;
138                 } else {
139                     String errMsg = "Incorrect power policy groups format\nPolicy reader proto:\n"
140                             + "state: " + state + "\npolicyId: " + policyId
141                             + "\nwaitForVHAL policy: " + waitForVhalPolicy + "\non policy: "
142                             + onPolicy;
143                     LogUtil.CLog.e(errMsg);
144                     throw new IllegalArgumentException(errMsg);
145                 }
146             }
147             policyGroups.add(policyGroupId, waitForVhalPolicy, onPolicy);
148         }
149         return policyGroups;
150     }
151 
parsePolicyGroupDef(String stateName, String defStr)152     private static String parsePolicyGroupDef(String stateName, String defStr) {
153         String[] tokens = defStr.trim().split("(\\s*)(-{1,2})(>?)(\\s*)");
154         if (tokens.length != 3) {
155             throw new IllegalArgumentException("malformatted policy group def str: " + defStr);
156         }
157 
158         if (!stateName.equals(tokens[1].trim())) {
159             String errMsg = String.format("expected power state: %s but got: %s",
160                     stateName, tokens[1]);
161             throw new IllegalArgumentException(errMsg);
162         }
163 
164         return tokens[2].trim();
165     }
166 
getGroupIds()167     public Set<String> getGroupIds() {
168         return mPolicyGroups.keySet();
169     }
170 
getGroup(String groupId)171     public PowerPolicyGroupDef getGroup(String groupId) {
172         return mPolicyGroups.get(groupId);
173     }
174 
containsGroup(String groupId, PowerPolicyGroupDef expectedGroupDef)175     public boolean containsGroup(String groupId, PowerPolicyGroupDef expectedGroupDef) {
176         PowerPolicyGroupDef policyGroup = mPolicyGroups.get(groupId);
177         if (policyGroup == null) {
178             return false;
179         }
180 
181         return policyGroup.equals(expectedGroupDef);
182     }
183 
184     public static final class PowerPolicyGroupDef {
185         private final String mGroupId;
186         private final String mWaitForVHALStatePolicy;
187         private final String mOnStatePolicy;
188 
PowerPolicyGroupDef(String groupId, String waitForVHALPolicy, String onPolicy)189         private PowerPolicyGroupDef(String groupId, String waitForVHALPolicy, String onPolicy) {
190             mGroupId = groupId;
191             mWaitForVHALStatePolicy = waitForVHALPolicy;
192             mOnStatePolicy = onPolicy;
193         }
194 
getGroupId()195         public String getGroupId() {
196             return mGroupId;
197         }
198 
getWaitForVHALStatePolicy()199         public String getWaitForVHALStatePolicy() {
200             return mWaitForVHALStatePolicy;
201         }
202 
getOnStatePolicy()203         public String getOnStatePolicy() {
204             return mOnStatePolicy;
205         }
206 
toShellCommandString()207         public String toShellCommandString() {
208             return String.format("%s WaitForVHAL:%s On:%s", mGroupId,
209                     mWaitForVHALStatePolicy, mOnStatePolicy);
210         }
211 
212         @Override
toString()213         public String toString() {
214             StringBuilder str = new StringBuilder();
215             str.append("  ").append(mGroupId).append('\n');
216             str.append("    - WaitForVHAL --> ").append(mWaitForVHALStatePolicy).append('\n');
217             str.append("    - On --> ").append(mOnStatePolicy).append('\n');
218             return str.toString();
219         }
220 
221         @Override
equals(Object o)222         public boolean equals(Object o) {
223             if (this == o) return true;
224             if (o == null || getClass() != o.getClass()) return false;
225             PowerPolicyGroupDef that = (PowerPolicyGroupDef) o;
226             return Objects.equals(mGroupId, that.mGroupId)
227                     && Objects.equals(mWaitForVHALStatePolicy, that.mWaitForVHALStatePolicy)
228                     && Objects.equals(mOnStatePolicy, that.mOnStatePolicy);
229         }
230 
231         @Override
hashCode()232         public int hashCode() {
233             return Objects.hash(mGroupId, mWaitForVHALStatePolicy, mOnStatePolicy);
234         }
235     }
236 
237     public static final class TestSet {
238         public static final String GROUP_ID1 = "policy_group1";
239         public static final String GROUP_ID2 = "policy_group2";
240 
241         public static final PowerPolicyGroupDef POLICY_GROUP_DEF1 =
242                 new PowerPolicyGroupDef(GROUP_ID1, PowerPolicyDef.IdSet.TEST1,
243                     PowerPolicyDef.IdSet.TEST2);
244 
245         public static final PowerPolicyGroupDef POLICY_GROUP_DEF2 =
246                 new PowerPolicyGroupDef(GROUP_ID2, PowerPolicyDef.IdSet.TEST2,
247                     PowerPolicyDef.IdSet.TEST1);
248 
249         public static final PowerPolicyGroups POLICY_GROUPS1 = new PowerPolicyGroups(
250                 new PowerPolicyGroupDef[]{POLICY_GROUP_DEF1, POLICY_GROUP_DEF2});
251 
TestSet()252         private TestSet() { }
253     }
254 }
255