1 /* 2 * Copyright (C) 2010 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.tradefed.targetprep; 18 19 import com.android.ddmlib.IDevice; 20 import com.android.tradefed.config.Option; 21 import com.android.tradefed.config.OptionClass; 22 import com.android.tradefed.dependencies.ExternalDependency; 23 import com.android.tradefed.dependencies.IExternalDependency; 24 import com.android.tradefed.dependencies.connectivity.BluetoothDependency; 25 import com.android.tradefed.dependencies.connectivity.EthernetDependency; 26 import com.android.tradefed.dependencies.connectivity.NetworkDependency; 27 import com.android.tradefed.dependencies.connectivity.TelephonyDependency; 28 import com.android.tradefed.device.DeviceNotAvailableException; 29 import com.android.tradefed.device.ITestDevice; 30 import com.android.tradefed.device.LocalAndroidVirtualDevice; 31 import com.android.tradefed.device.StubDevice; 32 import com.android.tradefed.device.TestDevice; 33 import com.android.tradefed.device.TestDeviceState; 34 import com.android.tradefed.device.cloud.NestedRemoteDevice; 35 import com.android.tradefed.device.cloud.RemoteAndroidVirtualDevice; 36 import com.android.tradefed.invoker.TestInformation; 37 import com.android.tradefed.invoker.logger.InvocationMetricLogger; 38 import com.android.tradefed.invoker.logger.InvocationMetricLogger.InvocationMetricKey; 39 import com.android.tradefed.invoker.tracing.CloseableTraceScope; 40 import com.android.tradefed.log.LogUtil.CLog; 41 import com.android.tradefed.result.error.DeviceErrorIdentifier; 42 import com.android.tradefed.result.error.InfraErrorIdentifier; 43 import com.android.tradefed.util.BinaryState; 44 import com.android.tradefed.util.CommandResult; 45 import com.android.tradefed.util.CommandStatus; 46 import com.android.tradefed.util.MultiMap; 47 import com.android.tradefed.util.RunUtil; 48 import com.android.tradefed.util.executor.ParallelDeviceExecutor; 49 50 import com.google.common.annotations.VisibleForTesting; 51 import com.google.common.base.Strings; 52 53 import java.io.File; 54 import java.util.ArrayList; 55 import java.util.Collection; 56 import java.util.HashMap; 57 import java.util.LinkedHashMap; 58 import java.util.LinkedHashSet; 59 import java.util.List; 60 import java.util.Map; 61 import java.util.Set; 62 import java.util.TimeZone; 63 import java.util.concurrent.Callable; 64 import java.util.concurrent.TimeUnit; 65 66 /** 67 * A {@link ITargetPreparer} that configures a device for testing based on provided {@link Option}s. 68 * 69 * <p>Requires a device where 'adb root' is possible, typically a userdebug build type. 70 * 71 * <p>Should be performed <strong>after</strong> a new build is flashed. 72 * 73 * <p><strong>Note:</strong> this preparer is meant for continuous testing labs and assumes that the 74 * device under test will be flashed and wiped before the next run. As such, it does minimal clean 75 * up during teardown and should not be used in a test module. 76 */ 77 @OptionClass(alias = "device-setup") 78 public class DeviceSetup extends BaseTargetPreparer implements IExternalDependency { 79 80 // Networking 81 @Option(name = "airplane-mode", 82 description = "Turn airplane mode on or off") 83 protected BinaryState mAirplaneMode = BinaryState.IGNORE; 84 // ON: settings put global airplane_mode_on 1 85 // am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true 86 // OFF: settings put global airplane_mode_on 0 87 // am broadcast -a android.intent.action.AIRPLANE_MODE --ez state false 88 89 @Option(name = "data", description = "Turn mobile data on or off") 90 protected BinaryState mData = BinaryState.IGNORE; 91 // ON: settings put global mobile_data 1 92 // svc data enable 93 // OFF: settings put global mobile_data 0 94 // svc data disable 95 96 @Option(name = "cell", description = "Turn cellular radio on or off") 97 protected BinaryState mCell = BinaryState.IGNORE; 98 // ON: settings put global cell_on 1 99 // OFF: settings put global cell_on 0 100 101 @Option(name = "cell-auto-setting", description = "Turn wear cellular mediator on or off") 102 protected BinaryState mCellAutoSetting = BinaryState.IGNORE; 103 // ON: settings put global clockwork_cell_auto_setting 1 104 // OFF: settings put global clockwork_cell_auto_setting 0 105 106 @Option(name = "wifi", description = "Turn wifi on or off") 107 protected BinaryState mWifi = BinaryState.IGNORE; 108 // ON: settings put global wifi_on 1 109 // svc wifi enable 110 // OFF: settings put global wifi_off 0 111 // svc wifi disable 112 113 @Option( 114 name = "skip-wifi-connection", 115 description = "Whether or not to completely skip connecting to wifi.") 116 private boolean mSkipWifi = false; 117 118 @Option(name = "wifi-network", 119 description = "The SSID of the network to connect to. Will only attempt to " + 120 "connect to a network if set") 121 protected String mWifiSsid = null; 122 123 @Option(name = "wifi-psk", 124 description = "The passphrase used to connect to a secured network") 125 protected String mWifiPsk = null; 126 127 @Option(name = "wifi-ssid-to-psk", description = "A map of wifi SSIDs to passwords.") 128 protected Map<String, String> mWifiSsidToPsk = new LinkedHashMap<>(); 129 130 @Option(name = "wifi-watchdog", 131 description = "Turn wifi watchdog on or off") 132 protected BinaryState mWifiWatchdog = BinaryState.IGNORE; 133 // ON: settings put global wifi_watchdog 1 134 // OFF: settings put global wifi_watchdog 0 135 136 @Option(name = "disable-cw-wifi-mediator", description = "Turn wifi mediator on or off") 137 protected BinaryState mDisableCwWifiMediator = BinaryState.IGNORE; 138 // ON: settings put global cw_disable_wifimediator 1 139 // OFF: settings put global cw_disable_wifimediator 0 140 141 @Option( 142 name = "wifi-scan-always-enabled", 143 description = "Turn wifi scan always enabled on or off" 144 ) 145 protected BinaryState mWifiScanAlwaysEnabled = BinaryState.IGNORE; 146 // ON: settings put global wifi_scan_always_enabled 1 147 // OFF: settings put global wifi_scan_always_enabled 0 148 149 @Option(name = "ethernet", 150 description = "Turn ethernet on or off") 151 protected BinaryState mEthernet = BinaryState.IGNORE; 152 // ON: ifconfig eth0 up 153 // OFF: ifconfig eth0 down 154 155 @Option(name = "bluetooth", 156 description = "Turn bluetooth on or off") 157 protected BinaryState mBluetooth = BinaryState.IGNORE; 158 // ON: svc bluetooth enable 159 // OFF: svc bluetooth disable 160 161 @Option(name = "nfc", 162 description = "Turn nfc on or off") 163 protected BinaryState mNfc = BinaryState.IGNORE; 164 // ON: svc nfc enable 165 // OFF: svc nfc disable 166 167 // Screen 168 @Option(name = "screen-adaptive-brightness", 169 description = "Turn screen adaptive brightness on or off") 170 protected BinaryState mScreenAdaptiveBrightness = BinaryState.IGNORE; 171 // ON: settings put system screen_brightness_mode 1 172 // OFF: settings put system screen_brightness_mode 0 173 174 @Option(name = "screen-brightness", 175 description = "Set the screen brightness. This is uncalibrated from product to product") 176 protected Integer mScreenBrightness = null; 177 // settings put system screen_brightness $N 178 179 @Option(name = "screen-always-on", 180 description = "Turn 'screen always on' on or off. If ON, then screen-timeout-secs " + 181 "must be unset. Will only work when the device is plugged in") 182 protected BinaryState mScreenAlwaysOn = BinaryState.ON; 183 // ON: svc power stayon true 184 // OFF: svc power stayon false 185 186 @Option(name = "screen-timeout-secs", 187 description = "Set the screen timeout in seconds. If set, then screen-always-on must " + 188 "be OFF or DEFAULT") 189 protected Long mScreenTimeoutSecs = null; 190 // settings put system screen_off_timeout $(N * 1000) 191 192 @Option(name = "screen-ambient-mode", 193 description = "Turn screen ambient mode on or off") 194 protected BinaryState mScreenAmbientMode = BinaryState.IGNORE; 195 // ON: settings put secure doze_enabled 1 196 // OFF: settings put secure doze_enabled 0 197 198 @Option(name = "wake-gesture", 199 description = "Turn wake gesture on or off") 200 protected BinaryState mWakeGesture = BinaryState.IGNORE; 201 // ON: settings put secure wake_gesture_enabled 1 202 // OFF: settings put secure wake_gesture_enabled 0 203 204 @Option(name = "screen-saver", 205 description = "Turn screen saver on or off") 206 protected BinaryState mScreenSaver = BinaryState.IGNORE; 207 // ON: settings put secure screensaver_enabled 1 208 // OFF: settings put secure screensaver_enabled 0 209 210 @Option(name = "notification-led", 211 description = "Turn the notification led on or off") 212 protected BinaryState mNotificationLed = BinaryState.IGNORE; 213 // ON: settings put system notification_light_pulse 1 214 // OFF: settings put system notification_light_pulse 0 215 216 @Option(name = "install-non-market-apps", 217 description = "Allow or prevent non-market app to initiate an apk install request") 218 protected BinaryState mInstallNonMarketApps = BinaryState.IGNORE; 219 // ON: settings put secure install_non_market_apps 1 220 // OFF: settings put secure install_non_market_apps 0 221 222 // Media 223 @Option(name = "trigger-media-mounted", 224 description = "Trigger a MEDIA_MOUNTED broadcast") 225 protected boolean mTriggerMediaMounted = false; 226 // am broadcast -a android.intent.action.MEDIA_MOUNTED -d file://${EXTERNAL_STORAGE} 227 // --receiver-include-background 228 229 // Location 230 @Option(name = "location-gps", description = "Turn the GPS location on or off") 231 protected BinaryState mLocationGps = BinaryState.IGNORE; 232 // ON: settings put secure location_providers_allowed +gps 233 // OFF: settings put secure location_providers_allowed -gps 234 235 @Option(name = "location-network", 236 description = "Turn the network location on or off") 237 protected BinaryState mLocationNetwork = BinaryState.IGNORE; 238 // ON: settings put secure location_providers_allowed +network 239 // OFF: settings put secure location_providers_allowed -network 240 241 // Sensor 242 @Option(name = "auto-rotate", 243 description = "Turn auto rotate on or off") 244 protected BinaryState mAutoRotate = BinaryState.IGNORE; 245 // ON: settings put system accelerometer_rotation 1 246 // OFF: settings put system accelerometer_rotation 0 247 248 // Power 249 @Option(name = "battery-saver-mode", 250 description = "Turn battery saver mode manually on or off. If OFF but battery is " + 251 "less battery-saver-trigger, the device will still go into battery saver mode") 252 protected BinaryState mBatterySaver = BinaryState.IGNORE; 253 // ON: dumpsys battery set usb 0 254 // settings put global low_power 1 255 // OFF: settings put global low_power 0 256 257 @Option(name = "battery-saver-trigger", 258 description = "Set the battery saver trigger level. Should be [1-99] to enable, or " + 259 "0 to disable automatic battery saver mode") 260 protected Integer mBatterySaverTrigger = null; 261 // settings put global low_power_trigger_level $N 262 263 @Option(name = "enable-full-battery-stats-history", 264 description = "Enable full history for batterystats. This option is only " + 265 "applicable for L+") 266 protected boolean mEnableFullBatteryStatsHistory = false; 267 // dumpsys batterystats --enable full-history 268 269 @Option(name = "disable-doze", 270 description = "Disable device from going into doze mode. This option is only " + 271 "applicable for M+") 272 protected boolean mDisableDoze = false; 273 // dumpsys deviceidle disable 274 275 // Time 276 @Option(name = "auto-update-time", 277 description = "Turn auto update time on or off") 278 protected BinaryState mAutoUpdateTime = BinaryState.IGNORE; 279 // ON: settings put global auto_time 1 280 // OFF: settings put global auto_time 0 281 282 @Option(name = "auto-update-timezone", description = "Turn auto update timezone on or off") 283 protected BinaryState mAutoUpdateTimezone = BinaryState.IGNORE; 284 // ON: settings put global auto_timezone 1 285 // OFF: settings put global auto_timezone 0 286 287 @Option( 288 name = "set-timezone", 289 description = 290 "Set timezone property by TZ name " 291 + "(http://en.wikipedia.org/wiki/List_of_tz_database_time_zones)") 292 protected String mTimezone = null; 293 294 @Option(name = "sync-timezone-with-host", 295 description = 296 "Turn on or off that make the time zone of device sync with host") 297 protected BinaryState mSyncTimezoneWithHost = BinaryState.IGNORE; 298 // ON: settings put global sync_timezone 1 299 // OFF: settings put global sync_timezone 0 300 301 // Calling 302 @Option(name = "disable-dialing", 303 description = "Disable dialing") 304 protected boolean mDisableDialing = true; 305 // setprop ro.telephony.disable-call true" 306 307 @Option(name = "default-sim-data", 308 description = "Set the default sim card slot for data. Leave unset for single SIM " + 309 "devices") 310 protected Integer mDefaultSimData = null; 311 // settings put global multi_sim_data_call $N 312 313 @Option(name = "default-sim-voice", 314 description = "Set the default sim card slot for voice calls. Leave unset for single " + 315 "SIM devices") 316 protected Integer mDefaultSimVoice = null; 317 // settings put global multi_sim_voice_call $N 318 319 @Option(name = "default-sim-sms", 320 description = "Set the default sim card slot for SMS. Leave unset for single SIM " + 321 "devices") 322 protected Integer mDefaultSimSms = null; 323 // settings put global multi_sim_sms $N 324 325 // Audio 326 private static final boolean DEFAULT_DISABLE_AUDIO = true; 327 @Option(name = "disable-audio", 328 description = "Disable the audio") 329 protected boolean mDisableAudio = DEFAULT_DISABLE_AUDIO; 330 // setprop ro.audio.silent 1" 331 332 @Option(name = "force-skip-system-props", 333 description = "Force setup to not modify any device system properties. All other " + 334 "system property options will be ignored") 335 protected boolean mForceSkipSystemProps = false; 336 337 @Option( 338 name = "force-root-setup", 339 description = 340 "Force switching to root before the setup.Root should only be need for system" 341 + " props, but adding this flag while transitioning in case someone reports" 342 + " issues.") 343 private boolean mForceRoot = false; 344 345 @Option(name = "force-skip-settings", 346 description = "Force setup to not modify any device settings. All other setting " + 347 "options will be ignored.") 348 protected boolean mForceSkipSettings = false; 349 350 @Option(name = "force-skip-run-commands", 351 description = "Force setup to not run any additional commands. All other commands " + 352 "will be ignored.") 353 protected boolean mForceSkipRunCommands = false; 354 355 @Option(name = "set-test-harness", 356 description = "Set the read-only test harness flag on boot") 357 protected boolean mSetTestHarness = true; 358 // setprop ro.monkey 1 359 // setprop ro.test_harness 1 360 // setprop persist.sys.test_harness 1 361 362 @Option(name = "hide-error-dialogs", description = "Turn on or off the error dialogs.") 363 protected BinaryState mHideErrorDialogs = BinaryState.ON; 364 // ON: settings put global hide_error_dialogs 1 365 // OFF: settings put global hide_error_dialogs 0 366 367 @Option( 368 name = "disable-dalvik-verifier", 369 description = 370 "Disable the dalvik verifier on device. Allows package-private " 371 + "framework tests to run.") 372 protected boolean mDisableDalvikVerifier = false; 373 // setprop dalvik.vm.dexopt-flags v=n 374 375 @Option(name = "set-property", 376 description = "Set the specified property on boot. Option may be repeated but only " + 377 "the last value for a given key will be set.") 378 protected Map<String, String> mSetProps = new HashMap<>(); 379 380 @Option( 381 name = "restore-properties", 382 description = 383 "Restore previous /data/local.prop on tear down, restoring any properties" 384 + " DeviceSetup changed by modifying /data/local.prop.") 385 protected boolean mRestoreProperties = false; 386 387 protected File mPreviousProperties; 388 389 @Option(name = "set-system-setting", 390 description = "Change a system (non-secure) setting. Option may be repeated and all " + 391 "key/value pairs will be set in order.") 392 // Use a Multimap since it is possible for a setting to have multiple values for the same key 393 protected MultiMap<String, String> mSystemSettings = new MultiMap<>(); 394 395 @Option(name = "set-secure-setting", 396 description = "Change a secure setting. Option may be repeated and all key/value " + 397 "pairs will be set in order.") 398 // Use a Multimap since it is possible for a setting to have multiple values for the same key 399 protected MultiMap<String, String> mSecureSettings = new MultiMap<>(); 400 401 @Option(name = "set-global-setting", 402 description = "Change a global setting. Option may be repeated and all key/value " + 403 "pairs will be set in order.") 404 // Use a Multimap since it is possible for a setting to have multiple values for the same key 405 protected MultiMap<String, String> mGlobalSettings = new MultiMap<>(); 406 407 @Option( 408 name = "restore-settings", 409 description = "Restore settings modified by this preparer on tear down." 410 ) 411 protected boolean mRestoreSettings = false; 412 413 @Option( 414 name = "optimized-non-persistent-setup", 415 description = "Feature to evaluate a faster non-persistent props setup.") 416 private boolean mOptimizeNonPersistentSetup = true; 417 418 @Option( 419 name = "dismiss-setup-wizard", 420 description = "Attempt to dismiss the setup wizard if present.") 421 private boolean mDismissSetupWizard = true; 422 423 @Option( 424 name = "dismiss-setup-wizard-timeout", 425 description = "Set the timeout for dismissing setup wizard in milli seconds.") 426 private Long mDismissSetupWizardTimeout = 60 * 1000L; 427 428 @Option( 429 name = "dismiss-setup-wizard-retry-count", 430 description = "Number of times to retry to dismiss setup wizard.") 431 private int mDismissSetupWizardRetry = 2; 432 433 private Map<String, String> mPreviousSystemSettings = new HashMap<>(); 434 private Map<String, String> mPreviousSecureSettings = new HashMap<>(); 435 private Map<String, String> mPreviousGlobalSettings = new HashMap<>(); 436 437 protected List<String> mRunCommandBeforeSettings = new ArrayList<>(); 438 439 @Option(name = "run-command", 440 description = "Run an adb shell command. Option may be repeated") 441 protected List<String> mRunCommandAfterSettings = new ArrayList<>(); 442 443 @Option(name = "disconnect-wifi-after-test", 444 description = "Disconnect from wifi network after test completes.") 445 private boolean mDisconnectWifiAfterTest = true; 446 447 private static final long DEFAULT_MIN_EXTERNAL_STORAGE_KB = 500; 448 @Option(name = "min-external-storage-kb", 449 description="The minimum amount of free space in KB that must be present on device's " + 450 "external storage.") 451 protected long mMinExternalStorageKb = DEFAULT_MIN_EXTERNAL_STORAGE_KB; 452 453 @Option(name = "local-data-path", 454 description = "Optional local file path of test data to sync to device's external " + 455 "storage. Use --remote-data-path to set remote location.") 456 protected File mLocalDataFile = null; 457 458 @Option(name = "remote-data-path", 459 description = "Optional file path on device's external storage to sync test data. " + 460 "Must be used with --local-data-path.") 461 protected String mRemoteDataPath = null; 462 463 @Option( 464 name = "optimized-property-setting", 465 description = 466 "If a property is already set to the desired value, don't reboot the device") 467 protected boolean mOptimizedPropertySetting = true; 468 469 // Deprecated options follow 470 /** 471 * @deprecated use min-external-storage-kb instead. 472 */ 473 @Option(name = "min-external-store-space", 474 description = "deprecated, use option min-external-storage-kb. The minimum amount of " + 475 "free space in KB that must be present on device's external storage.") 476 @Deprecated 477 private long mDeprecatedMinExternalStoreSpace = DEFAULT_MIN_EXTERNAL_STORAGE_KB; 478 479 /** 480 * @deprecated use option disable-audio instead. 481 */ 482 @Option(name = "audio-silent", 483 description = "deprecated, use option disable-audio. set ro.audio.silent on boot.") 484 @Deprecated 485 private boolean mDeprecatedSetAudioSilent = DEFAULT_DISABLE_AUDIO; 486 487 /** 488 * @deprecated use option set-property instead. 489 */ 490 @Option(name = "setprop", 491 description = "deprecated, use option set-property. set the specified property on " + 492 "boot. Format: --setprop key=value. May be repeated.") 493 @Deprecated 494 private Collection<String> mDeprecatedSetProps = new ArrayList<String>(); 495 496 @Option( 497 name = "skip-virtual-device-teardown", 498 description = "Whether or not to skip the teardown if it's a virtual device.") 499 private boolean mSkipVirtualDeviceTeardown = true; 500 501 @Option( 502 name = "disable-device-config-sync", 503 description = "Disable syncing device config with remote configuration server.") 504 private boolean mDisableDeviceConfigSync = false; 505 // device_config set_sync_disabled_for_tests persistent 506 507 @Option( 508 name = "disable-ramdump", 509 description = "Will set the flag to disable ramdump on the device.") 510 private boolean mDisableRamdump = false; 511 512 @Option(name = "parallelize-core-setup") 513 private boolean mParallelCoreSetup = false; 514 515 @Option(name = "dismiss-keyguard-via-wm", description = "Flag to dismiss keyguard via wm") 516 private boolean mDismissViaWm = false; 517 518 private static final String PERSIST_PREFIX = "persist."; 519 private static final String MEMTAG_BOOTCTL = "arm64.memtag.bootctl"; 520 521 private static final List<String> PROPERTIES_NEEDING_REBOOT = 522 List.of( 523 // MEMTAG_BOOTCTL stores a value in the misc partition that gets applied on 524 // reboot. 525 MEMTAG_BOOTCTL, 526 // Zygote caches the value of this property because it's expected to reboot the 527 // system whenever this property changes. 528 "persist.debug.dalvik.vm.jdwp.enabled"); 529 getDevice(TestInformation testInfo)530 public ITestDevice getDevice(TestInformation testInfo) { 531 return testInfo.getDevice(); 532 } 533 534 /** {@inheritDoc} */ 535 @Override setUp(TestInformation testInfo)536 public void setUp(TestInformation testInfo) 537 throws DeviceNotAvailableException, BuildError, TargetSetupError { 538 ITestDevice device = getDevice(testInfo); 539 CLog.i("Performing setup on %s", device.getSerialNumber()); 540 541 if (mForceRoot && device.getOptions().isEnableAdbRoot()) { 542 if (!device.enableAdbRoot()) { 543 throw new TargetSetupError( 544 String.format("Failed to enable adb root on %s", device.getSerialNumber()), 545 device.getDeviceDescriptor(), 546 DeviceErrorIdentifier.DEVICE_UNEXPECTED_RESPONSE); 547 } 548 } 549 550 // Convert deprecated options into current options 551 processDeprecatedOptions(device); 552 // Convert options into settings and run commands 553 processOptions(device); 554 // Change system props (will reboot device) 555 changeSystemProps(device); 556 // Run commands designated to be run before changing settings 557 runCommands(device, mRunCommandBeforeSettings); 558 List<Callable<Boolean>> callableTasks = new ArrayList<>(); 559 560 callableTasks.add( 561 () -> { 562 // Handle screen always on setting 563 handleScreenAlwaysOnSetting(device); 564 return true; 565 }); 566 callableTasks.add( 567 () -> { 568 // Change settings 569 changeSettings(device); 570 return true; 571 }); 572 callableTasks.add( 573 () -> { 574 // Connect wifi after settings since this may take a while 575 connectWifi(device); 576 return true; 577 }); 578 callableTasks.add( 579 () -> { 580 // Sync data after settings since this may take a while 581 syncTestData(device); 582 return true; 583 }); 584 callableTasks.add( 585 () -> { 586 // Throw an error if there is not enough storage space 587 checkExternalStoreSpace(device); 588 return true; 589 }); 590 if (mDismissSetupWizard) { 591 callableTasks.add( 592 () -> { 593 dismissSetupWizard(device); 594 return true; 595 }); 596 } 597 if (mParallelCoreSetup) { 598 ParallelDeviceExecutor<Boolean> executor = 599 new ParallelDeviceExecutor<Boolean>(callableTasks.size()); 600 executor.invokeAll(callableTasks, 5, TimeUnit.MINUTES); 601 if (executor.hasErrors()) { 602 List<Throwable> errors = executor.getErrors(); 603 // TODO: Handle throwing multi-exceptions, right now throw the first one. 604 for (Throwable error : errors) { 605 if (error instanceof TargetSetupError) { 606 throw (TargetSetupError) error; 607 } 608 if (error instanceof BuildError) { 609 throw (BuildError) error; 610 } 611 if (error instanceof DeviceNotAvailableException) { 612 throw (DeviceNotAvailableException) error; 613 } 614 throw new RuntimeException(error); 615 } 616 } 617 } else { 618 // Handle screen always on setting 619 handleScreenAlwaysOnSetting(device); 620 // Change settings 621 changeSettings(device); 622 // Connect wifi after settings since this may take a while 623 connectWifi(device); 624 // Sync data after settings since this may take a while 625 syncTestData(device); 626 // Throw an error if there is not enough storage space 627 checkExternalStoreSpace(device); 628 if (mDismissSetupWizard) { 629 dismissSetupWizard(device); 630 } 631 } 632 // Run commands designated to be run after changing settings 633 runCommands(device, mRunCommandAfterSettings); 634 635 device.clearErrorDialogs(); 636 } 637 638 /** {@inheritDoc} */ 639 @Override tearDown(TestInformation testInfo, Throwable e)640 public void tearDown(TestInformation testInfo, Throwable e) throws DeviceNotAvailableException { 641 ITestDevice device = testInfo.getDevice(); 642 // ignore tearDown if it's a stub device, since there is no real device to clean. 643 if (device.getIDevice() instanceof StubDevice) { 644 return; 645 } 646 if (device instanceof RemoteAndroidVirtualDevice && mSkipVirtualDeviceTeardown) { 647 CLog.d("Skipping teardown on virtual device that will be deleted."); 648 return; 649 } 650 if (e instanceof DeviceFailedToBootError) { 651 CLog.d("boot failure: skipping teardown"); 652 return; 653 } 654 if (e instanceof DeviceNotAvailableException) { 655 CLog.d("device not available: skipping teardown"); 656 return; 657 } 658 if (!TestDeviceState.ONLINE.equals(device.getDeviceState())) { 659 CLog.d("device offline: skipping teardown"); 660 return; 661 } 662 CLog.i("Performing teardown on %s", device.getSerialNumber()); 663 664 // Only try to disconnect if wifi ssid is set since isWifiEnabled() is a heavy operation 665 // which should be avoided when possible 666 boolean wifiSet = mWifiSsid != null || !mWifiSsidToPsk.isEmpty(); 667 if (mDisconnectWifiAfterTest && wifiSet && device.isWifiEnabled()) { 668 boolean result = device.disconnectFromWifi(); 669 if (result) { 670 CLog.i("Successfully disconnected from wifi network on %s", 671 device.getSerialNumber()); 672 } else { 673 CLog.w("Failed to disconnect from wifi network on %s", device.getSerialNumber()); 674 } 675 } 676 677 if (mRestoreProperties) { 678 if (mPreviousProperties != null) { 679 device.pushFile(mPreviousProperties, "/data/local.prop"); 680 } else { 681 device.deleteFile("/data/local.prop"); 682 } 683 device.reboot(); 684 } 685 686 if (mRestoreSettings) { 687 for (Map.Entry<String, String> entry : mPreviousSystemSettings.entrySet()) { 688 device.setSetting("system", entry.getKey(), entry.getValue()); 689 } 690 for (Map.Entry<String, String> entry : mPreviousGlobalSettings.entrySet()) { 691 device.setSetting("global", entry.getKey(), entry.getValue()); 692 } 693 for (Map.Entry<String, String> entry : mPreviousSecureSettings.entrySet()) { 694 device.setSetting("secure", entry.getKey(), entry.getValue()); 695 } 696 } 697 } 698 699 /** 700 * Processes the deprecated options converting them into the currently used options. 701 * <p> 702 * This method should be run before any other processing methods. Will throw a 703 * {@link TargetSetupError} if the deprecated option overrides a specified non-deprecated 704 * option. 705 * </p> 706 * @throws TargetSetupError if there is a conflict 707 */ processDeprecatedOptions(ITestDevice device)708 public void processDeprecatedOptions(ITestDevice device) throws TargetSetupError { 709 if (mDeprecatedMinExternalStoreSpace != DEFAULT_MIN_EXTERNAL_STORAGE_KB) { 710 if (mMinExternalStorageKb != DEFAULT_MIN_EXTERNAL_STORAGE_KB) { 711 throw new TargetSetupError("Deprecated option min-external-store-space conflicts " + 712 "with option min-external-storage-kb", device.getDeviceDescriptor()); 713 } 714 mMinExternalStorageKb = mDeprecatedMinExternalStoreSpace; 715 } 716 717 if (mDeprecatedSetAudioSilent != DEFAULT_DISABLE_AUDIO) { 718 if (mDisableAudio != DEFAULT_DISABLE_AUDIO) { 719 throw new TargetSetupError("Deprecated option audio-silent conflicts with " + 720 "option disable-audio", device.getDeviceDescriptor()); 721 } 722 mDisableAudio = mDeprecatedSetAudioSilent; 723 } 724 725 if (!mDeprecatedSetProps.isEmpty()) { 726 if (!mSetProps.isEmpty()) { 727 throw new TargetSetupError("Deprecated option setprop conflicts with option " + 728 "set-property ", device.getDeviceDescriptor()); 729 } 730 for (String prop : mDeprecatedSetProps) { 731 String[] parts = prop.split("=", 2); 732 String key = parts[0].trim(); 733 String value = parts.length == 2 ? parts[1].trim() : ""; 734 mSetProps.put(key, value); 735 } 736 } 737 } 738 739 /** 740 * Process all the {@link Option}s and turn them into system props, settings, or run commands. 741 * Does not run any commands on the device at this time. 742 * <p> 743 * Exposed so that children classes may override this. 744 * </p> 745 * 746 * @param device The {@link ITestDevice} 747 * @throws DeviceNotAvailableException if the device is not available 748 * @throws TargetSetupError if the {@link Option}s conflict 749 */ processOptions(ITestDevice device)750 public void processOptions(ITestDevice device) throws DeviceNotAvailableException, 751 TargetSetupError { 752 setSettingForBinaryState(mData, mGlobalSettings, "mobile_data", "1", "0"); 753 setCommandForBinaryState( 754 mData, mRunCommandAfterSettings, "svc data enable", "svc data disable"); 755 756 setSettingForBinaryState(mCell, mGlobalSettings, "cell_on", "1", "0"); 757 setSettingForBinaryState( 758 mCellAutoSetting, mGlobalSettings, "clockwork_cell_auto_setting", "1", "0"); 759 760 setSettingForBinaryState(mWifi, mGlobalSettings, "wifi_on", "1", "0"); 761 setCommandForBinaryState( 762 mWifi, mRunCommandAfterSettings, "svc wifi enable", "svc wifi disable"); 763 764 setSettingForBinaryState(mWifiWatchdog, mGlobalSettings, "wifi_watchdog", "1", "0"); 765 setSettingForBinaryState( 766 mDisableCwWifiMediator, mGlobalSettings, "cw_disable_wifimediator", "1", "0"); 767 768 setSettingForBinaryState(mWifiScanAlwaysEnabled, mGlobalSettings, 769 "wifi_scan_always_enabled", "1", "0"); 770 771 setCommandForBinaryState(mEthernet, mRunCommandAfterSettings, 772 "ifconfig eth0 up", "ifconfig eth0 down"); 773 774 setCommandForBinaryState( 775 mBluetooth, 776 mRunCommandAfterSettings, 777 "cmd bluetooth_manager enable && cmd bluetooth_manager wait-for-state:STATE_ON", 778 "cmd bluetooth_manager disable && cmd bluetooth_manager wait-for-state:STATE_OFF"); 779 780 setCommandForBinaryState(mNfc, mRunCommandAfterSettings, 781 "svc nfc enable", "svc nfc disable"); 782 783 if (mScreenBrightness != null && BinaryState.ON.equals(mScreenAdaptiveBrightness)) { 784 throw new TargetSetupError("Option screen-brightness cannot be set when " + 785 "screen-adaptive-brightness is set to ON", device.getDeviceDescriptor()); 786 } 787 788 setSettingForBinaryState(mScreenAdaptiveBrightness, mSystemSettings, 789 "screen_brightness_mode", "1", "0"); 790 791 if (mScreenBrightness != null) { 792 mSystemSettings.put("screen_brightness", Integer.toString(mScreenBrightness)); 793 } 794 795 if (mScreenTimeoutSecs != null) { 796 mSystemSettings.put("screen_off_timeout", Long.toString(mScreenTimeoutSecs * 1000)); 797 } 798 799 setSettingForBinaryState(mScreenAmbientMode, mSecureSettings, "doze_enabled", "1", "0"); 800 801 setSettingForBinaryState(mWakeGesture, mSecureSettings, "wake_gesture_enabled", "1", "0"); 802 803 setSettingForBinaryState(mScreenSaver, mSecureSettings, "screensaver_enabled", "1", "0"); 804 805 setSettingForBinaryState(mNotificationLed, mSystemSettings, 806 "notification_light_pulse", "1", "0"); 807 808 setSettingForBinaryState(mInstallNonMarketApps, mSecureSettings, 809 "install_non_market_apps", "1", "0"); 810 811 if (mTriggerMediaMounted) { 812 mRunCommandAfterSettings.add( 813 "am broadcast -a android.intent.action.MEDIA_MOUNTED -d " 814 + "file://${EXTERNAL_STORAGE} --receiver-include-background"); 815 } 816 817 setSettingForBinaryState(mLocationGps, mSecureSettings, 818 "location_providers_allowed", "+gps", "-gps"); 819 820 setSettingForBinaryState(mLocationNetwork, mSecureSettings, 821 "location_providers_allowed", "+network", "-network"); 822 823 setSettingForBinaryState(mAutoRotate, mSystemSettings, "accelerometer_rotation", "1", "0"); 824 825 if (device.getApiLevel() < 22) { 826 setCommandForBinaryState(mBatterySaver, mRunCommandBeforeSettings, 827 "dumpsys battery set usb 0", null); 828 } else { 829 setCommandForBinaryState(mBatterySaver, mRunCommandBeforeSettings, 830 "dumpsys battery unplug", null); 831 } 832 setSettingForBinaryState(mBatterySaver, mGlobalSettings, "low_power", "1", "0"); 833 834 if (mBatterySaverTrigger != null) { 835 mGlobalSettings.put("low_power_trigger_level", Integer.toString(mBatterySaverTrigger)); 836 } 837 838 if (mEnableFullBatteryStatsHistory) { 839 mRunCommandAfterSettings.add("dumpsys batterystats --enable full-history"); 840 } 841 842 if (mDisableDoze) { 843 mRunCommandAfterSettings.add("dumpsys deviceidle disable"); 844 } 845 846 setSettingForBinaryState(mAutoUpdateTime, mGlobalSettings, "auto_time", "1", "0"); 847 848 setSettingForBinaryState(mAutoUpdateTimezone, mGlobalSettings, "auto_timezone", "1", "0"); 849 850 if (BinaryState.ON.equals(mSyncTimezoneWithHost)) { 851 if (mTimezone != null) { 852 throw new TargetSetupError("Option set-timezone cannot be set when " + 853 "sync-timezone-with-host is set to ON", 854 device.getDeviceDescriptor(), 855 InfraErrorIdentifier.OPTION_CONFIGURATION_ERROR); 856 } else { 857 mTimezone = TimeZone.getDefault().getID(); 858 } 859 } 860 861 setSettingForBinaryState( 862 mHideErrorDialogs, mGlobalSettings, "hide_error_dialogs", "1", "0"); 863 864 if (mTimezone != null) { 865 CLog.i("The actual timezone we set here is %s", mTimezone); 866 mSetProps.put("persist.sys.timezone", mTimezone); 867 } 868 869 if (mDisableDialing) { 870 mSetProps.put("ro.telephony.disable-call", "true"); 871 } 872 873 if (mDefaultSimData != null) { 874 mGlobalSettings.put("multi_sim_data_call", Integer.toString(mDefaultSimData)); 875 } 876 877 if (mDefaultSimVoice != null) { 878 mGlobalSettings.put("multi_sim_voice_call", Integer.toString(mDefaultSimVoice)); 879 } 880 881 if (mDefaultSimSms != null) { 882 mGlobalSettings.put("multi_sim_sms", Integer.toString(mDefaultSimSms)); 883 } 884 885 if (mDisableAudio) { 886 mSetProps.put("ro.audio.silent", "1"); 887 } 888 889 if (mSetTestHarness) { 890 // set both ro.monkey, ro.test_harness, persist.sys.test_harness, for compatibility with 891 // older platforms 892 mSetProps.put("ro.monkey", "1"); 893 mSetProps.put("ro.test_harness", "1"); 894 mSetProps.put("persist.sys.test_harness", "1"); 895 } 896 897 if (mDisableDalvikVerifier) { 898 mSetProps.put("dalvik.vm.dexopt-flags", "v=n"); 899 } 900 901 if (mDisableDeviceConfigSync) { 902 mRunCommandBeforeSettings.add("device_config set_sync_disabled_for_tests persistent"); 903 } 904 } 905 906 /** 907 * Change the system properties on the device. 908 * 909 * @param device The {@link ITestDevice} 910 * @throws DeviceNotAvailableException if the device is not available 911 * @throws TargetSetupError if there was a failure setting the system properties 912 */ changeSystemProps(ITestDevice device)913 private void changeSystemProps(ITestDevice device) throws DeviceNotAvailableException, 914 TargetSetupError { 915 if (mForceSkipSystemProps) { 916 CLog.d("Skipping system props due to force-skip-system-props"); 917 return; 918 } 919 920 if (mSetProps.size() > 0 && !device.enableAdbRoot()) { 921 throw new TargetSetupError( 922 String.format( 923 "Cannot set system props %s on %s without adb root. Setting " 924 + "'force-skip-system-props' or 'enable-root' to avoid error", 925 mSetProps.toString(), device.getSerialNumber()), 926 device.getDeviceDescriptor(), 927 InfraErrorIdentifier.OPTION_CONFIGURATION_ERROR); 928 } 929 930 boolean needsReboot = false; 931 // Set persistent props and build a map of all the nonpersistent ones 932 Map<String, String> nonpersistentProps = new HashMap<String, String>(); 933 for (Map.Entry<String, String> prop : mSetProps.entrySet()) { 934 // MEMTAG_BOOTCTL is essentially a persist property. It triggers an action that 935 // stores the value in the misc partition, and gets applied and restored on 936 // reboot. 937 boolean isPersistProperty = 938 prop.getKey().startsWith(PERSIST_PREFIX) 939 || prop.getKey().equals(MEMTAG_BOOTCTL); 940 941 if (isPersistProperty || mOptimizeNonPersistentSetup) { 942 device.setProperty(prop.getKey(), prop.getValue()); 943 } 944 945 if (!isPersistProperty) { 946 nonpersistentProps.put(prop.getKey(), prop.getValue()); 947 } 948 949 if (PROPERTIES_NEEDING_REBOOT.contains(prop.getKey())) { 950 needsReboot = true; 951 } 952 } 953 954 // If the reboot optimization is enabled, only set nonpersistent props if 955 // there are changed values from what the device is running. 956 boolean shouldSetProps = true; 957 if (!mOptimizeNonPersistentSetup 958 && mOptimizedPropertySetting 959 && !nonpersistentProps.isEmpty()) { 960 boolean allPropsAlreadySet = true; 961 for (Map.Entry<String, String> prop : nonpersistentProps.entrySet()) { 962 if (!prop.getValue().equals(device.getProperty(prop.getKey()))) { 963 allPropsAlreadySet = false; 964 break; 965 } 966 } 967 if (allPropsAlreadySet) { 968 shouldSetProps = false; 969 CLog.i( 970 "All properties appear to already be set to desired values, skipping" 971 + " set stage"); 972 } 973 } 974 975 // Set the nonpersistent properties if needed. 976 if (!nonpersistentProps.isEmpty() && shouldSetProps) { 977 StringBuilder sb = new StringBuilder(); 978 for (Map.Entry<String, String> prop : nonpersistentProps.entrySet()) { 979 sb.append(String.format("%s=%s\n", prop.getKey(), prop.getValue())); 980 } 981 982 if (mRestoreProperties) { 983 mPreviousProperties = device.pullFile("/data/local.prop"); 984 } 985 CLog.d("Pushing the following properties to /data/local.prop:\n%s", sb.toString()); 986 boolean result = device.pushString(sb.toString(), "/data/local.prop"); 987 if (!result) { 988 throw new TargetSetupError( 989 String.format( 990 "Failed to push /data/local.prop to %s", device.getSerialNumber()), 991 device.getDeviceDescriptor(), 992 DeviceErrorIdentifier.FAIL_PUSH_FILE); 993 } 994 // Set reasonable permissions for /data/local.prop 995 device.executeShellCommand("chmod 644 /data/local.prop"); 996 997 if (mDisableRamdump) { 998 device.rebootIntoBootloader(); 999 CLog.i("Disabling ramdump."); 1000 CommandResult resultRampdump = 1001 device.executeFastbootCommand("oem", "ramdump", "disable"); 1002 if (!CommandStatus.SUCCESS.equals(resultRampdump.getStatus())) { 1003 CLog.w( 1004 "Failed to run ramdump disable: status: %s\nstdout: %s\nstderr: %s", 1005 resultRampdump.getStatus(), 1006 resultRampdump.getStdout(), 1007 resultRampdump.getStderr()); 1008 } 1009 } 1010 if (!mOptimizeNonPersistentSetup) { 1011 // non-persistent properties do not trigger a reboot in this 1012 // new setup, if not explicitly set. 1013 needsReboot = true; 1014 } 1015 } 1016 1017 if (needsReboot) { 1018 CLog.i("Rebooting %s due to system property change", device.getSerialNumber()); 1019 device.reboot(); 1020 } 1021 1022 // Log nonpersistent device properties (that change/lose values after reboot). 1023 String deviceType = device.getClass().getTypeName(); 1024 for (Map.Entry<String, String> prop : mSetProps.entrySet()) { 1025 String expected = prop.getValue(); 1026 String actual = device.getProperty(prop.getKey()); 1027 if ((expected != null && !expected.equals(actual)) 1028 || (expected == null && actual != null)) { 1029 String entry = 1030 String.format("%s-%s(%s:%s)", deviceType, prop.getKey(), expected, actual); 1031 InvocationMetricLogger.addInvocationMetrics( 1032 InvocationMetricKey.NONPERSISTENT_DEVICE_PROPERTIES, entry); 1033 } else { 1034 String entry = String.format("%s-%s(%s)", deviceType, prop.getKey(), actual); 1035 InvocationMetricLogger.addInvocationMetrics( 1036 InvocationMetricKey.PERSISTENT_DEVICE_PROPERTIES, entry); 1037 } 1038 } 1039 } 1040 1041 /** 1042 * Handles screen always on settings. 1043 * <p> 1044 * This is done in a dedicated function because special handling is required in case of setting 1045 * screen to always on. 1046 * @throws DeviceNotAvailableException 1047 */ handleScreenAlwaysOnSetting(ITestDevice device)1048 private void handleScreenAlwaysOnSetting(ITestDevice device) 1049 throws DeviceNotAvailableException { 1050 String cmd = "svc power stayon %s"; 1051 switch (mScreenAlwaysOn) { 1052 case ON: 1053 try (CloseableTraceScope ignored = 1054 new CloseableTraceScope(InvocationMetricKey.screen_on_setup.toString())) { 1055 CLog.d("Setting screen always on to true"); 1056 String cmdStayOn = String.format(cmd, "true"); 1057 CommandResult stayOn = device.executeShellV2Command(cmdStayOn); 1058 CLog.d("%s output: %s", cmdStayOn, stayOn); 1059 if (mDismissViaWm) { 1060 CommandResult res = 1061 device.executeShellV2Command( 1062 "wm dismiss-keyguard", 30000L, TimeUnit.MILLISECONDS, 0); 1063 CLog.d("Output of dismiss-keyguard: %s", res); 1064 } else { 1065 // send MENU press in case keyguard needs to be dismissed again 1066 CommandResult inputKey = device.executeShellV2Command("input keyevent 82"); 1067 CLog.d("Output of input keyevent 82: %s", inputKey); 1068 } 1069 // send HOME press in case keyguard was already dismissed, so we bring device 1070 // back 1071 // to home screen 1072 // No need for this on Wear OS, since that causes the launcher to show 1073 // instead of the home screen 1074 if ((device instanceof TestDevice) 1075 && !device.hasFeature("android.hardware.type.watch")) { 1076 CommandResult inputKey = device.executeShellV2Command("input keyevent 3"); 1077 CLog.d("Output of input keyevent 3: %s", inputKey); 1078 } 1079 break; 1080 } 1081 case OFF: 1082 CLog.d("Setting screen always on to false"); 1083 device.executeShellCommand(String.format(cmd, "false")); 1084 break; 1085 case IGNORE: 1086 break; 1087 } 1088 } 1089 1090 /** 1091 * Change the settings on the device. 1092 * <p> 1093 * Exposed so children classes may override. 1094 * </p> 1095 * 1096 * @param device The {@link ITestDevice} 1097 * @throws DeviceNotAvailableException if the device is not available 1098 * @throws TargetSetupError if there was a failure setting the settings 1099 */ changeSettings(ITestDevice device)1100 public void changeSettings(ITestDevice device) throws DeviceNotAvailableException, 1101 TargetSetupError { 1102 if (mForceSkipSettings) { 1103 CLog.d("Skipping settings due to force-skip-setttings"); 1104 return; 1105 } 1106 1107 if (mSystemSettings.isEmpty() && mSecureSettings.isEmpty() && mGlobalSettings.isEmpty() && 1108 BinaryState.IGNORE.equals(mAirplaneMode)) { 1109 CLog.d("No settings to change"); 1110 return; 1111 } 1112 1113 if (device.getApiLevel() < 22) { 1114 throw new TargetSetupError(String.format("Changing setting not supported on %s, " + 1115 "must be API 22+", device.getSerialNumber()), device.getDeviceDescriptor()); 1116 } 1117 1118 // Special case airplane mode since it needs to be set before other connectivity settings 1119 // For example, it is possible to enable airplane mode and then turn wifi on 1120 String command = "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state %s"; 1121 switch (mAirplaneMode) { 1122 case ON: 1123 CLog.d("Changing global setting airplane_mode_on to 1"); 1124 device.setSetting("global", "airplane_mode_on", "1"); 1125 if (!mForceSkipRunCommands) { 1126 device.executeShellCommand(String.format(command, "true")); 1127 } 1128 break; 1129 case OFF: 1130 CLog.d("Changing global setting airplane_mode_on to 0"); 1131 device.setSetting("global", "airplane_mode_on", "0"); 1132 if (!mForceSkipRunCommands) { 1133 device.executeShellCommand(String.format(command, "false")); 1134 } 1135 break; 1136 case IGNORE: 1137 // No-op 1138 break; 1139 } 1140 1141 for (String key : mSystemSettings.keySet()) { 1142 for (String value : mSystemSettings.get(key)) { 1143 if (mRestoreSettings) { 1144 String previousSetting = device.getSetting("system", key); 1145 mPreviousSystemSettings.put(key, previousSetting); 1146 } 1147 CLog.d("Changing system setting %s to %s", key, value); 1148 device.setSetting("system", key, value); 1149 } 1150 } 1151 for (String key : mSecureSettings.keySet()) { 1152 for (String value : mSecureSettings.get(key)) { 1153 if (mRestoreSettings) { 1154 String previousSetting = device.getSetting("secure", key); 1155 mPreviousSecureSettings.put(key, previousSetting); 1156 } 1157 CLog.d("Changing secure setting %s to %s", key, value); 1158 device.setSetting("secure", key, value); 1159 } 1160 } 1161 1162 for (String key : mGlobalSettings.keySet()) { 1163 for (String value : mGlobalSettings.get(key)) { 1164 if (mRestoreSettings) { 1165 String previousSetting = device.getSetting("global", key); 1166 mPreviousGlobalSettings.put(key, previousSetting); 1167 } 1168 CLog.d("Changing global setting %s to %s", key, value); 1169 device.setSetting("global", key, value); 1170 } 1171 } 1172 } 1173 1174 /** 1175 * Execute additional commands on the device. 1176 * 1177 * @param device The {@link ITestDevice} 1178 * @param commands The list of commands to run 1179 * @throws DeviceNotAvailableException if the device is not available 1180 * @throws TargetSetupError if there was a failure setting the settings 1181 */ runCommands(ITestDevice device, List<String> commands)1182 private void runCommands(ITestDevice device, List<String> commands) 1183 throws DeviceNotAvailableException, TargetSetupError { 1184 if (mForceSkipRunCommands) { 1185 CLog.d("Skipping run commands due to force-skip-run-commands"); 1186 return; 1187 } 1188 1189 for (String command : commands) { 1190 device.executeShellCommand(command); 1191 } 1192 } 1193 1194 /** 1195 * Connects device to Wifi if SSID is specified. 1196 * 1197 * @param device The {@link ITestDevice} 1198 * @throws DeviceNotAvailableException if the device is not available 1199 * @throws TargetSetupError if there was a failure setting the settings 1200 */ connectWifi(ITestDevice device)1201 private void connectWifi(ITestDevice device) throws DeviceNotAvailableException, 1202 TargetSetupError { 1203 if (mForceSkipRunCommands) { 1204 CLog.d("Skipping connect wifi due to force-skip-run-commands"); 1205 return; 1206 } 1207 if ((mWifiSsid == null || mWifiSsid.isEmpty()) && mWifiSsidToPsk.isEmpty()) { 1208 return; 1209 } 1210 if (mSkipWifi) { 1211 CLog.d("Skipping wifi connection due to skip-wifi-connection"); 1212 return; 1213 } 1214 1215 if (mWifiSsid != null) { 1216 mWifiSsidToPsk.put(mWifiSsid, mWifiPsk); 1217 } 1218 if (device.connectToWifiNetwork(mWifiSsidToPsk)) { 1219 return; 1220 } 1221 1222 if (mWifiSsid != null || !mWifiSsidToPsk.isEmpty()) { 1223 String network = (mWifiSsid == null) ? mWifiSsidToPsk.toString() : mWifiSsid; 1224 InfraErrorIdentifier errorIdentifier = InfraErrorIdentifier.WIFI_FAILED_CONNECT; 1225 if (device instanceof RemoteAndroidVirtualDevice 1226 || device instanceof NestedRemoteDevice 1227 || device instanceof LocalAndroidVirtualDevice) { 1228 // Error identifier for virtual devices. 1229 errorIdentifier = InfraErrorIdentifier.VIRTUAL_WIFI_FAILED_CONNECT; 1230 } 1231 throw new TargetSetupError( 1232 String.format( 1233 "Failed to connect to wifi network %s on %s", 1234 network, device.getSerialNumber()), 1235 device.getDeviceDescriptor(), 1236 errorIdentifier); 1237 } 1238 } 1239 1240 /** 1241 * Syncs a set of test data files, specified via local-data-path, to devices external storage. 1242 * 1243 * @param device The {@link ITestDevice} 1244 * @throws DeviceNotAvailableException if the device is not available 1245 * @throws TargetSetupError if data fails to sync 1246 */ syncTestData(ITestDevice device)1247 private void syncTestData(ITestDevice device) throws DeviceNotAvailableException, 1248 TargetSetupError { 1249 if (mLocalDataFile == null) { 1250 return; 1251 } 1252 1253 if (!mLocalDataFile.exists() || !mLocalDataFile.isDirectory()) { 1254 throw new TargetSetupError(String.format( 1255 "local-data-path %s is not a directory", mLocalDataFile.getAbsolutePath()), 1256 device.getDeviceDescriptor()); 1257 } 1258 String fullRemotePath = device.getIDevice().getMountPoint(IDevice.MNT_EXTERNAL_STORAGE); 1259 if (fullRemotePath == null) { 1260 throw new TargetSetupError(String.format( 1261 "failed to get external storage path on device %s", device.getSerialNumber()), 1262 device.getDeviceDescriptor()); 1263 } 1264 if (mRemoteDataPath != null) { 1265 fullRemotePath = String.format("%s/%s", fullRemotePath, mRemoteDataPath); 1266 } 1267 boolean result = device.syncFiles(mLocalDataFile, fullRemotePath); 1268 if (!result) { 1269 // TODO: get exact error code and respond accordingly 1270 throw new TargetSetupError(String.format( 1271 "failed to sync test data from local-data-path %s to %s on device %s", 1272 mLocalDataFile.getAbsolutePath(), fullRemotePath, device.getSerialNumber()), 1273 device.getDeviceDescriptor()); 1274 } 1275 } 1276 1277 /** 1278 * Check that device external store has the required space 1279 * 1280 * @param device The {@link ITestDevice} 1281 * @throws DeviceNotAvailableException if the device is not available or if the device does not 1282 * have the required space 1283 */ checkExternalStoreSpace(ITestDevice device)1284 private void checkExternalStoreSpace(ITestDevice device) throws DeviceNotAvailableException { 1285 if (mMinExternalStorageKb <= 0) { 1286 return; 1287 } 1288 if (!(device instanceof TestDevice)) { 1289 // TODO: instead check that sdcard exists 1290 return; 1291 } 1292 // Wait for device available to ensure the mounting of sdcard 1293 device.waitForDeviceAvailable(); 1294 long freeSpace = device.getExternalStoreFreeSpace(); 1295 if (freeSpace < mMinExternalStorageKb) { 1296 throw new DeviceNotAvailableException( 1297 String.format( 1298 "External store free space %dK is less than required %dK for device %s", 1299 freeSpace, mMinExternalStorageKb, device.getSerialNumber()), 1300 device.getSerialNumber(), 1301 DeviceErrorIdentifier.DEVICE_UNEXPECTED_RESPONSE); 1302 } 1303 } 1304 dismissSetupWizard(ITestDevice device)1305 private void dismissSetupWizard(ITestDevice device) throws DeviceNotAvailableException { 1306 for (int i = 0; i < mDismissSetupWizardRetry; i++) { 1307 CommandResult cmd1 = 1308 device.executeShellV2Command( 1309 "am start -a com.android.setupwizard.FOUR_CORNER_EXIT"); // Android 1310 // UDC+ 1311 CommandResult cmd2 = 1312 device.executeShellV2Command( 1313 "am start -a com.android.setupwizard.EXIT"); // Android L - T 1314 // if either of the command is successful, count it as success. Otherwise, retry. 1315 if (CommandStatus.SUCCESS.equals(cmd1.getStatus()) 1316 || CommandStatus.SUCCESS.equals(cmd2.getStatus())) { 1317 break; 1318 } 1319 } 1320 // verify setup wizard is dismissed 1321 CLog.d("Waiting %d ms for setup wizard to be dismissed.", mDismissSetupWizardTimeout); 1322 boolean dismissed = false; 1323 long startTime = System.currentTimeMillis(); 1324 while (System.currentTimeMillis() - startTime < mDismissSetupWizardTimeout) { 1325 CommandResult cmdOut = 1326 device.executeShellV2Command("dumpsys window displays | grep mCurrentFocus"); 1327 if (CommandStatus.SUCCESS.equals(cmdOut.getStatus()) 1328 && !cmdOut.getStdout().contains("setupwizard")) { 1329 CLog.d("Setup wizard is dismissed."); 1330 dismissed = true; 1331 break; 1332 } else { 1333 RunUtil.getDefault().sleep(2 * 1000); 1334 } 1335 } 1336 if (!dismissed) { 1337 CLog.w( 1338 "Setup wizard was not dismissed within the timeout limit: %d ms.", 1339 mDismissSetupWizardTimeout); 1340 } 1341 } 1342 1343 /** 1344 * Helper method to add an ON/OFF setting to a setting map. 1345 * 1346 * @param state The {@link BinaryState} 1347 * @param settingsMap The {@link MultiMap} used to store the settings. 1348 * @param setting The setting key 1349 * @param onValue The value if ON 1350 * @param offValue The value if OFF 1351 */ setSettingForBinaryState(BinaryState state, MultiMap<String, String> settingsMap, String setting, String onValue, String offValue)1352 public static void setSettingForBinaryState(BinaryState state, 1353 MultiMap<String, String> settingsMap, String setting, String onValue, String offValue) { 1354 switch (state) { 1355 case ON: 1356 settingsMap.put(setting, onValue); 1357 break; 1358 case OFF: 1359 settingsMap.put(setting, offValue); 1360 break; 1361 case IGNORE: 1362 // Do nothing 1363 break; 1364 } 1365 } 1366 1367 /** 1368 * Helper method to add an ON/OFF run command to be executed on the device. 1369 * 1370 * @param state The {@link BinaryState} 1371 * @param commands The list of commands to add the on or off command to. 1372 * @param onCommand The command to run if ON. Ignored if the command is {@code null} 1373 * @param offCommand The command to run if OFF. Ignored if the command is {@code null} 1374 */ setCommandForBinaryState(BinaryState state, List<String> commands, String onCommand, String offCommand)1375 public static void setCommandForBinaryState(BinaryState state, List<String> commands, 1376 String onCommand, String offCommand) { 1377 switch (state) { 1378 case ON: 1379 if (onCommand != null) { 1380 commands.add(onCommand); 1381 } 1382 break; 1383 case OFF: 1384 if (offCommand != null) { 1385 commands.add(offCommand); 1386 } 1387 break; 1388 case IGNORE: 1389 // Do nothing 1390 break; 1391 } 1392 } 1393 1394 /** Exposed for unit testing */ setForceSkipSystemProps(boolean force)1395 protected void setForceSkipSystemProps(boolean force) { 1396 mForceSkipSystemProps = force; 1397 } 1398 setForceRootSetup(boolean force)1399 protected void setForceRootSetup(boolean force) { 1400 mForceRoot = force; 1401 } 1402 isForceSkipSystemProps()1403 public boolean isForceSkipSystemProps() { 1404 return mForceSkipSystemProps; 1405 } 1406 1407 /** 1408 * Exposed for unit testing 1409 */ setAirplaneMode(BinaryState airplaneMode)1410 protected void setAirplaneMode(BinaryState airplaneMode) { 1411 mAirplaneMode = airplaneMode; 1412 } 1413 1414 /* Exposed for unit testing */ 1415 @VisibleForTesting setData(BinaryState data)1416 protected void setData(BinaryState data) { 1417 mData = data; 1418 } 1419 1420 /* Exposed for unit testing */ 1421 @VisibleForTesting setCell(BinaryState cell)1422 protected void setCell(BinaryState cell) { 1423 mCell = cell; 1424 } 1425 1426 /* Exposed for unit testing */ 1427 @VisibleForTesting setCellAutoSetting(BinaryState cellAutoSetting)1428 protected void setCellAutoSetting(BinaryState cellAutoSetting) { 1429 mCellAutoSetting = cellAutoSetting; 1430 } 1431 1432 /** 1433 * Exposed for unit testing 1434 */ setWifi(BinaryState wifi)1435 protected void setWifi(BinaryState wifi) { 1436 mWifi = wifi; 1437 } 1438 1439 /** 1440 * Exposed for unit testing 1441 */ setWifiNetwork(String wifiNetwork)1442 protected void setWifiNetwork(String wifiNetwork) { 1443 mWifiSsid = wifiNetwork; 1444 } 1445 1446 /* Exposed for unit testing */ 1447 @VisibleForTesting setWifiPsk(String wifiPsk)1448 protected void setWifiPsk(String wifiPsk) { 1449 mWifiPsk = wifiPsk; 1450 } 1451 1452 /* Exposed for unit testing */ 1453 @VisibleForTesting setWifiSsidToPsk(Map<String, String> wifiSssidToPsk)1454 protected void setWifiSsidToPsk(Map<String, String> wifiSssidToPsk) { 1455 mWifiSsidToPsk = wifiSssidToPsk; 1456 } 1457 1458 /** 1459 * Exposed for unit testing 1460 */ setWifiWatchdog(BinaryState wifiWatchdog)1461 protected void setWifiWatchdog(BinaryState wifiWatchdog) { 1462 mWifiWatchdog = wifiWatchdog; 1463 } 1464 1465 /* Exposed for unit testing */ 1466 @VisibleForTesting setDisableCwWifiMediator(BinaryState disableCwWifiMediator)1467 protected void setDisableCwWifiMediator(BinaryState disableCwWifiMediator) { 1468 mDisableCwWifiMediator = disableCwWifiMediator; 1469 } 1470 1471 /** 1472 * Exposed for unit testing 1473 */ setWifiScanAlwaysEnabled(BinaryState wifiScanAlwaysEnabled)1474 protected void setWifiScanAlwaysEnabled(BinaryState wifiScanAlwaysEnabled) { 1475 mWifiScanAlwaysEnabled = wifiScanAlwaysEnabled; 1476 } 1477 1478 /** 1479 * Exposed for unit testing 1480 */ setEthernet(BinaryState ethernet)1481 protected void setEthernet(BinaryState ethernet) { 1482 mEthernet = ethernet; 1483 } 1484 1485 /** 1486 * Exposed for unit testing 1487 */ setBluetooth(BinaryState bluetooth)1488 protected void setBluetooth(BinaryState bluetooth) { 1489 mBluetooth = bluetooth; 1490 } 1491 1492 /** 1493 * Exposed for unit testing 1494 */ setNfc(BinaryState nfc)1495 protected void setNfc(BinaryState nfc) { 1496 mNfc = nfc; 1497 } 1498 1499 /** 1500 * Exposed for unit testing 1501 */ setScreenAdaptiveBrightness(BinaryState screenAdaptiveBrightness)1502 protected void setScreenAdaptiveBrightness(BinaryState screenAdaptiveBrightness) { 1503 mScreenAdaptiveBrightness = screenAdaptiveBrightness; 1504 } 1505 1506 /** 1507 * Exposed for unit testing 1508 */ setScreenBrightness(Integer screenBrightness)1509 protected void setScreenBrightness(Integer screenBrightness) { 1510 mScreenBrightness = screenBrightness; 1511 } 1512 1513 /** 1514 * Exposed for unit testing 1515 */ setScreenAlwaysOn(BinaryState screenAlwaysOn)1516 protected void setScreenAlwaysOn(BinaryState screenAlwaysOn) { 1517 mScreenAlwaysOn = screenAlwaysOn; 1518 } 1519 1520 /** 1521 * Exposed for unit testing 1522 */ setScreenTimeoutSecs(Long screenTimeoutSecs)1523 protected void setScreenTimeoutSecs(Long screenTimeoutSecs) { 1524 mScreenTimeoutSecs = screenTimeoutSecs; 1525 } 1526 1527 /** 1528 * Exposed for unit testing 1529 */ setScreenAmbientMode(BinaryState screenAmbientMode)1530 protected void setScreenAmbientMode(BinaryState screenAmbientMode) { 1531 mScreenAmbientMode = screenAmbientMode; 1532 } 1533 1534 /** 1535 * Exposed for unit testing 1536 */ setWakeGesture(BinaryState wakeGesture)1537 protected void setWakeGesture(BinaryState wakeGesture) { 1538 mWakeGesture = wakeGesture; 1539 } 1540 1541 /** 1542 * Exposed for unit testing 1543 */ setScreenSaver(BinaryState screenSaver)1544 protected void setScreenSaver(BinaryState screenSaver) { 1545 mScreenSaver = screenSaver; 1546 } 1547 1548 /** 1549 * Exposed for unit testing 1550 */ setNotificationLed(BinaryState notificationLed)1551 protected void setNotificationLed(BinaryState notificationLed) { 1552 mNotificationLed = notificationLed; 1553 } 1554 1555 /** 1556 * Exposed for unit testing 1557 */ setInstallNonMarketApps(BinaryState installNonMarketApps)1558 protected void setInstallNonMarketApps(BinaryState installNonMarketApps) { 1559 mInstallNonMarketApps = installNonMarketApps; 1560 } 1561 1562 /** 1563 * Exposed for unit testing 1564 */ setTriggerMediaMounted(boolean triggerMediaMounted)1565 protected void setTriggerMediaMounted(boolean triggerMediaMounted) { 1566 mTriggerMediaMounted = triggerMediaMounted; 1567 } 1568 1569 /** 1570 * Exposed for unit testing 1571 */ setLocationGps(BinaryState locationGps)1572 protected void setLocationGps(BinaryState locationGps) { 1573 mLocationGps = locationGps; 1574 } 1575 1576 /** 1577 * Exposed for unit testing 1578 */ setLocationNetwork(BinaryState locationNetwork)1579 protected void setLocationNetwork(BinaryState locationNetwork) { 1580 mLocationNetwork = locationNetwork; 1581 } 1582 1583 /** 1584 * Exposed for unit testing 1585 */ setAutoRotate(BinaryState autoRotate)1586 protected void setAutoRotate(BinaryState autoRotate) { 1587 mAutoRotate = autoRotate; 1588 } 1589 1590 /** 1591 * Exposed for unit testing 1592 */ setBatterySaver(BinaryState batterySaver)1593 protected void setBatterySaver(BinaryState batterySaver) { 1594 mBatterySaver = batterySaver; 1595 } 1596 1597 /** 1598 * Exposed for unit testing 1599 */ setBatterySaverTrigger(Integer batterySaverTrigger)1600 protected void setBatterySaverTrigger(Integer batterySaverTrigger) { 1601 mBatterySaverTrigger = batterySaverTrigger; 1602 } 1603 1604 /** 1605 * Exposed for unit testing 1606 */ setEnableFullBatteryStatsHistory(boolean enableFullBatteryStatsHistory)1607 protected void setEnableFullBatteryStatsHistory(boolean enableFullBatteryStatsHistory) { 1608 mEnableFullBatteryStatsHistory = enableFullBatteryStatsHistory; 1609 } 1610 1611 /** 1612 * Exposed for unit testing 1613 */ setDisableDoze(boolean disableDoze)1614 protected void setDisableDoze(boolean disableDoze) { 1615 mDisableDoze = disableDoze; 1616 } 1617 1618 /** 1619 * Exposed for unit testing 1620 */ setAutoUpdateTime(BinaryState autoUpdateTime)1621 protected void setAutoUpdateTime(BinaryState autoUpdateTime) { 1622 mAutoUpdateTime = autoUpdateTime; 1623 } 1624 1625 /** 1626 * Exposed for unit testing 1627 */ setAutoUpdateTimezone(BinaryState autoUpdateTimezone)1628 protected void setAutoUpdateTimezone(BinaryState autoUpdateTimezone) { 1629 mAutoUpdateTimezone = autoUpdateTimezone; 1630 } 1631 1632 /** 1633 * Exposed for unit testing 1634 */ setTimezone(String timezone)1635 protected void setTimezone(String timezone) { 1636 mTimezone = timezone; 1637 } 1638 1639 /** 1640 * Exposed for unit testing 1641 */ setDisableDialing(boolean disableDialing)1642 protected void setDisableDialing(boolean disableDialing) { 1643 mDisableDialing = disableDialing; 1644 } 1645 1646 /** 1647 * Exposed for unit testing 1648 */ setDefaultSimData(Integer defaultSimData)1649 protected void setDefaultSimData(Integer defaultSimData) { 1650 mDefaultSimData = defaultSimData; 1651 } 1652 1653 /** 1654 * Exposed for unit testing 1655 */ setDefaultSimVoice(Integer defaultSimVoice)1656 protected void setDefaultSimVoice(Integer defaultSimVoice) { 1657 mDefaultSimVoice = defaultSimVoice; 1658 } 1659 1660 /** 1661 * Exposed for unit testing 1662 */ setDefaultSimSms(Integer defaultSimSms)1663 protected void setDefaultSimSms(Integer defaultSimSms) { 1664 mDefaultSimSms = defaultSimSms; 1665 } 1666 1667 /** 1668 * Exposed for unit testing 1669 */ setDisableAudio(boolean disable)1670 protected void setDisableAudio(boolean disable) { 1671 mDisableAudio = disable; 1672 } 1673 1674 /** 1675 * Exposed for unit testing 1676 */ setTestHarness(boolean setTestHarness)1677 protected void setTestHarness(boolean setTestHarness) { 1678 mSetTestHarness = setTestHarness; 1679 } 1680 1681 /** 1682 * Exposed for unit testing 1683 */ setDisableDalvikVerifier(boolean disableDalvikVerifier)1684 protected void setDisableDalvikVerifier(boolean disableDalvikVerifier) { 1685 mDisableDalvikVerifier = disableDalvikVerifier; 1686 } 1687 1688 /** 1689 * Exposed for unit testing 1690 */ setLocalDataPath(File path)1691 protected void setLocalDataPath(File path) { 1692 mLocalDataFile = path; 1693 } 1694 1695 /** 1696 * Exposed for unit testing 1697 */ setMinExternalStorageKb(long storageKb)1698 protected void setMinExternalStorageKb(long storageKb) { 1699 mMinExternalStorageKb = storageKb; 1700 } 1701 1702 /** 1703 * Exposed for unit testing 1704 */ setProperty(String key, String value)1705 protected void setProperty(String key, String value) { 1706 mSetProps.put(key, value); 1707 } 1708 1709 /** Exposed for unit testing */ setGlobalSetting(String key, String value)1710 public void setGlobalSetting(String key, String value) { 1711 mGlobalSettings.put(key, value); 1712 } 1713 1714 /** Exposed for unit testing */ setSecureSetting(String key, String value)1715 public void setSecureSetting(String key, String value) { 1716 mSecureSettings.put(key, value); 1717 } 1718 1719 /** Exposed for unit testing */ setSystemSetting(String key, String value)1720 public void setSystemSetting(String key, String value) { 1721 mSystemSettings.put(key, value); 1722 } 1723 1724 /** Exposed for unit testing */ setRestoreProperties(boolean restoreProperties)1725 protected void setRestoreProperties(boolean restoreProperties) { 1726 mRestoreProperties = restoreProperties; 1727 } 1728 1729 /** Exposed for unit testing */ setRestoreSettings(boolean restoreSettings)1730 protected void setRestoreSettings(boolean restoreSettings) { 1731 mRestoreSettings = restoreSettings; 1732 } 1733 1734 /** 1735 * Exposed for unit testing 1736 * @deprecated use {@link #setMinExternalStorageKb(long)} instead. 1737 */ 1738 @Deprecated setDeprecatedMinExternalStoreSpace(long storeSpace)1739 protected void setDeprecatedMinExternalStoreSpace(long storeSpace) { 1740 mDeprecatedMinExternalStoreSpace = storeSpace; 1741 } 1742 1743 /** 1744 * Exposed for unit testing 1745 * @deprecated use {@link #setDisableAudio(boolean)} instead. 1746 */ 1747 @Deprecated setDeprecatedAudioSilent(boolean silent)1748 protected void setDeprecatedAudioSilent(boolean silent) { 1749 mDeprecatedSetAudioSilent = silent; 1750 } 1751 1752 /** 1753 * Exposed for unit testing 1754 * @deprecated use {@link #setProperty(String, String)} instead. 1755 */ 1756 @Deprecated setDeprecatedSetProp(String prop)1757 protected void setDeprecatedSetProp(String prop) { 1758 mDeprecatedSetProps.add(prop); 1759 } 1760 1761 @Override getDependencies()1762 public Set<ExternalDependency> getDependencies() { 1763 Set<ExternalDependency> externalDependencies = new LinkedHashSet<>(); 1764 // check if we need mobile data 1765 if (BinaryState.ON.equals(mData)) { 1766 externalDependencies.add(new TelephonyDependency()); 1767 } 1768 // check if we need wifi 1769 if (!mSkipWifi && !(Strings.isNullOrEmpty(mWifiSsid) && mWifiSsidToPsk.isEmpty())) { 1770 externalDependencies.add(new NetworkDependency()); 1771 } 1772 // check if we need ethernet 1773 if (BinaryState.ON.equals(mEthernet)) { 1774 externalDependencies.add(new EthernetDependency()); 1775 } 1776 // check if we need bluetooth 1777 if (BinaryState.ON.equals(mBluetooth)) { 1778 externalDependencies.add(new BluetoothDependency()); 1779 } 1780 // check if we need location-network 1781 if (BinaryState.ON.equals(mLocationNetwork)) { 1782 externalDependencies.add(new NetworkDependency()); 1783 } 1784 return externalDependencies; 1785 } 1786 } 1787