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