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.build.IBuildInfo; 21 import com.android.tradefed.config.Option; 22 import com.android.tradefed.config.OptionClass; 23 import com.android.tradefed.device.DeviceNotAvailableException; 24 import com.android.tradefed.device.ITestDevice; 25 import com.android.tradefed.device.StubDevice; 26 import com.android.tradefed.log.LogUtil.CLog; 27 import com.android.tradefed.util.BinaryState; 28 import com.android.tradefed.util.MultiMap; 29 30 import java.io.File; 31 import java.util.ArrayList; 32 import java.util.Collection; 33 import java.util.HashMap; 34 import java.util.List; 35 import java.util.Map; 36 37 /** 38 * A {@link ITargetPreparer} that configures a device for testing based on provided {@link Option}s. 39 * <p> 40 * Requires a device where 'adb root' is possible, typically a userdebug build type. 41 * </p><p> 42 * Should be performed <strong>after</strong> a new build is flashed. 43 * </p> 44 */ 45 @OptionClass(alias = "device-setup") 46 public class DeviceSetup implements ITargetPreparer, ITargetCleaner { 47 48 // Networking 49 @Option(name = "airplane-mode", 50 description = "Turn airplane mode on or off") 51 protected BinaryState mAirplaneMode = BinaryState.IGNORE; 52 // ON: settings put global airplane_mode_on 1 53 // am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true 54 // OFF: settings put global airplane_mode_on 0 55 // am broadcast -a android.intent.action.AIRPLANE_MODE --ez state false 56 57 @Option(name = "wifi", 58 description = "Turn wifi on or off") 59 protected BinaryState mWifi = BinaryState.IGNORE; 60 // ON: settings put global wifi_on 1 61 // svc wifi enable 62 // OFF: settings put global wifi_off 0 63 // svc wifi disable 64 65 @Option(name = "wifi-network", 66 description = "The SSID of the network to connect to. Will only attempt to " + 67 "connect to a network if set") 68 protected String mWifiSsid = null; 69 70 @Option(name = "wifi-psk", 71 description = "The passphrase used to connect to a secured network") 72 protected String mWifiPsk = null; 73 74 @Option(name = "wifi-watchdog", 75 description = "Turn wifi watchdog on or off") 76 protected BinaryState mWifiWatchdog = BinaryState.IGNORE; 77 // ON: settings put global wifi_watchdog 1 78 // OFF: settings put global wifi_watchdog 0 79 80 @Option(name = "wifi-scan-always-enabled", 81 description = "Turn wifi scan always enabled on or off") 82 protected BinaryState mWifiScanAlwaysEnabled = BinaryState.IGNORE; 83 // ON: settings put global wifi_scan_always_enabled 1 84 // OFF: settings put global wifi_scan_always_enabled 0 85 86 @Option(name = "ethernet", 87 description = "Turn ethernet on or off") 88 protected BinaryState mEthernet = BinaryState.IGNORE; 89 // ON: ifconfig eth0 up 90 // OFF: ifconfig eth0 down 91 92 @Option(name = "bluetooth", 93 description = "Turn bluetooth on or off") 94 protected BinaryState mBluetooth = BinaryState.IGNORE; 95 // ON: service call bluetooth_manager 6 96 // OFF: service call bluetooth_manager 8 97 98 @Option(name = "nfc", 99 description = "Turn nfc on or off") 100 protected BinaryState mNfc = BinaryState.IGNORE; 101 // ON: svc nfc enable 102 // OFF: svc nfc disable 103 104 // Screen 105 @Option(name = "screen-adaptive-brightness", 106 description = "Turn screen adaptive brightness on or off") 107 protected BinaryState mScreenAdaptiveBrightness = BinaryState.IGNORE; 108 // ON: settings put system screen_brightness_mode 1 109 // OFF: settings put system screen_brightness_mode 0 110 111 @Option(name = "screen-brightness", 112 description = "Set the screen brightness. This is uncalibrated from product to product") 113 protected Integer mScreenBrightness = null; 114 // settings put system screen_brightness $N 115 116 @Option(name = "screen-always-on", 117 description = "Turn 'screen always on' on or off. If ON, then screen-timeout-secs " + 118 "must be unset. Will only work when the device is plugged in") 119 protected BinaryState mScreenAlwaysOn = BinaryState.ON; 120 // ON: svc power stayon true 121 // OFF: svc power stayon false 122 123 @Option(name = "screen-timeout-secs", 124 description = "Set the screen timeout in seconds. If set, then screen-always-on must " + 125 "be OFF or DEFAULT") 126 protected Long mScreenTimeoutSecs = null; 127 // settings put system screen_off_timeout $(N * 1000) 128 129 @Option(name = "screen-ambient-mode", 130 description = "Turn screen ambient mode on or off") 131 protected BinaryState mScreenAmbientMode = BinaryState.IGNORE; 132 // ON: settings put secure doze_enabled 1 133 // OFF: settings put secure doze_enabled 0 134 135 @Option(name = "wake-gesture", 136 description = "Turn wake gesture on or off") 137 protected BinaryState mWakeGesture = BinaryState.IGNORE; 138 // ON: settings put secure wake_gesture_enabled 1 139 // OFF: settings put secure wake_gesture_enabled 0 140 141 @Option(name = "screen-saver", 142 description = "Turn screen saver on or off") 143 protected BinaryState mScreenSaver = BinaryState.IGNORE; 144 // ON: settings put secure screensaver_enabled 1 145 // OFF: settings put secure screensaver_enabled 0 146 147 @Option(name = "notification-led", 148 description = "Turn the notification led on or off") 149 protected BinaryState mNotificationLed = BinaryState.IGNORE; 150 // ON: settings put system notification_light_pulse 1 151 // OFF: settings put system notification_light_pulse 0 152 153 @Option(name = "install-non-market-apps", 154 description = "Allow or prevent non-market app to initiate an apk install request") 155 protected BinaryState mInstallNonMarketApps = BinaryState.IGNORE; 156 // ON: settings put secure install_non_market_apps 1 157 // OFF: settings put secure install_non_market_apps 0 158 159 // Media 160 @Option(name = "trigger-media-mounted", 161 description = "Trigger a MEDIA_MOUNTED broadcast") 162 protected boolean mTriggerMediaMounted = false; 163 // am broadcast -a android.intent.action.MEDIA_MOUNTED -d file://${EXTERNAL_STORAGE} 164 // --receiver-include-background 165 166 // Location 167 @Option(name = "location-gps", description = "Turn the GPS location on or off") 168 protected BinaryState mLocationGps = BinaryState.IGNORE; 169 // ON: settings put secure location_providers_allowed +gps 170 // OFF: settings put secure location_providers_allowed -gps 171 172 @Option(name = "location-network", 173 description = "Turn the network location on or off") 174 protected BinaryState mLocationNetwork = BinaryState.IGNORE; 175 // ON: settings put secure location_providers_allowed +network 176 // OFF: settings put secure location_providers_allowed -network 177 178 // Sensor 179 @Option(name = "auto-rotate", 180 description = "Turn auto rotate on or off") 181 protected BinaryState mAutoRotate = BinaryState.IGNORE; 182 // ON: settings put system accelerometer_rotation 1 183 // OFF: settings put system accelerometer_rotation 0 184 185 // Power 186 @Option(name = "battery-saver-mode", 187 description = "Turn battery saver mode manually on or off. If OFF but battery is " + 188 "less battery-saver-trigger, the device will still go into battery saver mode") 189 protected BinaryState mBatterySaver = BinaryState.IGNORE; 190 // ON: dumpsys battery set usb 0 191 // settings put global low_power 1 192 // OFF: settings put global low_power 0 193 194 @Option(name = "battery-saver-trigger", 195 description = "Set the battery saver trigger level. Should be [1-99] to enable, or " + 196 "0 to disable automatic battery saver mode") 197 protected Integer mBatterySaverTrigger = null; 198 // settings put global low_power_trigger_level $N 199 200 @Option(name = "enable-full-battery-stats-history", 201 description = "Enable full history for batterystats. This option is only " + 202 "applicable for L+") 203 protected boolean mEnableFullBatteryStatsHistory = false; 204 // dumpsys batterystats --enable full-history 205 206 @Option(name = "disable-doze", 207 description = "Disable device from going into doze mode. This option is only " + 208 "applicable for M+") 209 protected boolean mDisableDoze = false; 210 // dumpsys deviceidle disable 211 212 // Time 213 @Option(name = "auto-update-time", 214 description = "Turn auto update time on or off") 215 protected BinaryState mAutoUpdateTime = BinaryState.IGNORE; 216 // ON: settings put system auto_time 1 217 // OFF: settings put system auto_time 0 218 219 @Option(name = "auto-update-timezone", 220 description = "Turn auto update timezone on or off") 221 protected BinaryState mAutoUpdateTimezone = BinaryState.IGNORE; 222 // ON: settings put system auto_timezone 1 223 // OFF: settings put system auto_timezone 0 224 225 @Option(name = "set-timezone", 226 description = "Set timezone property by TZ name " + 227 "(http://en.wikipedia.org/wiki/List_of_tz_database_time_zones)") 228 protected String mTimezone = null; 229 230 // Calling 231 @Option(name = "disable-dialing", 232 description = "Disable dialing") 233 protected boolean mDisableDialing = true; 234 // setprop ro.telephony.disable-call true" 235 236 @Option(name = "default-sim-data", 237 description = "Set the default sim card slot for data. Leave unset for single SIM " + 238 "devices") 239 protected Integer mDefaultSimData = null; 240 // settings put global multi_sim_data_call $N 241 242 @Option(name = "default-sim-voice", 243 description = "Set the default sim card slot for voice calls. Leave unset for single " + 244 "SIM devices") 245 protected Integer mDefaultSimVoice = null; 246 // settings put global multi_sim_voice_call $N 247 248 @Option(name = "default-sim-sms", 249 description = "Set the default sim card slot for SMS. Leave unset for single SIM " + 250 "devices") 251 protected Integer mDefaultSimSms = null; 252 // settings put global multi_sim_sms $N 253 254 // Audio 255 private static final boolean DEFAULT_DISABLE_AUDIO = true; 256 @Option(name = "disable-audio", 257 description = "Disable the audio") 258 protected boolean mDisableAudio = DEFAULT_DISABLE_AUDIO; 259 // setprop ro.audio.silent 1" 260 261 // Test harness 262 @Option(name = "disable", 263 description = "Disable the device setup") 264 protected boolean mDisable = false; 265 266 @Option(name = "force-skip-system-props", 267 description = "Force setup to not modify any device system properties. All other " + 268 "system property options will be ignored") 269 protected boolean mForceSkipSystemProps = false; 270 271 @Option(name = "force-skip-settings", 272 description = "Force setup to not modify any device settings. All other setting " + 273 "options will be ignored.") 274 protected boolean mForceSkipSettings = false; 275 276 @Option(name = "force-skip-run-commands", 277 description = "Force setup to not run any additional commands. All other commands " + 278 "will be ignored.") 279 protected boolean mForceSkipRunCommands = false; 280 281 @Option(name = "set-test-harness", 282 description = "Set the read-only test harness flag on boot") 283 protected boolean mSetTestHarness = true; 284 // setprop ro.monkey 1 285 // setprop ro.test_harness 1 286 287 @Option(name = "disable-dalvik-verifier", 288 description = "Disable the dalvik verifier on device. Allows package-private " + 289 "framework tests to run.") 290 protected boolean mDisableDalvikVerifier = false; 291 // setprop dalvik.vm.dexopt-flags v=n 292 293 @Option(name = "set-property", 294 description = "Set the specified property on boot. Option may be repeated but only " + 295 "the last value for a given key will be set.") 296 protected Map<String, String> mSetProps = new HashMap<>(); 297 298 @Option(name = "set-system-setting", 299 description = "Change a system (non-secure) setting. Option may be repeated and all " + 300 "key/value pairs will be set in order.") 301 // Use a Multimap since it is possible for a setting to have multiple values for the same key 302 protected MultiMap<String, String> mSystemSettings = new MultiMap<>(); 303 304 @Option(name = "set-secure-setting", 305 description = "Change a secure setting. Option may be repeated and all key/value " + 306 "pairs will be set in order.") 307 // Use a Multimap since it is possible for a setting to have multiple values for the same key 308 protected MultiMap<String, String> mSecureSettings = new MultiMap<>(); 309 310 @Option(name = "set-global-setting", 311 description = "Change a global setting. Option may be repeated and all key/value " + 312 "pairs will be set in order.") 313 // Use a Multimap since it is possible for a setting to have multiple values for the same key 314 protected MultiMap<String, String> mGlobalSettings = new MultiMap<>(); 315 316 protected List<String> mRunCommandBeforeSettings = new ArrayList<>(); 317 318 @Option(name = "run-command", 319 description = "Run an adb shell command. Option may be repeated") 320 protected List<String> mRunCommandAfterSettings = new ArrayList<>(); 321 322 @Option(name = "disconnect-wifi-after-test", 323 description = "Disconnect from wifi network after test completes.") 324 private boolean mDisconnectWifiAfterTest = true; 325 326 private static final long DEFAULT_MIN_EXTERNAL_STORAGE_KB = 500; 327 @Option(name = "min-external-storage-kb", 328 description="The minimum amount of free space in KB that must be present on device's " + 329 "external storage.") 330 protected long mMinExternalStorageKb = DEFAULT_MIN_EXTERNAL_STORAGE_KB; 331 332 @Option(name = "local-data-path", 333 description = "Optional local file path of test data to sync to device's external " + 334 "storage. Use --remote-data-path to set remote location.") 335 protected File mLocalDataFile = null; 336 337 @Option(name = "remote-data-path", 338 description = "Optional file path on device's external storage to sync test data. " + 339 "Must be used with --local-data-path.") 340 protected String mRemoteDataPath = null; 341 342 // Deprecated options follow 343 /** 344 * @deprecated use min-external-storage-kb instead. 345 */ 346 @Option(name = "min-external-store-space", 347 description = "deprecated, use option min-external-storage-kb. The minimum amount of " + 348 "free space in KB that must be present on device's external storage.") 349 @Deprecated 350 private long mDeprecatedMinExternalStoreSpace = DEFAULT_MIN_EXTERNAL_STORAGE_KB; 351 352 /** 353 * @deprecated use option disable-audio instead. 354 */ 355 @Option(name = "audio-silent", 356 description = "deprecated, use option disable-audio. set ro.audio.silent on boot.") 357 @Deprecated 358 private boolean mDeprecatedSetAudioSilent = DEFAULT_DISABLE_AUDIO; 359 360 /** 361 * @deprecated use option set-property instead. 362 */ 363 @Option(name = "setprop", 364 description = "deprecated, use option set-property. set the specified property on " + 365 "boot. Format: --setprop key=value. May be repeated.") 366 @Deprecated 367 private Collection<String> mDeprecatedSetProps = new ArrayList<String>(); 368 369 private static final String PERSIST_PREFIX = "persist."; 370 371 /** 372 * {@inheritDoc} 373 */ 374 @Override 375 public void setUp(ITestDevice device, IBuildInfo buildInfo) throws DeviceNotAvailableException, 376 TargetSetupError { 377 if (mDisable) { 378 return; 379 } 380 381 CLog.i("Performing setup on %s", device.getSerialNumber()); 382 383 if (device.getOptions().isEnableAdbRoot() && !device.enableAdbRoot()) { 384 throw new TargetSetupError(String.format("Failed to enable adb root on %s", 385 device.getSerialNumber()), device.getDeviceDescriptor()); 386 } 387 388 // Convert deprecated options into current options 389 processDeprecatedOptions(device); 390 // Convert options into settings and run commands 391 processOptions(device); 392 // Change system props (will reboot device) 393 changeSystemProps(device); 394 // Handle screen always on setting 395 handleScreenAlwaysOnSetting(device); 396 // Run commands designated to be run before changing settings 397 runCommands(device, mRunCommandBeforeSettings); 398 // Change settings 399 changeSettings(device); 400 // Connect wifi after settings since this may take a while 401 connectWifi(device); 402 // Sync data after settings since this may take a while 403 syncTestData(device); 404 // Run commands designated to be run after changing settings 405 runCommands(device, mRunCommandAfterSettings); 406 // Throw an error if there is not enough storage space 407 checkExternalStoreSpace(device); 408 409 device.clearErrorDialogs(); 410 } 411 412 /** 413 * {@inheritDoc} 414 */ 415 @Override 416 public void tearDown(ITestDevice device, IBuildInfo buildInfo, Throwable e) 417 throws DeviceNotAvailableException { 418 // ignore tearDown if it's a stub device, since there is no real device to clean. 419 if (mDisable || device.getIDevice() instanceof StubDevice) { 420 return; 421 } 422 423 CLog.i("Performing teardown on %s", device.getSerialNumber()); 424 425 if (e instanceof DeviceFailedToBootError) { 426 CLog.d("boot failure: skipping teardown"); 427 return; 428 } 429 430 // Only try to disconnect if wifi ssid is set since isWifiEnabled() is a heavy operation 431 // which should be avoided when possible 432 if (mDisconnectWifiAfterTest && mWifiSsid != null && device.isWifiEnabled()) { 433 boolean result = device.disconnectFromWifi(); 434 if (result) { 435 CLog.i("Successfully disconnected from wifi network on %s", 436 device.getSerialNumber()); 437 } else { 438 CLog.w("Failed to disconnect from wifi network on %s", device.getSerialNumber()); 439 } 440 } 441 } 442 443 /** 444 * Processes the deprecated options converting them into the currently used options. 445 * <p> 446 * This method should be run before any other processing methods. Will throw a 447 * {@link TargetSetupError} if the deprecated option overrides a specified non-deprecated 448 * option. 449 * </p> 450 * @throws TargetSetupError if there is a conflict 451 */ 452 public void processDeprecatedOptions(ITestDevice device) throws TargetSetupError { 453 if (mDeprecatedMinExternalStoreSpace != DEFAULT_MIN_EXTERNAL_STORAGE_KB) { 454 if (mMinExternalStorageKb != DEFAULT_MIN_EXTERNAL_STORAGE_KB) { 455 throw new TargetSetupError("Deprecated option min-external-store-space conflicts " + 456 "with option min-external-storage-kb", device.getDeviceDescriptor()); 457 } 458 mMinExternalStorageKb = mDeprecatedMinExternalStoreSpace; 459 } 460 461 if (mDeprecatedSetAudioSilent != DEFAULT_DISABLE_AUDIO) { 462 if (mDisableAudio != DEFAULT_DISABLE_AUDIO) { 463 throw new TargetSetupError("Deprecated option audio-silent conflicts with " + 464 "option disable-audio", device.getDeviceDescriptor()); 465 } 466 mDisableAudio = mDeprecatedSetAudioSilent; 467 } 468 469 if (!mDeprecatedSetProps.isEmpty()) { 470 if (!mSetProps.isEmpty()) { 471 throw new TargetSetupError("Deprecated option setprop conflicts with option " + 472 "set-property ", device.getDeviceDescriptor()); 473 } 474 for (String prop : mDeprecatedSetProps) { 475 String[] parts = prop.split("=", 2); 476 String key = parts[0].trim(); 477 String value = parts.length == 2 ? parts[1].trim() : ""; 478 mSetProps.put(key, value); 479 } 480 } 481 } 482 483 /** 484 * Process all the {@link Option}s and turn them into system props, settings, or run commands. 485 * Does not run any commands on the device at this time. 486 * <p> 487 * Exposed so that children classes may override this. 488 * </p> 489 * 490 * @param device The {@link ITestDevice} 491 * @throws DeviceNotAvailableException if the device is not available 492 * @throws TargetSetupError if the {@link Option}s conflict 493 */ 494 public void processOptions(ITestDevice device) throws DeviceNotAvailableException, 495 TargetSetupError { 496 setSettingForBinaryState(mWifi, mGlobalSettings, "wifi_on", "1", "0"); 497 setCommandForBinaryState(mWifi, mRunCommandAfterSettings, 498 "svc wifi enable", "svc wifi disable"); 499 500 setSettingForBinaryState(mWifiWatchdog, mGlobalSettings, "wifi_watchdog", "1", "0"); 501 502 setSettingForBinaryState(mWifiScanAlwaysEnabled, mGlobalSettings, 503 "wifi_scan_always_enabled", "1", "0"); 504 505 setCommandForBinaryState(mEthernet, mRunCommandAfterSettings, 506 "ifconfig eth0 up", "ifconfig eth0 down"); 507 508 setCommandForBinaryState(mBluetooth, mRunCommandAfterSettings, 509 "service call bluetooth_manager 6", "service call bluetooth_manager 8"); 510 511 setCommandForBinaryState(mNfc, mRunCommandAfterSettings, 512 "svc nfc enable", "svc nfc disable"); 513 514 if (mScreenBrightness != null && BinaryState.ON.equals(mScreenAdaptiveBrightness)) { 515 throw new TargetSetupError("Option screen-brightness cannot be set when " + 516 "screen-adaptive-brightness is set to ON", device.getDeviceDescriptor()); 517 } 518 519 setSettingForBinaryState(mScreenAdaptiveBrightness, mSystemSettings, 520 "screen_brightness_mode", "1", "0"); 521 522 if (mScreenBrightness != null) { 523 mSystemSettings.put("screen_brightness", Integer.toString(mScreenBrightness)); 524 } 525 526 if (mScreenTimeoutSecs != null) { 527 mSystemSettings.put("screen_off_timeout", Long.toString(mScreenTimeoutSecs * 1000)); 528 } 529 530 setSettingForBinaryState(mScreenAmbientMode, mSecureSettings, "doze_enabled", "1", "0"); 531 532 setSettingForBinaryState(mWakeGesture, mSecureSettings, "wake_gesture_enabled", "1", "0"); 533 534 setSettingForBinaryState(mScreenSaver, mSecureSettings, "screensaver_enabled", "1", "0"); 535 536 setSettingForBinaryState(mNotificationLed, mSystemSettings, 537 "notification_light_pulse", "1", "0"); 538 539 setSettingForBinaryState(mInstallNonMarketApps, mSecureSettings, 540 "install_non_market_apps", "1", "0"); 541 542 if (mTriggerMediaMounted) { 543 mRunCommandAfterSettings.add( 544 "am broadcast -a android.intent.action.MEDIA_MOUNTED -d " 545 + "file://${EXTERNAL_STORAGE} --receiver-include-background"); 546 } 547 548 setSettingForBinaryState(mLocationGps, mSecureSettings, 549 "location_providers_allowed", "+gps", "-gps"); 550 551 setSettingForBinaryState(mLocationNetwork, mSecureSettings, 552 "location_providers_allowed", "+network", "-network"); 553 554 setSettingForBinaryState(mAutoRotate, mSystemSettings, "accelerometer_rotation", "1", "0"); 555 556 if (device.getApiLevel() < 22) { 557 setCommandForBinaryState(mBatterySaver, mRunCommandBeforeSettings, 558 "dumpsys battery set usb 0", null); 559 } else { 560 setCommandForBinaryState(mBatterySaver, mRunCommandBeforeSettings, 561 "dumpsys battery unplug", null); 562 } 563 setSettingForBinaryState(mBatterySaver, mGlobalSettings, "low_power", "1", "0"); 564 565 if (mBatterySaverTrigger != null) { 566 mGlobalSettings.put("low_power_trigger_level", Integer.toString(mBatterySaverTrigger)); 567 } 568 569 if (mEnableFullBatteryStatsHistory) { 570 mRunCommandAfterSettings.add("dumpsys batterystats --enable full-history"); 571 } 572 573 if (mDisableDoze) { 574 mRunCommandAfterSettings.add("dumpsys deviceidle disable"); 575 } 576 577 setSettingForBinaryState(mAutoUpdateTime, mSystemSettings, "auto_time", "1", "0"); 578 579 setSettingForBinaryState(mAutoUpdateTimezone, mSystemSettings, "auto_timezone", "1", "0"); 580 581 if (mTimezone != null) { 582 mSetProps.put("persist.sys.timezone", mTimezone); 583 } 584 585 if (mDisableDialing) { 586 mSetProps.put("ro.telephony.disable-call", "true"); 587 } 588 589 if (mDefaultSimData != null) { 590 mGlobalSettings.put("multi_sim_data_call", Integer.toString(mDefaultSimData)); 591 } 592 593 if (mDefaultSimVoice != null) { 594 mGlobalSettings.put("multi_sim_voice_call", Integer.toString(mDefaultSimVoice)); 595 } 596 597 if (mDefaultSimSms != null) { 598 mGlobalSettings.put("multi_sim_sms", Integer.toString(mDefaultSimSms)); 599 } 600 601 if (mDisableAudio) { 602 mSetProps.put("ro.audio.silent", "1"); 603 } 604 605 if (mSetTestHarness) { 606 // set both ro.monkey and ro.test_harness, for compatibility with older platforms 607 mSetProps.put("ro.monkey", "1"); 608 mSetProps.put("ro.test_harness", "1"); 609 } 610 611 if (mDisableDalvikVerifier) { 612 mSetProps.put("dalvik.vm.dexopt-flags", "v=n"); 613 } 614 } 615 616 /** 617 * Change the system properties on the device. 618 * 619 * @param device The {@link ITestDevice} 620 * @throws DeviceNotAvailableException if the device is not available 621 * @throws TargetSetupError if there was a failure setting the system properties 622 */ 623 private void changeSystemProps(ITestDevice device) throws DeviceNotAvailableException, 624 TargetSetupError { 625 if (mForceSkipSystemProps) { 626 CLog.d("Skipping system props due to force-skip-system-props"); 627 return; 628 } 629 630 StringBuilder sb = new StringBuilder(); 631 for (Map.Entry<String, String> prop : mSetProps.entrySet()) { 632 if (prop.getKey().startsWith(PERSIST_PREFIX)) { 633 String command = String.format("setprop \"%s\" \"%s\"", 634 prop.getKey(), prop.getValue()); 635 device.executeShellCommand(command); 636 } else { 637 sb.append(String.format("%s=%s\n", prop.getKey(), prop.getValue())); 638 } 639 } 640 641 if (sb.length() == 0) { 642 return; 643 } 644 645 boolean result = device.pushString(sb.toString(), "/data/local.prop"); 646 if (!result) { 647 throw new TargetSetupError(String.format("Failed to push /data/local.prop to %s", 648 device.getSerialNumber()), device.getDeviceDescriptor()); 649 } 650 // Set reasonable permissions for /data/local.prop 651 device.executeShellCommand("chmod 644 /data/local.prop"); 652 CLog.i("Rebooting %s due to system property change", device.getSerialNumber()); 653 device.reboot(); 654 } 655 656 /** 657 * Handles screen always on settings. 658 * <p> 659 * This is done in a dedicated function because special handling is required in case of setting 660 * screen to always on. 661 * @throws DeviceNotAvailableException 662 */ 663 private void handleScreenAlwaysOnSetting(ITestDevice device) 664 throws DeviceNotAvailableException { 665 String cmd = "svc power stayon %s"; 666 switch (mScreenAlwaysOn) { 667 case ON: 668 CLog.d("Setting screen always on to true"); 669 device.executeShellCommand(String.format(cmd, "true")); 670 // send MENU press in case keygaurd needs to be dismissed again 671 device.executeShellCommand("input keyevent 82"); 672 // send HOME press in case keyguard was already dismissed, so we bring device back 673 // to home screen 674 device.executeShellCommand("input keyevent 3"); 675 break; 676 case OFF: 677 CLog.d("Setting screen always on to false"); 678 device.executeShellCommand(String.format(cmd, "false")); 679 break; 680 case IGNORE: 681 break; 682 } 683 } 684 685 /** 686 * Change the settings on the device. 687 * <p> 688 * Exposed so children classes may override. 689 * </p> 690 * 691 * @param device The {@link ITestDevice} 692 * @throws DeviceNotAvailableException if the device is not available 693 * @throws TargetSetupError if there was a failure setting the settings 694 */ 695 public void changeSettings(ITestDevice device) throws DeviceNotAvailableException, 696 TargetSetupError { 697 if (mForceSkipSettings) { 698 CLog.d("Skipping settings due to force-skip-setttings"); 699 return; 700 } 701 702 if (mSystemSettings.isEmpty() && mSecureSettings.isEmpty() && mGlobalSettings.isEmpty() && 703 BinaryState.IGNORE.equals(mAirplaneMode)) { 704 CLog.d("No settings to change"); 705 return; 706 } 707 708 if (device.getApiLevel() < 22) { 709 throw new TargetSetupError(String.format("Changing setting not supported on %s, " + 710 "must be API 22+", device.getSerialNumber()), device.getDeviceDescriptor()); 711 } 712 713 // Special case airplane mode since it needs to be set before other connectivity settings 714 // For example, it is possible to enable airplane mode and then turn wifi on 715 String command = "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state %s"; 716 switch (mAirplaneMode) { 717 case ON: 718 CLog.d("Changing global setting airplane_mode_on to 1"); 719 device.setSetting("global", "airplane_mode_on", "1"); 720 if (!mForceSkipRunCommands) { 721 device.executeShellCommand(String.format(command, "true")); 722 } 723 break; 724 case OFF: 725 CLog.d("Changing global setting airplane_mode_on to 0"); 726 device.setSetting("global", "airplane_mode_on", "0"); 727 if (!mForceSkipRunCommands) { 728 device.executeShellCommand(String.format(command, "false")); 729 } 730 break; 731 case IGNORE: 732 // No-op 733 break; 734 } 735 736 for (String key : mSystemSettings.keySet()) { 737 for (String value : mSystemSettings.get(key)) { 738 CLog.d("Changing system setting %s to %s", key, value); 739 device.setSetting("system", key, value); 740 } 741 } 742 for (String key : mSecureSettings.keySet()) { 743 for (String value : mSecureSettings.get(key)) { 744 CLog.d("Changing secure setting %s to %s", key, value); 745 device.setSetting("secure", key, value); 746 } 747 } 748 749 for (String key : mGlobalSettings.keySet()) { 750 for (String value : mGlobalSettings.get(key)) { 751 CLog.d("Changing global setting %s to %s", key, value); 752 device.setSetting("global", key, value); 753 } 754 } 755 } 756 757 /** 758 * Execute additional commands on the device. 759 * 760 * @param device The {@link ITestDevice} 761 * @param commands The list of commands to run 762 * @throws DeviceNotAvailableException if the device is not available 763 * @throws TargetSetupError if there was a failure setting the settings 764 */ 765 private void runCommands(ITestDevice device, List<String> commands) 766 throws DeviceNotAvailableException, TargetSetupError { 767 if (mForceSkipRunCommands) { 768 CLog.d("Skipping run commands due to force-skip-run-commands"); 769 return; 770 } 771 772 for (String command : commands) { 773 device.executeShellCommand(command); 774 } 775 } 776 777 /** 778 * Connects device to Wifi if SSID is specified. 779 * 780 * @param device The {@link ITestDevice} 781 * @throws DeviceNotAvailableException if the device is not available 782 * @throws TargetSetupError if there was a failure setting the settings 783 */ 784 private void connectWifi(ITestDevice device) throws DeviceNotAvailableException, 785 TargetSetupError { 786 if (mForceSkipRunCommands) { 787 CLog.d("Skipping connect wifi due to force-skip-run-commands"); 788 return; 789 } 790 791 if (mWifiSsid != null) { 792 if (!device.connectToWifiNetwork(mWifiSsid, mWifiPsk)) { 793 throw new TargetSetupError(String.format( 794 "Failed to connect to wifi network %s on %s", mWifiSsid, 795 device.getSerialNumber()), device.getDeviceDescriptor()); 796 } 797 } 798 } 799 800 /** 801 * Syncs a set of test data files, specified via local-data-path, to devices external storage. 802 * 803 * @param device The {@link ITestDevice} 804 * @throws DeviceNotAvailableException if the device is not available 805 * @throws TargetSetupError if data fails to sync 806 */ 807 private void syncTestData(ITestDevice device) throws DeviceNotAvailableException, 808 TargetSetupError { 809 if (mLocalDataFile == null) { 810 return; 811 } 812 813 if (!mLocalDataFile.exists() || !mLocalDataFile.isDirectory()) { 814 throw new TargetSetupError(String.format( 815 "local-data-path %s is not a directory", mLocalDataFile.getAbsolutePath()), 816 device.getDeviceDescriptor()); 817 } 818 String fullRemotePath = device.getIDevice().getMountPoint(IDevice.MNT_EXTERNAL_STORAGE); 819 if (fullRemotePath == null) { 820 throw new TargetSetupError(String.format( 821 "failed to get external storage path on device %s", device.getSerialNumber()), 822 device.getDeviceDescriptor()); 823 } 824 if (mRemoteDataPath != null) { 825 fullRemotePath = String.format("%s/%s", fullRemotePath, mRemoteDataPath); 826 } 827 boolean result = device.syncFiles(mLocalDataFile, fullRemotePath); 828 if (!result) { 829 // TODO: get exact error code and respond accordingly 830 throw new TargetSetupError(String.format( 831 "failed to sync test data from local-data-path %s to %s on device %s", 832 mLocalDataFile.getAbsolutePath(), fullRemotePath, device.getSerialNumber()), 833 device.getDeviceDescriptor()); 834 } 835 } 836 837 /** 838 * Check that device external store has the required space 839 * 840 * @param device The {@link ITestDevice} 841 * @throws DeviceNotAvailableException if the device is not available or if the device does not 842 * have the required space 843 */ 844 private void checkExternalStoreSpace(ITestDevice device) throws DeviceNotAvailableException { 845 if (mMinExternalStorageKb <= 0) { 846 return; 847 } 848 849 long freeSpace = device.getExternalStoreFreeSpace(); 850 if (freeSpace < mMinExternalStorageKb) { 851 throw new DeviceNotAvailableException(String.format( 852 "External store free space %dK is less than required %dK for device %s", 853 freeSpace , mMinExternalStorageKb, device.getSerialNumber()), 854 device.getSerialNumber()); 855 } 856 } 857 858 /** 859 * Helper method to add an ON/OFF setting to a setting map. 860 * 861 * @param state The {@link BinaryState} 862 * @param settingsMap The {@link MultiMap} used to store the settings. 863 * @param setting The setting key 864 * @param onValue The value if ON 865 * @param offValue The value if OFF 866 */ 867 public static void setSettingForBinaryState(BinaryState state, 868 MultiMap<String, String> settingsMap, String setting, String onValue, String offValue) { 869 switch (state) { 870 case ON: 871 settingsMap.put(setting, onValue); 872 break; 873 case OFF: 874 settingsMap.put(setting, offValue); 875 break; 876 case IGNORE: 877 // Do nothing 878 break; 879 } 880 } 881 882 /** 883 * Helper method to add an ON/OFF run command to be executed on the device. 884 * 885 * @param state The {@link BinaryState} 886 * @param commands The list of commands to add the on or off command to. 887 * @param onCommand The command to run if ON. Ignored if the command is {@code null} 888 * @param offCommand The command to run if OFF. Ignored if the command is {@code null} 889 */ 890 public static void setCommandForBinaryState(BinaryState state, List<String> commands, 891 String onCommand, String offCommand) { 892 switch (state) { 893 case ON: 894 if (onCommand != null) { 895 commands.add(onCommand); 896 } 897 break; 898 case OFF: 899 if (offCommand != null) { 900 commands.add(offCommand); 901 } 902 break; 903 case IGNORE: 904 // Do nothing 905 break; 906 } 907 } 908 909 /** 910 * Exposed for unit testing 911 */ 912 protected void setAirplaneMode(BinaryState airplaneMode) { 913 mAirplaneMode = airplaneMode; 914 } 915 916 /** 917 * Exposed for unit testing 918 */ 919 protected void setWifi(BinaryState wifi) { 920 mWifi = wifi; 921 } 922 923 /** 924 * Exposed for unit testing 925 */ 926 protected void setWifiNetwork(String wifiNetwork) { 927 mWifiSsid = wifiNetwork; 928 } 929 930 /** 931 * Exposed for unit testing 932 */ 933 protected void setWifiWatchdog(BinaryState wifiWatchdog) { 934 mWifiWatchdog = wifiWatchdog; 935 } 936 937 /** 938 * Exposed for unit testing 939 */ 940 protected void setWifiScanAlwaysEnabled(BinaryState wifiScanAlwaysEnabled) { 941 mWifiScanAlwaysEnabled = wifiScanAlwaysEnabled; 942 } 943 944 /** 945 * Exposed for unit testing 946 */ 947 protected void setEthernet(BinaryState ethernet) { 948 mEthernet = ethernet; 949 } 950 951 /** 952 * Exposed for unit testing 953 */ 954 protected void setBluetooth(BinaryState bluetooth) { 955 mBluetooth = bluetooth; 956 } 957 958 /** 959 * Exposed for unit testing 960 */ 961 protected void setNfc(BinaryState nfc) { 962 mNfc = nfc; 963 } 964 965 /** 966 * Exposed for unit testing 967 */ 968 protected void setScreenAdaptiveBrightness(BinaryState screenAdaptiveBrightness) { 969 mScreenAdaptiveBrightness = screenAdaptiveBrightness; 970 } 971 972 /** 973 * Exposed for unit testing 974 */ 975 protected void setScreenBrightness(Integer screenBrightness) { 976 mScreenBrightness = screenBrightness; 977 } 978 979 /** 980 * Exposed for unit testing 981 */ 982 protected void setScreenAlwaysOn(BinaryState screenAlwaysOn) { 983 mScreenAlwaysOn = screenAlwaysOn; 984 } 985 986 /** 987 * Exposed for unit testing 988 */ 989 protected void setScreenTimeoutSecs(Long screenTimeoutSecs) { 990 mScreenTimeoutSecs = screenTimeoutSecs; 991 } 992 993 /** 994 * Exposed for unit testing 995 */ 996 protected void setScreenAmbientMode(BinaryState screenAmbientMode) { 997 mScreenAmbientMode = screenAmbientMode; 998 } 999 1000 /** 1001 * Exposed for unit testing 1002 */ 1003 protected void setWakeGesture(BinaryState wakeGesture) { 1004 mWakeGesture = wakeGesture; 1005 } 1006 1007 /** 1008 * Exposed for unit testing 1009 */ 1010 protected void setScreenSaver(BinaryState screenSaver) { 1011 mScreenSaver = screenSaver; 1012 } 1013 1014 /** 1015 * Exposed for unit testing 1016 */ 1017 protected void setNotificationLed(BinaryState notificationLed) { 1018 mNotificationLed = notificationLed; 1019 } 1020 1021 /** 1022 * Exposed for unit testing 1023 */ 1024 protected void setInstallNonMarketApps(BinaryState installNonMarketApps) { 1025 mInstallNonMarketApps = installNonMarketApps; 1026 } 1027 1028 /** 1029 * Exposed for unit testing 1030 */ 1031 protected void setTriggerMediaMounted(boolean triggerMediaMounted) { 1032 mTriggerMediaMounted = triggerMediaMounted; 1033 } 1034 1035 /** 1036 * Exposed for unit testing 1037 */ 1038 protected void setLocationGps(BinaryState locationGps) { 1039 mLocationGps = locationGps; 1040 } 1041 1042 /** 1043 * Exposed for unit testing 1044 */ 1045 protected void setLocationNetwork(BinaryState locationNetwork) { 1046 mLocationNetwork = locationNetwork; 1047 } 1048 1049 /** 1050 * Exposed for unit testing 1051 */ 1052 protected void setAutoRotate(BinaryState autoRotate) { 1053 mAutoRotate = autoRotate; 1054 } 1055 1056 /** 1057 * Exposed for unit testing 1058 */ 1059 protected void setBatterySaver(BinaryState batterySaver) { 1060 mBatterySaver = batterySaver; 1061 } 1062 1063 /** 1064 * Exposed for unit testing 1065 */ 1066 protected void setBatterySaverTrigger(Integer batterySaverTrigger) { 1067 mBatterySaverTrigger = batterySaverTrigger; 1068 } 1069 1070 /** 1071 * Exposed for unit testing 1072 */ 1073 protected void setEnableFullBatteryStatsHistory(boolean enableFullBatteryStatsHistory) { 1074 mEnableFullBatteryStatsHistory = enableFullBatteryStatsHistory; 1075 } 1076 1077 /** 1078 * Exposed for unit testing 1079 */ 1080 protected void setDisableDoze(boolean disableDoze) { 1081 mDisableDoze = disableDoze; 1082 } 1083 1084 /** 1085 * Exposed for unit testing 1086 */ 1087 protected void setAutoUpdateTime(BinaryState autoUpdateTime) { 1088 mAutoUpdateTime = autoUpdateTime; 1089 } 1090 1091 /** 1092 * Exposed for unit testing 1093 */ 1094 protected void setAutoUpdateTimezone(BinaryState autoUpdateTimezone) { 1095 mAutoUpdateTimezone = autoUpdateTimezone; 1096 } 1097 1098 /** 1099 * Exposed for unit testing 1100 */ 1101 protected void setTimezone(String timezone) { 1102 mTimezone = timezone; 1103 } 1104 1105 /** 1106 * Exposed for unit testing 1107 */ 1108 protected void setDisableDialing(boolean disableDialing) { 1109 mDisableDialing = disableDialing; 1110 } 1111 1112 /** 1113 * Exposed for unit testing 1114 */ 1115 protected void setDefaultSimData(Integer defaultSimData) { 1116 mDefaultSimData = defaultSimData; 1117 } 1118 1119 /** 1120 * Exposed for unit testing 1121 */ 1122 protected void setDefaultSimVoice(Integer defaultSimVoice) { 1123 mDefaultSimVoice = defaultSimVoice; 1124 } 1125 1126 /** 1127 * Exposed for unit testing 1128 */ 1129 protected void setDefaultSimSms(Integer defaultSimSms) { 1130 mDefaultSimSms = defaultSimSms; 1131 } 1132 1133 /** 1134 * Exposed for unit testing 1135 */ 1136 protected void setDisableAudio(boolean disable) { 1137 mDisableAudio = disable; 1138 } 1139 1140 /** 1141 * Exposed for unit testing 1142 */ 1143 protected void setTestHarness(boolean setTestHarness) { 1144 mSetTestHarness = setTestHarness; 1145 } 1146 1147 /** 1148 * Exposed for unit testing 1149 */ 1150 protected void setDisableDalvikVerifier(boolean disableDalvikVerifier) { 1151 mDisableDalvikVerifier = disableDalvikVerifier; 1152 } 1153 1154 /** 1155 * Exposed for unit testing 1156 */ 1157 protected void setLocalDataPath(File path) { 1158 mLocalDataFile = path; 1159 } 1160 1161 /** 1162 * Exposed for unit testing 1163 */ 1164 protected void setMinExternalStorageKb(long storageKb) { 1165 mMinExternalStorageKb = storageKb; 1166 } 1167 1168 /** 1169 * Exposed for unit testing 1170 */ 1171 protected void setProperty(String key, String value) { 1172 mSetProps.put(key, value); 1173 } 1174 1175 /** 1176 * Exposed for unit testing 1177 * @deprecated use {@link #setMinExternalStorageKb(long)} instead. 1178 */ 1179 @Deprecated 1180 protected void setDeprecatedMinExternalStoreSpace(long storeSpace) { 1181 mDeprecatedMinExternalStoreSpace = storeSpace; 1182 } 1183 1184 /** 1185 * Exposed for unit testing 1186 * @deprecated use {@link #setDisableAudio(boolean)} instead. 1187 */ 1188 @Deprecated 1189 protected void setDeprecatedAudioSilent(boolean silent) { 1190 mDeprecatedSetAudioSilent = silent; 1191 } 1192 1193 /** 1194 * Exposed for unit testing 1195 * @deprecated use {@link #setProperty(String, String)} instead. 1196 */ 1197 @Deprecated 1198 protected void setDeprecatedSetProp(String prop) { 1199 mDeprecatedSetProps.add(prop); 1200 } 1201 } 1202