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         CLog.d("Pushing the following properties to /data/local.prop:\n%s", sb.toString());
    646         boolean result = device.pushString(sb.toString(), "/data/local.prop");
    647         if (!result) {
    648             throw new TargetSetupError(String.format("Failed to push /data/local.prop to %s",
    649                     device.getSerialNumber()), device.getDeviceDescriptor());
    650         }
    651         // Set reasonable permissions for /data/local.prop
    652         device.executeShellCommand("chmod 644 /data/local.prop");
    653         CLog.i("Rebooting %s due to system property change", device.getSerialNumber());
    654         device.reboot();
    655     }
    656 
    657     /**
    658      * Handles screen always on settings.
    659      * <p>
    660      * This is done in a dedicated function because special handling is required in case of setting
    661      * screen to always on.
    662      * @throws DeviceNotAvailableException
    663      */
    664     private void handleScreenAlwaysOnSetting(ITestDevice device)
    665             throws DeviceNotAvailableException {
    666         String cmd = "svc power stayon %s";
    667         switch (mScreenAlwaysOn) {
    668             case ON:
    669                 CLog.d("Setting screen always on to true");
    670                 device.executeShellCommand(String.format(cmd, "true"));
    671                 // send MENU press in case keygaurd needs to be dismissed again
    672                 device.executeShellCommand("input keyevent 82");
    673                 // send HOME press in case keyguard was already dismissed, so we bring device back
    674                 // to home screen
    675                 device.executeShellCommand("input keyevent 3");
    676                 break;
    677             case OFF:
    678                 CLog.d("Setting screen always on to false");
    679                 device.executeShellCommand(String.format(cmd, "false"));
    680                 break;
    681             case IGNORE:
    682                 break;
    683         }
    684     }
    685 
    686     /**
    687      * Change the settings on the device.
    688      * <p>
    689      * Exposed so children classes may override.
    690      * </p>
    691      *
    692      * @param device The {@link ITestDevice}
    693      * @throws DeviceNotAvailableException if the device is not available
    694      * @throws TargetSetupError if there was a failure setting the settings
    695      */
    696     public void changeSettings(ITestDevice device) throws DeviceNotAvailableException,
    697             TargetSetupError {
    698         if (mForceSkipSettings) {
    699             CLog.d("Skipping settings due to force-skip-setttings");
    700             return;
    701         }
    702 
    703         if (mSystemSettings.isEmpty() && mSecureSettings.isEmpty() && mGlobalSettings.isEmpty() &&
    704                 BinaryState.IGNORE.equals(mAirplaneMode)) {
    705             CLog.d("No settings to change");
    706             return;
    707         }
    708 
    709         if (device.getApiLevel() < 22) {
    710             throw new TargetSetupError(String.format("Changing setting not supported on %s, " +
    711                     "must be API 22+", device.getSerialNumber()), device.getDeviceDescriptor());
    712         }
    713 
    714         // Special case airplane mode since it needs to be set before other connectivity settings
    715         // For example, it is possible to enable airplane mode and then turn wifi on
    716         String command = "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state %s";
    717         switch (mAirplaneMode) {
    718             case ON:
    719                 CLog.d("Changing global setting airplane_mode_on to 1");
    720                 device.setSetting("global", "airplane_mode_on", "1");
    721                 if (!mForceSkipRunCommands) {
    722                     device.executeShellCommand(String.format(command, "true"));
    723                 }
    724                 break;
    725             case OFF:
    726                 CLog.d("Changing global setting airplane_mode_on to 0");
    727                 device.setSetting("global", "airplane_mode_on", "0");
    728                 if (!mForceSkipRunCommands) {
    729                     device.executeShellCommand(String.format(command, "false"));
    730                 }
    731                 break;
    732             case IGNORE:
    733                 // No-op
    734                 break;
    735         }
    736 
    737         for (String key : mSystemSettings.keySet()) {
    738             for (String value : mSystemSettings.get(key)) {
    739                 CLog.d("Changing system setting %s to %s", key, value);
    740                 device.setSetting("system", key, value);
    741             }
    742         }
    743         for (String key : mSecureSettings.keySet()) {
    744             for (String value : mSecureSettings.get(key)) {
    745                 CLog.d("Changing secure setting %s to %s", key, value);
    746                 device.setSetting("secure", key, value);
    747             }
    748         }
    749 
    750         for (String key : mGlobalSettings.keySet()) {
    751             for (String value : mGlobalSettings.get(key)) {
    752                 CLog.d("Changing global setting %s to %s", key, value);
    753                 device.setSetting("global", key, value);
    754             }
    755         }
    756     }
    757 
    758     /**
    759      * Execute additional commands on the device.
    760      *
    761      * @param device The {@link ITestDevice}
    762      * @param commands The list of commands to run
    763      * @throws DeviceNotAvailableException if the device is not available
    764      * @throws TargetSetupError if there was a failure setting the settings
    765      */
    766     private void runCommands(ITestDevice device, List<String> commands)
    767             throws DeviceNotAvailableException, TargetSetupError {
    768         if (mForceSkipRunCommands) {
    769             CLog.d("Skipping run commands due to force-skip-run-commands");
    770             return;
    771         }
    772 
    773         for (String command : commands) {
    774             device.executeShellCommand(command);
    775         }
    776     }
    777 
    778     /**
    779      * Connects device to Wifi if SSID is specified.
    780      *
    781      * @param device The {@link ITestDevice}
    782      * @throws DeviceNotAvailableException if the device is not available
    783      * @throws TargetSetupError if there was a failure setting the settings
    784      */
    785     private void connectWifi(ITestDevice device) throws DeviceNotAvailableException,
    786             TargetSetupError {
    787         if (mForceSkipRunCommands) {
    788             CLog.d("Skipping connect wifi due to force-skip-run-commands");
    789             return;
    790         }
    791 
    792         if (mWifiSsid != null) {
    793             if (!device.connectToWifiNetwork(mWifiSsid, mWifiPsk)) {
    794                 throw new TargetSetupError(String.format(
    795                         "Failed to connect to wifi network %s on %s", mWifiSsid,
    796                         device.getSerialNumber()), device.getDeviceDescriptor());
    797             }
    798         }
    799     }
    800 
    801     /**
    802      * Syncs a set of test data files, specified via local-data-path, to devices external storage.
    803      *
    804      * @param device The {@link ITestDevice}
    805      * @throws DeviceNotAvailableException if the device is not available
    806      * @throws TargetSetupError if data fails to sync
    807      */
    808     private void syncTestData(ITestDevice device) throws DeviceNotAvailableException,
    809             TargetSetupError {
    810         if (mLocalDataFile == null) {
    811             return;
    812         }
    813 
    814         if (!mLocalDataFile.exists() || !mLocalDataFile.isDirectory()) {
    815             throw new TargetSetupError(String.format(
    816                     "local-data-path %s is not a directory", mLocalDataFile.getAbsolutePath()),
    817                     device.getDeviceDescriptor());
    818         }
    819         String fullRemotePath = device.getIDevice().getMountPoint(IDevice.MNT_EXTERNAL_STORAGE);
    820         if (fullRemotePath == null) {
    821             throw new TargetSetupError(String.format(
    822                     "failed to get external storage path on device %s", device.getSerialNumber()),
    823                     device.getDeviceDescriptor());
    824         }
    825         if (mRemoteDataPath != null) {
    826             fullRemotePath = String.format("%s/%s", fullRemotePath, mRemoteDataPath);
    827         }
    828         boolean result = device.syncFiles(mLocalDataFile, fullRemotePath);
    829         if (!result) {
    830             // TODO: get exact error code and respond accordingly
    831             throw new TargetSetupError(String.format(
    832                     "failed to sync test data from local-data-path %s to %s on device %s",
    833                     mLocalDataFile.getAbsolutePath(), fullRemotePath, device.getSerialNumber()),
    834                     device.getDeviceDescriptor());
    835         }
    836     }
    837 
    838     /**
    839      * Check that device external store has the required space
    840      *
    841      * @param device The {@link ITestDevice}
    842      * @throws DeviceNotAvailableException if the device is not available or if the device does not
    843      * have the required space
    844      */
    845     private void checkExternalStoreSpace(ITestDevice device) throws DeviceNotAvailableException {
    846         if (mMinExternalStorageKb <= 0) {
    847             return;
    848         }
    849 
    850         long freeSpace = device.getExternalStoreFreeSpace();
    851         if (freeSpace < mMinExternalStorageKb) {
    852             throw new DeviceNotAvailableException(String.format(
    853                     "External store free space %dK is less than required %dK for device %s",
    854                     freeSpace , mMinExternalStorageKb, device.getSerialNumber()),
    855                     device.getSerialNumber());
    856         }
    857     }
    858 
    859     /**
    860      * Helper method to add an ON/OFF setting to a setting map.
    861      *
    862      * @param state The {@link BinaryState}
    863      * @param settingsMap The {@link MultiMap} used to store the settings.
    864      * @param setting The setting key
    865      * @param onValue The value if ON
    866      * @param offValue The value if OFF
    867      */
    868     public static void setSettingForBinaryState(BinaryState state,
    869             MultiMap<String, String> settingsMap, String setting, String onValue, String offValue) {
    870         switch (state) {
    871             case ON:
    872                 settingsMap.put(setting, onValue);
    873                 break;
    874             case OFF:
    875                 settingsMap.put(setting, offValue);
    876                 break;
    877             case IGNORE:
    878                 // Do nothing
    879                 break;
    880         }
    881     }
    882 
    883     /**
    884      * Helper method to add an ON/OFF run command to be executed on the device.
    885      *
    886      * @param state The {@link BinaryState}
    887      * @param commands The list of commands to add the on or off command to.
    888      * @param onCommand The command to run if ON. Ignored if the command is {@code null}
    889      * @param offCommand The command to run if OFF. Ignored if the command is {@code null}
    890      */
    891     public static void setCommandForBinaryState(BinaryState state, List<String> commands,
    892             String onCommand, String offCommand) {
    893         switch (state) {
    894             case ON:
    895                 if (onCommand != null) {
    896                     commands.add(onCommand);
    897                 }
    898                 break;
    899             case OFF:
    900                 if (offCommand != null) {
    901                     commands.add(offCommand);
    902                 }
    903                 break;
    904             case IGNORE:
    905                 // Do nothing
    906                 break;
    907         }
    908     }
    909 
    910     /**
    911      * Exposed for unit testing
    912      */
    913     protected void setAirplaneMode(BinaryState airplaneMode) {
    914         mAirplaneMode = airplaneMode;
    915     }
    916 
    917     /**
    918      * Exposed for unit testing
    919      */
    920     protected void setWifi(BinaryState wifi) {
    921         mWifi = wifi;
    922     }
    923 
    924     /**
    925      * Exposed for unit testing
    926      */
    927     protected void setWifiNetwork(String wifiNetwork) {
    928         mWifiSsid = wifiNetwork;
    929     }
    930 
    931     /**
    932      * Exposed for unit testing
    933      */
    934     protected void setWifiWatchdog(BinaryState wifiWatchdog) {
    935         mWifiWatchdog = wifiWatchdog;
    936     }
    937 
    938     /**
    939      * Exposed for unit testing
    940      */
    941     protected void setWifiScanAlwaysEnabled(BinaryState wifiScanAlwaysEnabled) {
    942         mWifiScanAlwaysEnabled = wifiScanAlwaysEnabled;
    943     }
    944 
    945     /**
    946      * Exposed for unit testing
    947      */
    948     protected void setEthernet(BinaryState ethernet) {
    949         mEthernet = ethernet;
    950     }
    951 
    952     /**
    953      * Exposed for unit testing
    954      */
    955     protected void setBluetooth(BinaryState bluetooth) {
    956         mBluetooth = bluetooth;
    957     }
    958 
    959     /**
    960      * Exposed for unit testing
    961      */
    962     protected void setNfc(BinaryState nfc) {
    963         mNfc = nfc;
    964     }
    965 
    966     /**
    967      * Exposed for unit testing
    968      */
    969     protected void setScreenAdaptiveBrightness(BinaryState screenAdaptiveBrightness) {
    970         mScreenAdaptiveBrightness = screenAdaptiveBrightness;
    971     }
    972 
    973     /**
    974      * Exposed for unit testing
    975      */
    976     protected void setScreenBrightness(Integer screenBrightness) {
    977         mScreenBrightness = screenBrightness;
    978     }
    979 
    980     /**
    981      * Exposed for unit testing
    982      */
    983     protected void setScreenAlwaysOn(BinaryState screenAlwaysOn) {
    984         mScreenAlwaysOn = screenAlwaysOn;
    985     }
    986 
    987     /**
    988      * Exposed for unit testing
    989      */
    990     protected void setScreenTimeoutSecs(Long screenTimeoutSecs) {
    991         mScreenTimeoutSecs = screenTimeoutSecs;
    992     }
    993 
    994     /**
    995      * Exposed for unit testing
    996      */
    997     protected void setScreenAmbientMode(BinaryState screenAmbientMode) {
    998         mScreenAmbientMode = screenAmbientMode;
    999     }
   1000 
   1001     /**
   1002      * Exposed for unit testing
   1003      */
   1004     protected void setWakeGesture(BinaryState wakeGesture) {
   1005         mWakeGesture = wakeGesture;
   1006     }
   1007 
   1008     /**
   1009      * Exposed for unit testing
   1010      */
   1011     protected void setScreenSaver(BinaryState screenSaver) {
   1012         mScreenSaver = screenSaver;
   1013     }
   1014 
   1015     /**
   1016      * Exposed for unit testing
   1017      */
   1018     protected void setNotificationLed(BinaryState notificationLed) {
   1019         mNotificationLed = notificationLed;
   1020     }
   1021 
   1022     /**
   1023      * Exposed for unit testing
   1024      */
   1025     protected void setInstallNonMarketApps(BinaryState installNonMarketApps) {
   1026         mInstallNonMarketApps = installNonMarketApps;
   1027     }
   1028 
   1029     /**
   1030      * Exposed for unit testing
   1031      */
   1032     protected void setTriggerMediaMounted(boolean triggerMediaMounted) {
   1033         mTriggerMediaMounted = triggerMediaMounted;
   1034     }
   1035 
   1036     /**
   1037      * Exposed for unit testing
   1038      */
   1039     protected void setLocationGps(BinaryState locationGps) {
   1040         mLocationGps = locationGps;
   1041     }
   1042 
   1043     /**
   1044      * Exposed for unit testing
   1045      */
   1046     protected void setLocationNetwork(BinaryState locationNetwork) {
   1047         mLocationNetwork = locationNetwork;
   1048     }
   1049 
   1050     /**
   1051      * Exposed for unit testing
   1052      */
   1053     protected void setAutoRotate(BinaryState autoRotate) {
   1054         mAutoRotate = autoRotate;
   1055     }
   1056 
   1057     /**
   1058      * Exposed for unit testing
   1059      */
   1060     protected void setBatterySaver(BinaryState batterySaver) {
   1061         mBatterySaver = batterySaver;
   1062     }
   1063 
   1064     /**
   1065      * Exposed for unit testing
   1066      */
   1067     protected void setBatterySaverTrigger(Integer batterySaverTrigger) {
   1068         mBatterySaverTrigger = batterySaverTrigger;
   1069     }
   1070 
   1071     /**
   1072      * Exposed for unit testing
   1073      */
   1074     protected void setEnableFullBatteryStatsHistory(boolean enableFullBatteryStatsHistory) {
   1075         mEnableFullBatteryStatsHistory = enableFullBatteryStatsHistory;
   1076     }
   1077 
   1078     /**
   1079      * Exposed for unit testing
   1080      */
   1081     protected void setDisableDoze(boolean disableDoze) {
   1082         mDisableDoze = disableDoze;
   1083     }
   1084 
   1085     /**
   1086      * Exposed for unit testing
   1087      */
   1088     protected void setAutoUpdateTime(BinaryState autoUpdateTime) {
   1089         mAutoUpdateTime = autoUpdateTime;
   1090     }
   1091 
   1092     /**
   1093      * Exposed for unit testing
   1094      */
   1095     protected void setAutoUpdateTimezone(BinaryState autoUpdateTimezone) {
   1096         mAutoUpdateTimezone = autoUpdateTimezone;
   1097     }
   1098 
   1099     /**
   1100      * Exposed for unit testing
   1101      */
   1102     protected void setTimezone(String timezone) {
   1103         mTimezone = timezone;
   1104     }
   1105 
   1106     /**
   1107      * Exposed for unit testing
   1108      */
   1109     protected void setDisableDialing(boolean disableDialing) {
   1110         mDisableDialing = disableDialing;
   1111     }
   1112 
   1113     /**
   1114      * Exposed for unit testing
   1115      */
   1116     protected void setDefaultSimData(Integer defaultSimData) {
   1117         mDefaultSimData = defaultSimData;
   1118     }
   1119 
   1120     /**
   1121      * Exposed for unit testing
   1122      */
   1123     protected void setDefaultSimVoice(Integer defaultSimVoice) {
   1124         mDefaultSimVoice = defaultSimVoice;
   1125     }
   1126 
   1127     /**
   1128      * Exposed for unit testing
   1129      */
   1130     protected void setDefaultSimSms(Integer defaultSimSms) {
   1131         mDefaultSimSms = defaultSimSms;
   1132     }
   1133 
   1134     /**
   1135      * Exposed for unit testing
   1136      */
   1137     protected void setDisableAudio(boolean disable) {
   1138         mDisableAudio = disable;
   1139     }
   1140 
   1141     /**
   1142      * Exposed for unit testing
   1143      */
   1144     protected void setTestHarness(boolean setTestHarness) {
   1145         mSetTestHarness = setTestHarness;
   1146     }
   1147 
   1148     /**
   1149      * Exposed for unit testing
   1150      */
   1151     protected void setDisableDalvikVerifier(boolean disableDalvikVerifier) {
   1152         mDisableDalvikVerifier = disableDalvikVerifier;
   1153     }
   1154 
   1155     /**
   1156      * Exposed for unit testing
   1157      */
   1158     protected void setLocalDataPath(File path) {
   1159         mLocalDataFile = path;
   1160     }
   1161 
   1162     /**
   1163      * Exposed for unit testing
   1164      */
   1165     protected void setMinExternalStorageKb(long storageKb) {
   1166         mMinExternalStorageKb = storageKb;
   1167     }
   1168 
   1169     /**
   1170      * Exposed for unit testing
   1171      */
   1172     protected void setProperty(String key, String value) {
   1173         mSetProps.put(key, value);
   1174     }
   1175 
   1176     /**
   1177      * Exposed for unit testing
   1178      * @deprecated use {@link #setMinExternalStorageKb(long)} instead.
   1179      */
   1180     @Deprecated
   1181     protected void setDeprecatedMinExternalStoreSpace(long storeSpace) {
   1182         mDeprecatedMinExternalStoreSpace = storeSpace;
   1183     }
   1184 
   1185     /**
   1186      * Exposed for unit testing
   1187      * @deprecated use {@link #setDisableAudio(boolean)} instead.
   1188      */
   1189     @Deprecated
   1190     protected void setDeprecatedAudioSilent(boolean silent) {
   1191         mDeprecatedSetAudioSilent = silent;
   1192     }
   1193 
   1194     /**
   1195      * Exposed for unit testing
   1196      * @deprecated use {@link #setProperty(String, String)} instead.
   1197      */
   1198     @Deprecated
   1199     protected void setDeprecatedSetProp(String prop) {
   1200         mDeprecatedSetProps.add(prop);
   1201     }
   1202 }
   1203