• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.tradefed.log.LogUtil.CLog;
20 
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.Collections;
24 import java.util.HashSet;
25 import java.util.Objects;
26 import java.util.regex.Matcher;
27 import java.util.regex.Pattern;
28 
29 public final class CpmsFrameworkLayerStateInfo {
30     private static final int STRING_BUILDER_BUF_SIZE = 1024;
31 
32     public static final String COMMAND = "dumpsys car_service --services"
33             + " CarPowerManagementService";
34     public static final String CURRENT_STATE_HDR = "mCurrentState:";
35     public static final String CURRENT_POLICY_ID_HDR = "mCurrentPowerPolicyId:";
36     public static final String PENDING_POLICY_ID_HDR = "mPendingPowerPolicyId:";
37     public static final String CURRENT_POLICY_GROUP_ID_HDR = "mCurrentPowerPolicyGroupId:";
38     public static final String NUMBER_POLICY_LISTENERS_HDR = "# of power policy change listener:";
39     public static final String POWER_POLICY_GROUPS_HDR = "Power policy groups:";
40     public static final String PREEMPTIVE_POWER_POLICY_HDR = "Preemptive power policy:";
41     public static final String COMPONENT_STATE_HDR = "Power components state:";
42     public static final String COMPONENT_CONTROLLED_HDR =
43             "Components powered off by power policy:";
44     public static final String COMPONENT_CHANGED_HDR = "Components changed by the last policy:";
45     public static final String MONITORING_HW_HDR = "Monitoring HW state signal:";
46     public static final String SILENT_MODE_BY_HW_HDR = "Silent mode by HW state signal:";
47     public static final String FORCED_SILENT_MODE_HDR = "Forced silent mode:";
48 
49     private static final String[] COMPONENT_LIST = {"AUDIO", "MEDIA", "DISPLAY", "BLUETOOTH",
50             "WIFI", "CELLULAR", "ETHERNET", "PROJECTION", "NFC", "INPUT", "VOICE_INTERACTION",
51             "VISUAL_INTERACTION", "TRUSTED_DEVICE_DETECTION", "LOCATION", "MICROPHONE", "CPU"};
52     private static final HashSet COMPONENT_SET = new HashSet(Arrays.asList(COMPONENT_LIST));
53 
54     private final ArrayList<String> mEnables;
55     private final ArrayList<String> mDisables;
56     private final ArrayList<String> mControlledEnables;
57     private final ArrayList<String> mControlledDisables;
58     private final String[] mChangedComponents;
59     private final PowerPolicyGroups mPowerPolicyGroups;
60     private final String mCurrentPolicyId;
61     private final String mPendingPolicyId;
62     private final String mCurrentPolicyGroupId;
63     private final int mNumberPolicyListeners;
64     private final boolean mMonitoringHw;
65     private final boolean mSilentModeByHw;
66     private final boolean mForcedSilentMode;
67     private final int mCurrentState;
68 
CpmsFrameworkLayerStateInfo(String currentPolicyId, String pendingPolicyId, String currentPolicyGroupId, int numberPolicyListeners, String[] changedComponents, ArrayList<String> enables, ArrayList<String> disables, PowerPolicyGroups policyGroups, ArrayList<String> controlledEnables, ArrayList<String> controlledDisables, boolean monitoringHw, boolean silentModeByHw, boolean forcedSilentMode, int currentState)69     private CpmsFrameworkLayerStateInfo(String currentPolicyId, String pendingPolicyId,
70             String currentPolicyGroupId, int numberPolicyListeners, String[] changedComponents,
71             ArrayList<String> enables, ArrayList<String> disables, PowerPolicyGroups policyGroups,
72             ArrayList<String> controlledEnables, ArrayList<String> controlledDisables,
73             boolean monitoringHw, boolean silentModeByHw, boolean forcedSilentMode,
74             int currentState) {
75         mEnables = enables;
76         mDisables = disables;
77         mControlledEnables = controlledEnables;
78         mControlledDisables = controlledDisables;
79         mChangedComponents = changedComponents;
80         mPowerPolicyGroups = policyGroups;
81         mCurrentPolicyId = currentPolicyId;
82         mPendingPolicyId = pendingPolicyId;
83         mCurrentPolicyGroupId = currentPolicyGroupId;
84         mNumberPolicyListeners = numberPolicyListeners;
85         mMonitoringHw = monitoringHw;
86         mSilentModeByHw = silentModeByHw;
87         mForcedSilentMode = forcedSilentMode;
88         mCurrentState = currentState;
89     }
90 
getCurrentPolicyId()91     public String getCurrentPolicyId() {
92         return mCurrentPolicyId;
93     }
94 
getPendingPolicyId()95     public String getPendingPolicyId() {
96         return mPendingPolicyId;
97     }
98 
getCurrentState()99     public int getCurrentState() {
100         return mCurrentState;
101     }
102 
getForcedSilentMode()103     public boolean getForcedSilentMode() {
104         return mForcedSilentMode;
105     }
106 
getCurrentEnabledComponents()107     public PowerPolicyDef.PowerComponent[] getCurrentEnabledComponents() {
108         return PowerPolicyDef.PowerComponent.asComponentArray(mEnables);
109     }
110 
getCurrentDisabledComponents()111     public PowerPolicyDef.PowerComponent[] getCurrentDisabledComponents() {
112         return PowerPolicyDef.PowerComponent.asComponentArray(mDisables);
113     }
114 
getCurrentPolicyGroupId()115     public String getCurrentPolicyGroupId() {
116         return mCurrentPolicyGroupId;
117     }
118 
getPowerPolicyGroups()119     public PowerPolicyGroups getPowerPolicyGroups() {
120         return mPowerPolicyGroups;
121     }
122 
getNumberPolicyListeners()123     public int getNumberPolicyListeners() {
124         return mNumberPolicyListeners;
125     }
126 
isComponentOn(String component)127     public boolean isComponentOn(String component) {
128         return mEnables.contains(component);
129     }
130 
isComponentOff(String component)131     public boolean isComponentOff(String component) {
132         return mDisables.contains(component);
133     }
134 
135     @Override
toString()136     public String toString() {
137         StringBuilder sb = new StringBuilder(STRING_BUILDER_BUF_SIZE);
138         sb.append("mCurrentState=").append(mCurrentState).append(' ');
139         sb.append("mCurrentPolicyId=").append(mCurrentPolicyId).append(' ');
140         sb.append("mPendingPolicyId=").append(mPendingPolicyId).append(' ');
141         sb.append("mCurrentPolicyGroupId=").append(mCurrentPolicyGroupId).append(' ');
142         sb.append("mNumberPolicyListeners=").append(mNumberPolicyListeners).append(' ');
143         sb.append("silentmode=").append(mMonitoringHw).append(',');
144         sb.append(mSilentModeByHw).append(',').append(mForcedSilentMode).append(' ');
145         sb.append("enables=").append(String.join(",", mEnables)).append(' ');
146         sb.append("disables=").append(String.join(",", mDisables));
147         sb.append("controlledEnables=").append(String.join(",", mControlledEnables)).append(' ');
148         sb.append("controlledDisables=").append(String.join(",", mControlledDisables));
149         sb.append("changedComponents=").append(String.join(",", mChangedComponents));
150         return sb.toString();
151     }
152 
153     @Override
equals(Object o)154     public boolean equals(Object o) {
155         if (this == o) return true;
156         if (o == null || getClass() != o.getClass()) return false;
157         CpmsFrameworkLayerStateInfo that = (CpmsFrameworkLayerStateInfo) o;
158         return mCurrentState == that.mCurrentState
159                 && mMonitoringHw == that.mMonitoringHw
160                 && mSilentModeByHw == that.mSilentModeByHw
161                 && mForcedSilentMode == that.mForcedSilentMode
162                 && mNumberPolicyListeners == that.mNumberPolicyListeners
163                 && mEnables.equals(that.mEnables)
164                 && mDisables.equals(that.mDisables)
165                 && mPowerPolicyGroups.equals(that.mPowerPolicyGroups)
166                 && mControlledEnables.equals(that.mControlledEnables)
167                 && mControlledDisables.equals(that.mControlledDisables)
168                 && Arrays.equals(mChangedComponents, that.mChangedComponents)
169                 && Objects.equals(mCurrentPolicyId, that.mCurrentPolicyId)
170                 && Objects.equals(mPendingPolicyId, that.mPendingPolicyId)
171                 && Objects.equals(mCurrentPolicyGroupId, that.mCurrentPolicyGroupId);
172     }
173 
174     @Override
hashCode()175     public int hashCode() {
176         return Objects.hash(mEnables, mDisables, mControlledEnables, mControlledDisables,
177                 mChangedComponents, mPowerPolicyGroups, mCurrentPolicyId, mPendingPolicyId,
178                 mCurrentPolicyGroupId, mCurrentState, mMonitoringHw, mSilentModeByHw,
179                 mForcedSilentMode, mNumberPolicyListeners);
180     }
181 
parse(String cmdOutput)182     public static CpmsFrameworkLayerStateInfo parse(String cmdOutput) throws Exception {
183         int currentState = -1;
184         String currentPolicyId = null;
185         String pendingPolicyId = null;
186         String currentPolicyGroupId = null;
187         ArrayList<String> enables = null;
188         ArrayList<String> disables = null;
189         ArrayList<String> controlledEnables = null;
190         ArrayList<String> controlledDisables = null;
191         String[] changedComponents = null;
192         PowerPolicyGroups policyGroups = null;
193         boolean monitoringHw = false;
194         boolean silentModeByHw = false;
195         boolean forcedSilentMode = false;
196         int numberPolicyListeners = 0;
197 
198         String[] lines = cmdOutput.split("\n");
199         StateInfoParser parser = new StateInfoParser(lines);
200         HashSet<String> headerCounter = new HashSet<String>();
201         String header;
202         while ((header = parser.searchHeader()) != null) {
203             switch (header) {
204                 case CURRENT_STATE_HDR:
205                     currentState = parser.getIntData(CURRENT_STATE_HDR);
206                     break;
207                 case CURRENT_POLICY_ID_HDR:
208                     currentPolicyId = parser.getStringData(CURRENT_POLICY_ID_HDR);
209                     break;
210                 case PENDING_POLICY_ID_HDR:
211                     pendingPolicyId = parser.getStringData(PENDING_POLICY_ID_HDR);
212                     break;
213                 case CURRENT_POLICY_GROUP_ID_HDR:
214                     currentPolicyGroupId = parser.getStringData(CURRENT_POLICY_GROUP_ID_HDR);
215                     break;
216                 case POWER_POLICY_GROUPS_HDR:
217                     ArrayList<String> groupList = parser.getStringArray(POWER_POLICY_GROUPS_HDR,
218                             PREEMPTIVE_POWER_POLICY_HDR);
219                     policyGroups = PowerPolicyGroups.parse(groupList);
220                     break;
221                 case COMPONENT_STATE_HDR:
222                     parser.parseComponentStates(COMPONENT_STATE_HDR,
223                             COMPONENT_CONTROLLED_HDR, true);
224                     enables = parser.getEnables();
225                     disables = parser.getDisables();
226                     Collections.sort(enables);
227                     Collections.sort(disables);
228                     break;
229                 case COMPONENT_CONTROLLED_HDR:
230                     parser.parseComponentStates(COMPONENT_CONTROLLED_HDR,
231                             COMPONENT_CHANGED_HDR, false);
232                     controlledEnables = parser.getEnables();
233                     controlledDisables = parser.getDisables();
234                     Collections.sort(controlledEnables);
235                     Collections.sort(controlledDisables);
236                     break;
237                 case COMPONENT_CHANGED_HDR:
238                     changedComponents = parser.getChangedComponents(COMPONENT_CHANGED_HDR,
239                             MONITORING_HW_HDR);
240                     break;
241                 case MONITORING_HW_HDR:
242                     monitoringHw = parser.getBooleanData(MONITORING_HW_HDR);
243                     break;
244                 case SILENT_MODE_BY_HW_HDR:
245                     silentModeByHw = parser.getBooleanData(SILENT_MODE_BY_HW_HDR);
246                     break;
247                 case FORCED_SILENT_MODE_HDR:
248                     forcedSilentMode = parser.getBooleanData(FORCED_SILENT_MODE_HDR);
249                     break;
250                 case NUMBER_POLICY_LISTENERS_HDR:
251                     numberPolicyListeners = parser.getIntData(NUMBER_POLICY_LISTENERS_HDR);
252                     break;
253                 default:
254                     throw new IllegalArgumentException("parser header mismatch: " + header);
255             }
256             headerCounter.add(header);
257         }
258 
259         if (headerCounter.size() != StateInfoParser.HEADERS.length) {
260             String errMsg = "miss headers. got: " + headerCounter + " expected: "
261                     + String.join(",", StateInfoParser.HEADERS);
262             throw new IllegalArgumentException(errMsg);
263         }
264 
265         return new CpmsFrameworkLayerStateInfo(currentPolicyId, pendingPolicyId,
266                 currentPolicyGroupId, numberPolicyListeners, changedComponents, enables,
267                 disables, policyGroups, controlledEnables, controlledDisables, monitoringHw,
268                 silentModeByHw, forcedSilentMode, currentState);
269     }
270 
271     private static final class StateInfoParser {
272         private static final String[] HEADERS = {
273             CURRENT_STATE_HDR,
274             CURRENT_POLICY_ID_HDR,
275             PENDING_POLICY_ID_HDR,
276             CURRENT_POLICY_GROUP_ID_HDR,
277             NUMBER_POLICY_LISTENERS_HDR,
278             COMPONENT_STATE_HDR,
279             COMPONENT_CONTROLLED_HDR,
280             POWER_POLICY_GROUPS_HDR,
281             COMPONENT_CHANGED_HDR,
282             MONITORING_HW_HDR,
283             SILENT_MODE_BY_HW_HDR,
284             FORCED_SILENT_MODE_HDR
285         };
286         private final String[] mLines;
287         private ArrayList<String> mEnables;
288         private ArrayList<String> mDisables;
289         private int mIdx = 0;
290 
StateInfoParser(String[] lines)291         private StateInfoParser(String[] lines) {
292             mLines = lines;
293         }
294 
getEnables()295         private ArrayList<String> getEnables() {
296             return mEnables;
297         }
298 
getDisables()299         private ArrayList<String> getDisables() {
300             return mDisables;
301         }
302 
getIntData(String header)303         private int getIntData(String header) throws Exception {
304             int val = 0;
305             switch (header) {
306                 case CURRENT_STATE_HDR:
307                     Pattern pattern = Pattern.compile("mCurrentState: CpmsState "
308                             + "[^\\n]*carPowerStateListenerState=(\\d+)");
309                     Matcher matcher = pattern.matcher(mLines[mIdx]);
310                     if (!matcher.find()) {
311                         throw new IllegalArgumentException("malformatted mCurrentState: "
312                                 + mLines[mIdx]);
313                     }
314                     val = Integer.parseInt(matcher.group(1));
315                     break;
316                 case NUMBER_POLICY_LISTENERS_HDR:
317                     int strLen = mLines[mIdx].length();
318                     val = Integer.parseInt(mLines[mIdx].substring(strLen - 1).trim());
319                     break;
320                 default:
321                     break;
322             }
323             return val;
324         }
325 
getStringData(String header)326         private String getStringData(String header) {
327             String val = null;
328             if (mLines[mIdx].trim().length() != header.length()) {
329                 val = mLines[mIdx].trim().substring(header.length()).trim();
330             }
331             return val;
332         }
333 
getStringArray(String startHdr, String endHdr)334         private ArrayList<String> getStringArray(String startHdr, String endHdr)
335                 throws Exception {
336             if (!mLines[mIdx].contains(startHdr)) {
337                 String errMsg = String.format("expected start header %s at line %d : %s",
338                         startHdr, mIdx, mLines[mIdx]);
339                 throw new IllegalArgumentException(errMsg);
340             }
341 
342             ArrayList<String> strArray = new ArrayList<String>();
343             while (++mIdx < mLines.length && !mLines[mIdx].contains(endHdr)) {
344                 strArray.add(mLines[mIdx]);
345             }
346             mIdx--;
347 
348             if (mIdx == (mLines.length - 1)) {
349                 throw new IllegalArgumentException("reaches the end while get " + startHdr);
350             }
351             return strArray;
352         }
353 
parseComponentStates(String startHdr, String endHdr, boolean hasStateInfo)354         private void parseComponentStates(String startHdr, String endHdr,
355                 boolean hasStateInfo) throws Exception {
356             mEnables = new ArrayList<String>();
357             mDisables = new ArrayList<String>();
358             while (mIdx < (mLines.length - 1) && !mLines[++mIdx].contains(endHdr)) {
359                 String stateStr = mLines[mIdx].trim();
360                 String[] vals = stateStr.split(":\\s");
361                 if (hasStateInfo && vals.length != 2) {
362                     String errMsg = String.format("wrong format at %d in: %s ", mIdx, stateStr);
363                     CLog.e(errMsg);
364                     throw new IllegalArgumentException(errMsg);
365                 }
366 
367                 for (int i = 0; i < vals.length; i++) {
368                     vals[i] = vals[i].trim();
369                 }
370 
371                 if (!COMPONENT_SET.contains(vals[0])) {
372                     String errMsg = String.format("invalid component at %d with %s in: %s",
373                             mIdx, vals[0], stateStr);
374                     CLog.e(errMsg);
375                     throw new IllegalArgumentException(errMsg);
376                 }
377 
378                 if (hasStateInfo) {
379                     if (vals[1].startsWith("on")) {
380                         mEnables.add(vals[0]);
381                     } else if (vals[1].startsWith("off")) {
382                         mDisables.add(vals[0]);
383                     } else {
384                         String errMsg =
385                                 String.format("wrong state value at %d with (%s, %s) in: %s",
386                                 mIdx, vals[0], vals[1], stateStr);
387                         CLog.e(errMsg);
388                         throw new IllegalArgumentException(errMsg);
389                     }
390                 } else {
391                     mDisables.add(vals[0]);
392                 }
393             }
394             mIdx--;
395 
396             if (mIdx == (mLines.length - 1)) {
397                 throw new IllegalArgumentException("reaches the end while parse " + startHdr);
398             }
399         }
400 
getChangedComponents(String startHdr, String endHdr)401         private String[] getChangedComponents(String startHdr, String endHdr) {
402             int idx = mLines[mIdx].indexOf(endHdr);
403             String compStr;
404             if (idx < 0) {
405                 compStr = mLines[mIdx].substring(startHdr.length());
406             } else {
407                 compStr = mLines[mIdx].substring(startHdr.length(), idx);
408                 mLines[mIdx] = mLines[mIdx].substring(idx);
409                 mIdx--;
410             }
411             return compStr.split(",\\s*");
412         }
413 
getBooleanData(String header)414         private boolean getBooleanData(String header) {
415             return Boolean.parseBoolean(mLines[mIdx].trim().substring(header.length()).trim());
416         }
417 
searchHeader()418         private String searchHeader() {
419             String header = null;
420             for (mIdx++; mIdx < mLines.length; mIdx++) {
421                 if (mLines[mIdx].trim().isEmpty()) {
422                     continue;
423                 }
424 
425                 int firstHdrPos = mLines[mIdx].length() + 1;
426                 for (int i = 0; i < HEADERS.length; i++) {
427                     int tempHdrPos = mLines[mIdx].indexOf(HEADERS[i]);
428                     if (tempHdrPos >= 0 && (firstHdrPos > tempHdrPos)) {
429                         firstHdrPos = tempHdrPos;
430                         header = HEADERS[i];
431                     }
432                 }
433                 if (header != null) {
434                     break;
435                 }
436             }
437 
438             return header;
439         }
440     }
441 }
442