1 /*
2  * Copyright (C) 2020 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 com.android.server.policy;
18 
19 import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE;
20 import static android.hardware.devicestate.DeviceStateManager.MINIMUM_DEVICE_STATE;
21 
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.content.BroadcastReceiver;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.content.IntentFilter;
28 import android.hardware.Sensor;
29 import android.hardware.SensorEvent;
30 import android.hardware.SensorEventListener;
31 import android.hardware.SensorManager;
32 import android.os.Environment;
33 import android.os.PowerManager;
34 import android.util.ArrayMap;
35 import android.util.ArraySet;
36 import android.util.Slog;
37 import android.util.SparseArray;
38 
39 import com.android.internal.annotations.GuardedBy;
40 import com.android.internal.annotations.VisibleForTesting;
41 import com.android.internal.util.Preconditions;
42 import com.android.server.LocalServices;
43 import com.android.server.devicestate.DeviceState;
44 import com.android.server.devicestate.DeviceStateProvider;
45 import com.android.server.input.InputManagerInternal;
46 import com.android.server.policy.devicestate.config.Conditions;
47 import com.android.server.policy.devicestate.config.DeviceStateConfig;
48 import com.android.server.policy.devicestate.config.Flags;
49 import com.android.server.policy.devicestate.config.LidSwitchCondition;
50 import com.android.server.policy.devicestate.config.NumericRange;
51 import com.android.server.policy.devicestate.config.SensorCondition;
52 import com.android.server.policy.devicestate.config.XmlParser;
53 
54 import org.xmlpull.v1.XmlPullParserException;
55 
56 import java.io.BufferedInputStream;
57 import java.io.File;
58 import java.io.FileInputStream;
59 import java.io.IOException;
60 import java.io.InputStream;
61 import java.math.BigDecimal;
62 import java.util.ArrayList;
63 import java.util.Arrays;
64 import java.util.Comparator;
65 import java.util.List;
66 import java.util.Map;
67 import java.util.function.BooleanSupplier;
68 
69 import javax.xml.datatype.DatatypeConfigurationException;
70 
71 /**
72  * Implementation of {@link DeviceStateProvider} that reads the set of supported device states
73  * from a configuration file provided at either /vendor/etc/devicestate or
74  * /data/system/devicestate/.
75  * <p>
76  * When a device state configuration file is present this provider will consider the provided
77  * {@link Conditions} block for each declared state, halting and returning when the first set of
78  * conditions for a device state match the current system state. If there are multiple states whose
79  * conditions match the current system state the matching state with the smallest integer identifier
80  * will be returned. When no declared state matches the current system state, the device state with
81  * the smallest integer identifier will be returned.
82  * <p>
83  * By default, the provider reports {@link #DEFAULT_DEVICE_STATE} when no configuration file is
84  * provided.
85  */
86 public final class DeviceStateProviderImpl implements DeviceStateProvider,
87         InputManagerInternal.LidSwitchCallback, SensorEventListener,
88         PowerManager.OnThermalStatusChangedListener {
89     private static final String TAG = "DeviceStateProviderImpl";
90     private static final boolean DEBUG = false;
91 
92     private static final BooleanSupplier TRUE_BOOLEAN_SUPPLIER = () -> true;
93     private static final BooleanSupplier FALSE_BOOLEAN_SUPPLIER = () -> false;
94 
95     @VisibleForTesting
96     static final DeviceState DEFAULT_DEVICE_STATE = new DeviceState(MINIMUM_DEVICE_STATE,
97             "DEFAULT", 0 /* flags */);
98 
99     private static final String VENDOR_CONFIG_FILE_PATH = "etc/devicestate/";
100     private static final String DATA_CONFIG_FILE_PATH = "system/devicestate/";
101     private static final String CONFIG_FILE_NAME = "device_state_configuration.xml";
102     private static final String FLAG_CANCEL_OVERRIDE_REQUESTS = "FLAG_CANCEL_OVERRIDE_REQUESTS";
103     private static final String FLAG_APP_INACCESSIBLE = "FLAG_APP_INACCESSIBLE";
104     private static final String FLAG_EMULATED_ONLY = "FLAG_EMULATED_ONLY";
105     private static final String FLAG_CANCEL_WHEN_REQUESTER_NOT_ON_TOP =
106             "FLAG_CANCEL_WHEN_REQUESTER_NOT_ON_TOP";
107     private static final String FLAG_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL =
108             "FLAG_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL";
109     private static final String FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE =
110             "FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE";
111 
112     /** Interface that allows reading the device state configuration. */
113     interface ReadableConfig {
114         @NonNull
openRead()115         InputStream openRead() throws IOException;
116     }
117 
118     /**
119      * Returns a new {@link DeviceStateProviderImpl} instance.
120      *
121      * @param context the {@link Context} that should be used to access system services.
122      */
create(@onNull Context context)123     public static DeviceStateProviderImpl create(@NonNull Context context) {
124         File configFile = getConfigurationFile();
125         if (configFile == null) {
126             return createFromConfig(context, null);
127         }
128         return createFromConfig(context, new ReadableFileConfig(configFile));
129     }
130 
131     /**
132      * Returns a new {@link DeviceStateProviderImpl} instance.
133      *
134      * @param context the {@link Context} that should be used to access system services.
135      * @param readableConfig the config the provider instance should read supported states from.
136      */
137     @VisibleForTesting
createFromConfig(@onNull Context context, @Nullable ReadableConfig readableConfig)138     static DeviceStateProviderImpl createFromConfig(@NonNull Context context,
139             @Nullable ReadableConfig readableConfig) {
140         List<DeviceState> deviceStateList = new ArrayList<>();
141         List<Conditions> conditionsList = new ArrayList<>();
142 
143         if (readableConfig != null) {
144             DeviceStateConfig config = parseConfig(readableConfig);
145             if (config != null) {
146                 for (com.android.server.policy.devicestate.config.DeviceState stateConfig :
147                         config.getDeviceState()) {
148                     final int state = stateConfig.getIdentifier().intValue();
149                     final String name = stateConfig.getName() == null ? "" : stateConfig.getName();
150 
151                     int flags = 0;
152                     final Flags configFlags = stateConfig.getFlags();
153                     if (configFlags != null) {
154                         List<String> configFlagStrings = configFlags.getFlag();
155                         for (int i = 0; i < configFlagStrings.size(); i++) {
156                             final String configFlagString = configFlagStrings.get(i);
157                             switch (configFlagString) {
158                                 case FLAG_CANCEL_OVERRIDE_REQUESTS:
159                                     flags |= DeviceState.FLAG_CANCEL_OVERRIDE_REQUESTS;
160                                     break;
161                                 case FLAG_APP_INACCESSIBLE:
162                                     flags |= DeviceState.FLAG_APP_INACCESSIBLE;
163                                     break;
164                                 case FLAG_EMULATED_ONLY:
165                                     flags |= DeviceState.FLAG_EMULATED_ONLY;
166                                     break;
167                                 case FLAG_CANCEL_WHEN_REQUESTER_NOT_ON_TOP:
168                                     flags |= DeviceState.FLAG_CANCEL_WHEN_REQUESTER_NOT_ON_TOP;
169                                     break;
170                                 case FLAG_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL:
171                                     flags |= DeviceState
172                                             .FLAG_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL;
173                                     break;
174                                 case FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE:
175                                     flags |= DeviceState.FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE;
176                                 default:
177                                     Slog.w(TAG, "Parsed unknown flag with name: "
178                                             + configFlagString);
179                                     break;
180                             }
181                         }
182                     }
183 
184                     deviceStateList.add(new DeviceState(state, name, flags));
185 
186                     final Conditions condition = stateConfig.getConditions();
187                     conditionsList.add(condition);
188                 }
189             }
190         }
191 
192         if (deviceStateList.size() == 0) {
193             deviceStateList.add(DEFAULT_DEVICE_STATE);
194             conditionsList.add(null);
195         }
196         return new DeviceStateProviderImpl(context, deviceStateList, conditionsList);
197     }
198 
199     // Lock for internal state.
200     private final Object mLock = new Object();
201     private final Context mContext;
202     // List of supported states in ascending order based on their identifier.
203     private final DeviceState[] mOrderedStates;
204     // Map of state identifier to a boolean supplier that returns true when all required conditions
205     // are met for the device to be in the state.
206     private final SparseArray<BooleanSupplier> mStateConditions = new SparseArray<>();
207 
208     @Nullable
209     @GuardedBy("mLock")
210     private Listener mListener = null;
211     @GuardedBy("mLock")
212     private int mLastReportedState = INVALID_DEVICE_STATE;
213 
214     @GuardedBy("mLock")
215     private Boolean mIsLidOpen;
216     @GuardedBy("mLock")
217     private final Map<Sensor, SensorEvent> mLatestSensorEvent = new ArrayMap<>();
218     @GuardedBy("mLock")
219     private @PowerManager.ThermalStatus int mThermalStatus = PowerManager.THERMAL_STATUS_NONE;
220 
221     @GuardedBy("mLock")
222     private boolean mPowerSaveModeEnabled;
223 
DeviceStateProviderImpl(@onNull Context context, @NonNull List<DeviceState> deviceStates, @NonNull List<Conditions> stateConditions)224     private DeviceStateProviderImpl(@NonNull Context context,
225             @NonNull List<DeviceState> deviceStates,
226             @NonNull List<Conditions> stateConditions) {
227         Preconditions.checkArgument(deviceStates.size() == stateConditions.size(),
228                 "Number of device states must be equal to the number of device state conditions.");
229 
230         mContext = context;
231 
232         DeviceState[] orderedStates = deviceStates.toArray(new DeviceState[deviceStates.size()]);
233         Arrays.sort(orderedStates, Comparator.comparingInt(DeviceState::getIdentifier));
234         mOrderedStates = orderedStates;
235 
236         setStateConditions(deviceStates, stateConditions);
237 
238         PowerManager powerManager = context.getSystemService(PowerManager.class);
239         if (powerManager != null) {
240             // If any of the device states are thermal sensitive, i.e. it should be disabled when
241             // the device is overheating, then we will update the list of supported states when
242             // thermal status changes.
243             if (hasThermalSensitiveState(deviceStates)) {
244                 powerManager.addThermalStatusListener(this);
245             }
246 
247             // If any of the device states are power sensitive, i.e. it should be disabled when
248             // power save mode is enabled, then we will update the list of supported states when
249             // power save mode is toggled.
250             if (hasPowerSaveSensitiveState(deviceStates)) {
251                 IntentFilter filter = new IntentFilter(
252                         PowerManager.ACTION_POWER_SAVE_MODE_CHANGED_INTERNAL);
253                 BroadcastReceiver receiver = new BroadcastReceiver() {
254                     @Override
255                     public void onReceive(Context context, Intent intent) {
256                         if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED_INTERNAL.equals(
257                                 intent.getAction())) {
258                             onPowerSaveModeChanged(powerManager.isPowerSaveMode());
259                         }
260                     }
261                 };
262                 mContext.registerReceiver(receiver, filter);
263             }
264         }
265     }
266 
setStateConditions(@onNull List<DeviceState> deviceStates, @NonNull List<Conditions> stateConditions)267     private void setStateConditions(@NonNull List<DeviceState> deviceStates,
268             @NonNull List<Conditions> stateConditions) {
269         // Whether or not this instance should register to receive lid switch notifications from
270         // InputManagerInternal. If there are no device state conditions that are based on the lid
271         // switch there is no need to register for a callback.
272         boolean shouldListenToLidSwitch = false;
273 
274         // The set of Sensor(s) that this instance should register to receive SensorEvent(s) from.
275         final ArraySet<Sensor> sensorsToListenTo = new ArraySet<>();
276 
277         for (int i = 0; i < stateConditions.size(); i++) {
278             final int state = deviceStates.get(i).getIdentifier();
279             if (DEBUG) {
280                 Slog.d(TAG, "Evaluating conditions for device state " + state
281                         + " (" + deviceStates.get(i).getName() + ")");
282             }
283             final Conditions conditions = stateConditions.get(i);
284             if (conditions == null) {
285                 // If this state has the FLAG_EMULATED_ONLY flag on it, it should never be triggered
286                 // by a physical hardware change, and should always return false for it's conditions
287                 if (deviceStates.get(i).hasFlag(DeviceState.FLAG_EMULATED_ONLY)) {
288                     mStateConditions.put(state, FALSE_BOOLEAN_SUPPLIER);
289                 } else {
290                     mStateConditions.put(state, TRUE_BOOLEAN_SUPPLIER);
291                 }
292                 continue;
293             }
294 
295             // Whether or not all the required hardware components could be found that match the
296             // requirements from the config.
297             boolean allRequiredComponentsFound = true;
298             // Whether or not this condition requires the lid switch.
299             boolean lidSwitchRequired = false;
300             // Set of sensors required for this condition.
301             ArraySet<Sensor> sensorsRequired = new ArraySet<>();
302 
303             List<BooleanSupplier> suppliers = new ArrayList<>();
304 
305             LidSwitchCondition lidSwitchCondition = conditions.getLidSwitch();
306             if (lidSwitchCondition != null) {
307                 suppliers.add(new LidSwitchBooleanSupplier(lidSwitchCondition.getOpen()));
308                 lidSwitchRequired = true;
309                 if (DEBUG) {
310                     Slog.d(TAG, "Lid switch required");
311                 }
312             }
313 
314             List<SensorCondition> sensorConditions = conditions.getSensor();
315             for (int j = 0; j < sensorConditions.size(); j++) {
316                 SensorCondition sensorCondition = sensorConditions.get(j);
317                 final String expectedSensorType = sensorCondition.getType();
318                 final String expectedSensorName = sensorCondition.getName();
319 
320                 final Sensor foundSensor = findSensor(expectedSensorType, expectedSensorName);
321                 if (foundSensor == null) {
322                     Slog.e(TAG, "Failed to find Sensor with type: " + expectedSensorType
323                             + " and name: " + expectedSensorName);
324                     allRequiredComponentsFound = false;
325                     break;
326                 }
327 
328                 if (DEBUG) {
329                     Slog.d(TAG, "Found sensor with type: " + expectedSensorType
330                             + " (" + expectedSensorName + ")");
331                 }
332 
333                 suppliers.add(new SensorBooleanSupplier(foundSensor, sensorCondition.getValue()));
334                 sensorsRequired.add(foundSensor);
335             }
336 
337             if (allRequiredComponentsFound) {
338                 shouldListenToLidSwitch |= lidSwitchRequired;
339                 sensorsToListenTo.addAll(sensorsRequired);
340 
341                 if (suppliers.size() > 1) {
342                     mStateConditions.put(state, new AndBooleanSupplier(suppliers));
343                 } else if (suppliers.size() > 0) {
344                     // No need to wrap with an AND supplier if there is only 1.
345                     mStateConditions.put(state, suppliers.get(0));
346                 } else {
347                     // There are no conditions for this state. Default to always true.
348                     mStateConditions.put(state, TRUE_BOOLEAN_SUPPLIER);
349                 }
350             } else {
351                 // Failed to setup this condition. This can happen if a sensor is missing. Default
352                 // this state to always false.
353                 mStateConditions.put(state, FALSE_BOOLEAN_SUPPLIER);
354             }
355         }
356 
357         if (shouldListenToLidSwitch) {
358             InputManagerInternal inputManager = LocalServices.getService(
359                     InputManagerInternal.class);
360             inputManager.registerLidSwitchCallback(this);
361         }
362 
363         final SensorManager sensorManager = mContext.getSystemService(SensorManager.class);
364         for (int i = 0; i < sensorsToListenTo.size(); i++) {
365             Sensor sensor = sensorsToListenTo.valueAt(i);
366             sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_FASTEST);
367         }
368     }
369 
370     @Nullable
findSensor(String type, String name)371     private Sensor findSensor(String type, String name) {
372         final SensorManager sensorManager = mContext.getSystemService(SensorManager.class);
373         final List<Sensor> sensors = sensorManager.getSensorList(Sensor.TYPE_ALL);
374         for (int sensorIndex = 0; sensorIndex < sensors.size(); sensorIndex++) {
375             final Sensor sensor = sensors.get(sensorIndex);
376             final String sensorType = sensor.getStringType();
377             final String sensorName = sensor.getName();
378 
379             if (sensorType == null || sensorName == null) {
380                 continue;
381             }
382 
383             if (sensorType.equals(type) && sensorName.equals(name)) {
384                 return sensor;
385             }
386         }
387         return null;
388     }
389 
390     @Override
setListener(Listener listener)391     public void setListener(Listener listener) {
392         synchronized (mLock) {
393             if (mListener != null) {
394                 throw new RuntimeException("Provider already has a listener set.");
395             }
396             mListener = listener;
397         }
398         notifySupportedStatesChanged(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED);
399         notifyDeviceStateChangedIfNeeded();
400     }
401 
402     /** Notifies the listener that the set of supported device states has changed. */
notifySupportedStatesChanged(@upportedStatesUpdatedReason int reason)403     private void notifySupportedStatesChanged(@SupportedStatesUpdatedReason int reason) {
404         List<DeviceState> supportedStates = new ArrayList<>();
405         Listener listener;
406         synchronized (mLock) {
407             if (mListener == null) {
408                 return;
409             }
410             listener = mListener;
411             for (DeviceState deviceState : mOrderedStates) {
412                 if (isThermalStatusCriticalOrAbove(mThermalStatus)
413                         && deviceState.hasFlag(
414                                 DeviceState.FLAG_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL)) {
415                     continue;
416                 }
417                 if (mPowerSaveModeEnabled && deviceState.hasFlag(
418                         DeviceState.FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE)) {
419                     continue;
420                 }
421                 supportedStates.add(deviceState);
422             }
423         }
424 
425         listener.onSupportedDeviceStatesChanged(
426                 supportedStates.toArray(new DeviceState[supportedStates.size()]), reason);
427     }
428 
429     /** Computes the current device state and notifies the listener of a change, if needed. */
notifyDeviceStateChangedIfNeeded()430     void notifyDeviceStateChangedIfNeeded() {
431         int stateToReport = INVALID_DEVICE_STATE;
432         synchronized (mLock) {
433             if (mListener == null) {
434                 return;
435             }
436 
437             int newState = INVALID_DEVICE_STATE;
438             for (int i = 0; i < mOrderedStates.length; i++) {
439                 int state = mOrderedStates[i].getIdentifier();
440                 if (DEBUG) {
441                     Slog.d(TAG, "Checking conditions for " + mOrderedStates[i].getName() + "("
442                             + i + ")");
443                 }
444                 boolean conditionSatisfied;
445                 try {
446                     conditionSatisfied = mStateConditions.get(state).getAsBoolean();
447                 } catch (IllegalStateException e) {
448                     // Failed to compute the current state based on current available data. Continue
449                     // with the expectation that notifyDeviceStateChangedIfNeeded() will be called
450                     // when a callback with the missing data is triggered. May trigger another state
451                     // change if another state is satisfied currently.
452                     if (DEBUG) {
453                         Slog.d(TAG, "Unable to check current state", e);
454                     }
455                     continue;
456                 }
457 
458                 if (conditionSatisfied) {
459                     if (DEBUG) {
460                         Slog.d(TAG, "Device State conditions satisfied, transition to " + state);
461                     }
462                     newState = state;
463                     break;
464                 }
465             }
466             if (newState == INVALID_DEVICE_STATE) {
467                 Slog.e(TAG, "No declared device states match any of the required conditions.");
468                 dumpSensorValues();
469             }
470 
471             if (newState != INVALID_DEVICE_STATE && newState != mLastReportedState) {
472                 mLastReportedState = newState;
473                 stateToReport = newState;
474             }
475         }
476 
477         if (stateToReport != INVALID_DEVICE_STATE) {
478             mListener.onStateChanged(stateToReport);
479         }
480     }
481 
482     @Override
notifyLidSwitchChanged(long whenNanos, boolean lidOpen)483     public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) {
484         synchronized (mLock) {
485             mIsLidOpen = lidOpen;
486         }
487         if (DEBUG) {
488             Slog.d(TAG, "Lid switch state: " + (lidOpen ? "open" : "closed"));
489         }
490         notifyDeviceStateChangedIfNeeded();
491     }
492 
493     @Override
onSensorChanged(SensorEvent event)494     public void onSensorChanged(SensorEvent event) {
495         synchronized (mLock) {
496             mLatestSensorEvent.put(event.sensor, event);
497         }
498         notifyDeviceStateChangedIfNeeded();
499     }
500 
501     @Override
onAccuracyChanged(Sensor sensor, int accuracy)502     public void onAccuracyChanged(Sensor sensor, int accuracy) {
503         // Do nothing.
504     }
505 
506     /**
507      * Implementation of {@link BooleanSupplier} that returns {@code true} if the expected lid
508      * switch open state matches {@link #mIsLidOpen}.
509      */
510     private final class LidSwitchBooleanSupplier implements BooleanSupplier {
511         private final boolean mExpectedOpen;
512 
LidSwitchBooleanSupplier(boolean expectedOpen)513         LidSwitchBooleanSupplier(boolean expectedOpen) {
514             mExpectedOpen = expectedOpen;
515         }
516 
517         @Override
getAsBoolean()518         public boolean getAsBoolean() {
519             synchronized (mLock) {
520                 if (mIsLidOpen == null) {
521                     throw new IllegalStateException("Have not received lid switch value.");
522                 }
523 
524                 return mIsLidOpen == mExpectedOpen;
525             }
526         }
527     }
528 
529     /**
530      * Implementation of {@link BooleanSupplier} that returns {@code true} if the latest
531      * {@link SensorEvent#values sensor event values} for the specified {@link Sensor} adhere to
532      * the supplied {@link NumericRange ranges}.
533      */
534     private final class SensorBooleanSupplier implements BooleanSupplier {
535         @NonNull
536         private final Sensor mSensor;
537         @NonNull
538         private final List<NumericRange> mExpectedValues;
539 
SensorBooleanSupplier(@onNull Sensor sensor, @NonNull List<NumericRange> expectedValues)540         SensorBooleanSupplier(@NonNull Sensor sensor, @NonNull List<NumericRange> expectedValues) {
541             mSensor = sensor;
542             mExpectedValues = expectedValues;
543         }
544 
545         @Override
getAsBoolean()546         public boolean getAsBoolean() {
547             synchronized (mLock) {
548                 SensorEvent latestEvent = mLatestSensorEvent.get(mSensor);
549                 if (latestEvent == null) {
550                     throw new IllegalStateException("Have not received sensor event.");
551                 }
552 
553                 if (latestEvent.values.length < mExpectedValues.size()) {
554                     throw new RuntimeException("Number of supplied numeric range(s) does not "
555                             + "match the number of values in the latest sensor event for sensor: "
556                             + mSensor);
557                 }
558 
559                 for (int i = 0; i < mExpectedValues.size(); i++) {
560                     if (!adheresToRange(latestEvent.values[i], mExpectedValues.get(i))) {
561                         return false;
562                     }
563                 }
564                 return true;
565             }
566         }
567 
568         /**
569          * Returns {@code true} if the supplied {@code value} adheres to the constraints specified
570          * in {@code range}.
571          */
adheresToRange(float value, @NonNull NumericRange range)572         private boolean adheresToRange(float value, @NonNull NumericRange range) {
573             final BigDecimal min = range.getMin_optional();
574             if (min != null) {
575                 if (DEBUG) {
576                     Slog.d(TAG, "value: " + value + ", constraint min: " + min.floatValue());
577                 }
578                 if (value <= min.floatValue()) {
579                     return false;
580                 }
581             }
582 
583             final BigDecimal minInclusive = range.getMinInclusive_optional();
584             if (minInclusive != null) {
585                 if (DEBUG) {
586                     Slog.d(TAG, "value: " + value + ", constraint min-inclusive: "
587                             + minInclusive.floatValue());
588                 }
589                 if (value < minInclusive.floatValue()) {
590                     return false;
591                 }
592             }
593 
594             final BigDecimal max = range.getMax_optional();
595             if (max != null) {
596                 if (DEBUG) {
597                     Slog.d(TAG, "value: " + value + ", constraint max: " + max.floatValue());
598                 }
599                 if (value >= max.floatValue()) {
600                     return false;
601                 }
602             }
603 
604             final BigDecimal maxInclusive = range.getMaxInclusive_optional();
605             if (maxInclusive != null) {
606                 if (DEBUG) {
607                     Slog.d(TAG, "value: " + value + ", constraint max-inclusive: "
608                             + maxInclusive.floatValue());
609                 }
610                 if (value > maxInclusive.floatValue()) {
611                     return false;
612                 }
613             }
614 
615             return true;
616         }
617     }
618 
619     /**
620      * Implementation of {@link BooleanSupplier} whose result is the product of an AND operation
621      * applied to the result of all child suppliers.
622      */
623     private static final class AndBooleanSupplier implements BooleanSupplier {
624         @NonNull
625         List<BooleanSupplier> mBooleanSuppliers;
626 
AndBooleanSupplier(@onNull List<BooleanSupplier> booleanSuppliers)627         AndBooleanSupplier(@NonNull List<BooleanSupplier> booleanSuppliers) {
628             mBooleanSuppliers = booleanSuppliers;
629         }
630 
631         @Override
getAsBoolean()632         public boolean getAsBoolean() {
633             for (int i = 0; i < mBooleanSuppliers.size(); i++) {
634                 if (!mBooleanSuppliers.get(i).getAsBoolean()) {
635                     return false;
636                 }
637             }
638             return true;
639         }
640     }
641 
642     /**
643      * Returns the device state configuration file that should be used, or {@code null} if no file
644      * is present on the device.
645      * <p>
646      * Defaults to returning a config file present in the data/ dir at
647      * {@link #DATA_CONFIG_FILE_PATH}, and then falls back to the config file in the vendor/ dir
648      * at {@link #VENDOR_CONFIG_FILE_PATH} if no config file is found in the data/ dir.
649      */
650     @Nullable
getConfigurationFile()651     private static File getConfigurationFile() {
652         final File configFileFromDataDir = Environment.buildPath(Environment.getDataDirectory(),
653                 DATA_CONFIG_FILE_PATH, CONFIG_FILE_NAME);
654         if (configFileFromDataDir.exists()) {
655             return configFileFromDataDir;
656         }
657 
658         final File configFileFromVendorDir = Environment.buildPath(Environment.getVendorDirectory(),
659                 VENDOR_CONFIG_FILE_PATH, CONFIG_FILE_NAME);
660         if (configFileFromVendorDir.exists()) {
661             return configFileFromVendorDir;
662         }
663 
664         return null;
665     }
666 
667     @GuardedBy("mLock")
dumpSensorValues()668     private void dumpSensorValues() {
669         Slog.i(TAG, "Sensor values:");
670         for (Sensor sensor : mLatestSensorEvent.keySet()) {
671             SensorEvent sensorEvent = mLatestSensorEvent.get(sensor);
672             if (sensorEvent != null) {
673                 Slog.i(TAG, sensor.getName() + ": " + Arrays.toString(sensorEvent.values));
674             } else {
675                 Slog.i(TAG, sensor.getName() + ": null");
676             }
677         }
678     }
679 
680     /**
681      * Tries to parse the provided file into a {@link DeviceStateConfig} object. Returns
682      * {@code null} if the file could not be successfully parsed.
683      */
684     @Nullable
parseConfig(@onNull ReadableConfig readableConfig)685     private static DeviceStateConfig parseConfig(@NonNull ReadableConfig readableConfig) {
686         try (InputStream in = readableConfig.openRead();
687                 InputStream bin = new BufferedInputStream(in)) {
688             return XmlParser.read(bin);
689         } catch (IOException | DatatypeConfigurationException | XmlPullParserException e) {
690             Slog.e(TAG, "Encountered an error while reading device state config", e);
691         }
692         return null;
693     }
694 
695     /** Implementation of {@link ReadableConfig} that reads config data from a file. */
696     private static final class ReadableFileConfig implements ReadableConfig {
697         @NonNull
698         private final File mFile;
699 
ReadableFileConfig(@onNull File file)700         private ReadableFileConfig(@NonNull File file) {
701             mFile = file;
702         }
703 
704         @Override
openRead()705         public InputStream openRead() throws IOException {
706             return new FileInputStream(mFile);
707         }
708     }
709 
710     @VisibleForTesting
onPowerSaveModeChanged(boolean isPowerSaveModeEnabled)711     void onPowerSaveModeChanged(boolean isPowerSaveModeEnabled) {
712         synchronized (mLock) {
713             if (mPowerSaveModeEnabled != isPowerSaveModeEnabled) {
714                 mPowerSaveModeEnabled = isPowerSaveModeEnabled;
715                 notifySupportedStatesChanged(
716                         isPowerSaveModeEnabled ? SUPPORTED_DEVICE_STATES_CHANGED_POWER_SAVE_ENABLED
717                                 : SUPPORTED_DEVICE_STATES_CHANGED_POWER_SAVE_DISABLED);
718             }
719         }
720     }
721 
722     @Override
onThermalStatusChanged(@owerManager.ThermalStatus int thermalStatus)723     public void onThermalStatusChanged(@PowerManager.ThermalStatus int thermalStatus) {
724         int previousThermalStatus;
725         synchronized (mLock) {
726             previousThermalStatus = mThermalStatus;
727             mThermalStatus = thermalStatus;
728         }
729 
730         boolean isThermalStatusCriticalOrAbove = isThermalStatusCriticalOrAbove(thermalStatus);
731         boolean isPreviousThermalStatusCriticalOrAbove =
732                 isThermalStatusCriticalOrAbove(previousThermalStatus);
733         if (isThermalStatusCriticalOrAbove != isPreviousThermalStatusCriticalOrAbove) {
734             Slog.i(TAG, "Updating supported device states due to thermal status change."
735                     + " isThermalStatusCriticalOrAbove: " + isThermalStatusCriticalOrAbove);
736             notifySupportedStatesChanged(
737                     isThermalStatusCriticalOrAbove
738                             ? SUPPORTED_DEVICE_STATES_CHANGED_THERMAL_CRITICAL
739                             : SUPPORTED_DEVICE_STATES_CHANGED_THERMAL_NORMAL);
740         }
741     }
742 
isThermalStatusCriticalOrAbove( @owerManager.ThermalStatus int thermalStatus)743     private static boolean isThermalStatusCriticalOrAbove(
744             @PowerManager.ThermalStatus int thermalStatus) {
745         switch (thermalStatus) {
746             case PowerManager.THERMAL_STATUS_CRITICAL:
747             case PowerManager.THERMAL_STATUS_EMERGENCY:
748             case PowerManager.THERMAL_STATUS_SHUTDOWN:
749                 return true;
750             default:
751                 return false;
752         }
753     }
754 
hasThermalSensitiveState(List<DeviceState> deviceStates)755     private static boolean hasThermalSensitiveState(List<DeviceState> deviceStates) {
756         for (DeviceState state : deviceStates) {
757             if (state.hasFlag(DeviceState.FLAG_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL)) {
758                 return true;
759             }
760         }
761         return false;
762     }
763 
hasPowerSaveSensitiveState(List<DeviceState> deviceStates)764     private static boolean hasPowerSaveSensitiveState(List<DeviceState> deviceStates) {
765         for (int i = 0; i < deviceStates.size(); i++) {
766             if (deviceStates.get(i).hasFlag(DeviceState.FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE)) {
767                 return true;
768             }
769         }
770         return false;
771     }
772 }
773