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