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