Home | History | Annotate | Download | only in targetprep
      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