diff options
author | Eric Rowe <erowe@google.com> | 2015-05-08 17:10:29 -0700 |
---|---|---|
committer | Eric Rowe <erowe@google.com> | 2015-06-10 15:33:19 -0700 |
commit | af68aaa5ea53d4df1eb9afcf587af408d1096633 (patch) | |
tree | a528cd2db3022bf7409257bbadaa8de43c2c903b /src/com/android/tradefed/targetprep | |
parent | df0aee4a75684b944b749e4cdd14dd50037385c2 (diff) | |
download | tradefederation-af68aaa5ea53d4df1eb9afcf587af408d1096633.tar.gz |
Merge DeviceSetup and DeviceSetup2
Change-Id: I3b0a86de0811298b99438fb01aa020b3724bf003
Diffstat (limited to 'src/com/android/tradefed/targetprep')
-rw-r--r-- | src/com/android/tradefed/targetprep/DeviceSetup.java | 1149 | ||||
-rw-r--r-- | src/com/android/tradefed/targetprep/DeviceSetup2.java | 740 |
2 files changed, 940 insertions, 949 deletions
diff --git a/src/com/android/tradefed/targetprep/DeviceSetup.java b/src/com/android/tradefed/targetprep/DeviceSetup.java index 6ec9d041b..ae27b0e8b 100644 --- a/src/com/android/tradefed/targetprep/DeviceSetup.java +++ b/src/com/android/tradefed/targetprep/DeviceSetup.java @@ -17,263 +17,698 @@ package com.android.tradefed.targetprep; import com.android.ddmlib.IDevice; -import com.android.ddmlib.Log; import com.android.tradefed.build.IBuildInfo; import com.android.tradefed.config.Option; import com.android.tradefed.config.OptionClass; import com.android.tradefed.device.DeviceNotAvailableException; import com.android.tradefed.device.ITestDevice; import com.android.tradefed.log.LogUtil.CLog; +import com.android.tradefed.util.MultiMap; import java.io.File; import java.util.ArrayList; import java.util.Collection; -import java.util.regex.Pattern; +import java.util.HashMap; +import java.util.List; +import java.util.Map; /** * A {@link ITargetPreparer} that configures a device for testing based on provided {@link Option}s. - * <p/> + * <p> * Requires a device where 'adb root' is possible, typically a userdebug build type. - * <p/> - * Should be performed *after* a new build is flashed. - * @deprecated Use {@link DeviceSetup2} + * </p><p> + * Should be performed <strong>after</strong> a new build is flashed. + * </p> */ -@Deprecated @OptionClass(alias = "device-setup") public class DeviceSetup implements ITargetPreparer, ITargetCleaner { - private static final String LOG_TAG = "DeviceSetup"; - private static final Pattern RELEASE_BUILD_NAME_PATTERN = - Pattern.compile("[A-Z]{3}\\d{2}[A-Z]?"); - private static final String PERSIST_PREFIX = "persist."; + /** + * Enum used to record ON/OFF state with a IGNORE no-op state. + */ + public enum BinaryState { + IGNORE, + ON, + OFF; + } + + // Networking + @Option(name = "airplane-mode", + description = "Turn airplane mode on or off") + protected BinaryState mAirplaneMode = BinaryState.IGNORE; + // ON: settings put global airplane_mode_on 1 + // am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true + // OFF: settings put global airplane_mode_on 0 + // am broadcast -a android.intent.action.AIRPLANE_MODE --ez state false + + @Option(name = "wifi", + description = "Turn wifi on or off") + protected BinaryState mWifi = BinaryState.IGNORE; + // ON: settings put global wifi_on 1 + // svc wifi enable + // OFF: settings put global wifi_off 0 + // svc wifi disable + + @Option(name = "wifi-network", + description = "The SSID of the network to connect to. Will only attempt to " + + "connect to a network if set") + protected String mWifiSsid = null; + + @Option(name = "wifi-psk", + description = "The passphrase used to connect to a secured network") + protected String mWifiPsk = null; + + @Option(name = "wifi-watchdog", + description = "Turn wifi watchdog on or off") + protected BinaryState mWifiWatchdog = BinaryState.IGNORE; + // ON: settings put global wifi_watchdog 1 + // OFF: settings put global wifi_watchdog 0 + + @Option(name = "wifi-scan-always-enabled", + description = "Turn wifi scan always enabled on or off") + protected BinaryState mWifiScanAlwaysEnabled = BinaryState.IGNORE; + // ON: settings put global wifi_scan_always_enabled 1 + // OFF: settings put global wifi_scan_always_enabled 0 + + @Option(name = "ethernet", + description = "Turn ethernet on or off") + protected BinaryState mEthernet = BinaryState.IGNORE; + // ON: ifconfig eth0 up + // OFF: ifconfig eth0 down + + @Option(name = "bluetooth", + description = "Turn bluetooth on or off") + protected BinaryState mBluetooth = BinaryState.IGNORE; + // ON: service call bluetooth_manager 6 + // OFF: service call bluetooth_manager 8 + + // Screen + @Option(name = "screen-adaptive-brightness", + description = "Turn screen adaptive brightness on or off") + protected BinaryState mScreenAdaptiveBrightness = BinaryState.IGNORE; + // ON: settings put system screen_brightness_mode 1 + // OFF: settings put system screen_brightness_mode 0 + + @Option(name = "screen-brightness", + description = "Set the screen brightness. This is uncalibrated from product to product") + protected Integer mScreenBrightness = null; + // settings put system screen_brightness $N + + @Option(name = "screen-always-on", + description = "Turn 'screen always on' on or off. If ON, then screen-timeout-secs " + + "must be unset. Will only work when the device is plugged in") + protected BinaryState mScreenAlwaysOn = BinaryState.ON; + // ON: svc power stayon true + // OFF: svc power stayon false + + @Option(name = "screen-timeout-secs", + description = "Set the screen timeout in seconds. If set, then screen-always-on must " + + "be OFF or DEFAULT") + protected Long mScreenTimeoutSecs = null; + // settings put system screen_off_timeout $(N * 1000) + + @Option(name = "screen-ambient-mode", + description = "Turn screen ambient mode on or off") + protected BinaryState mScreenAmbientMode = BinaryState.IGNORE; + // ON: settings put secure doze_enabled 1 + // OFF: settings put secure doze_enabled 0 + + @Option(name = "wake-gesture", + description = "Turn wake gesture on or off") + protected BinaryState mWakeGesture = BinaryState.IGNORE; + // ON: settings put secure wake_gesture_enabled 1 + // OFF: settings put secure wake_gesture_enabled 0 + + @Option(name = "screen-saver", + description = "Turn screen saver on or off") + protected BinaryState mScreenSaver = BinaryState.IGNORE; + // ON: settings put secure screensaver_enabled 1 + // OFF: settings put secure screensaver_enabled 0 + + @Option(name = "notification-led", + description = "Turn the notification led on or off") + protected BinaryState mNotificationLed = BinaryState.IGNORE; + // ON: settings put system notification_light_pulse 1 + // OFF: settings put system notification_light_pulse 0 + + // Media + @Option(name = "trigger-media-mounted", + description = "Trigger a MEDIA_MOUNTED broadcast") + protected boolean mTriggerMediaMounted = false; + // am broadcast -a android.intent.action.MEDIA_MOUNTED -d file://${EXTERNAL_STORAGE} + + // Location + @Option(name = "location-gps", + description = "Turn the GPS location on or off") + protected BinaryState mLocationGps = BinaryState.IGNORE; + // ON: settings put secure location_providers_allowed +gps + // OFF: settings put secure location_providers_allowed -gps + + @Option(name = "location-network", + description = "Turn the network location on or off") + protected BinaryState mLocationNetwork = BinaryState.IGNORE; + // ON: settings put secure location_providers_allowed +network + // OFF: settings put secure location_providers_allowed -network + + // Sensor + @Option(name = "auto-rotate", + description = "Turn auto rotate on or off") + protected BinaryState mAutoRotate = BinaryState.IGNORE; + // ON: settings put system accelerometer_rotation 1 + // OFF: settings put system accelerometer_rotation 0 + + // Power + @Option(name = "battery-saver-mode", + description = "Turn battery saver mode manually on or off. If OFF but battery is " + + "less battery-saver-trigger, the device will still go into battery saver mode") + protected BinaryState mBatterySaver = BinaryState.IGNORE; + // ON: dumpsys battery set usb 0 + // settings put global low_power 1 + // OFF: settings put global low_power 0 - @Option(name="wifi-network", description="the name of wifi network to connect to.") - private String mWifiNetwork = null; + @Option(name = "battery-saver-trigger", + description = "Set the battery saver trigger level. Should be [1-99] to enable, or " + + "0 to disable automatic battery saver mode") + protected Integer mBatterySaverTrigger = null; + // settings put global low_power_trigger_level $N - @Option(name="wifi-psk", description="WPA-PSK passphrase of wifi network to connect to.") - private String mWifiPsk = null; + // Time + @Option(name = "auto-update-time", + description = "Turn auto update time on or off") + protected BinaryState mAutoUpdateTime = BinaryState.IGNORE; + // ON: settings put system auto_time 1 + // OFF: settings put system auto_time 0 - @Option(name = "disconnect-wifi-after-test", description = - "disconnect from wifi network after test completes.") + @Option(name = "auto-update-timezone", + description = "Turn auto update timezone on or off") + protected BinaryState mAutoUpdateTimezone = BinaryState.IGNORE; + // ON: settings put system auto_timezone 1 + // OFF: settings put system auto_timezone 0 + + // Calling + @Option(name = "disable-dialing", + description = "Disable dialing") + protected boolean mDisableDialing = true; + // setprop ro.telephony.disable-call true" + + @Option(name = "default-sim-data", + description = "Set the default sim card slot for data. Leave unset for single SIM " + + "devices") + protected Integer mDefaultSimData = null; + // settings put global multi_sim_data_call $N + + @Option(name = "default-sim-voice", + description = "Set the default sim card slot for voice calls. Leave unset for single " + + "SIM devices") + protected Integer mDefaultSimVoice = null; + // settings put global multi_sim_voice_call $N + + @Option(name = "default-sim-sms", + description = "Set the default sim card slot for SMS. Leave unset for single SIM " + + "devices") + protected Integer mDefaultSimSms = null; + // settings put global multi_sim_sms $N + + // Audio + private static final boolean DEFAULT_DISABLE_AUDIO = true; + @Option(name = "disable-audio", + description = "Disable the audio") + protected boolean mDisableAudio = DEFAULT_DISABLE_AUDIO; + // setprop ro.audio.silent 1" + + // Test harness + @Option(name = "disable", + description = "Disable the device setup") + protected boolean mDisable = false; + + @Option(name = "force-skip-system-props", + description = "Force setup to not modify any device system properties. All other " + + "system property options will be ignored") + protected boolean mForceSkipSystemProps = false; + + @Option(name = "force-skip-settings", + description = "Force setup to not modify any device settings. All other setting " + + "options will be ignored.") + protected boolean mForceSkipSettings = false; + + @Option(name = "force-skip-run-commands", + description = "Force setup to not run any additional commands. All other commands " + + "will be ignored.") + protected boolean mForceSkipRunCommands = false; + + @Option(name = "set-test-harness", + description = "Set the read-only test harness flag on boot") + protected boolean mSetTestHarness = true; + // setprop ro.monkey 1 + // setprop ro.test_harness 1 + + @Option(name = "disable-dalvik-verifier", + description = "Disable the dalvik verifier on device. Allows package-private " + + "framework tests to run.") + protected boolean mDisableDalvikVerifier = false; + // setprop dalvik.vm.dexopt-flags v=n + + @Option(name = "set-property", + description = "Set the specified property on boot. Option may be repeated but only " + + "the last value for a given key will be set.") + protected Map<String, String> mSetProps = new HashMap<>(); + + @Option(name = "set-system-setting", + description = "Change a system (non-secure) setting. Option may be repeated and all " + + "key/value pairs will be set in order.") + // Use a Multimap since it is possible for a setting to have multiple values for the same key + protected MultiMap<String, String> mSystemSettings = new MultiMap<>(); + + @Option(name = "set-secure-setting", + description = "Change a secure setting. Option may be repeated and all key/value " + + "pairs will be set in order.") + // Use a Multimap since it is possible for a setting to have multiple values for the same key + protected MultiMap<String, String> mSecureSettings = new MultiMap<>(); + + @Option(name = "set-global-setting", + description = "Change a global setting. Option may be repeated and all key/value " + + "pairs will be set in order.") + // Use a Multimap since it is possible for a setting to have multiple values for the same key + protected MultiMap<String, String> mGlobalSettings = new MultiMap<>(); + + protected List<String> mRunCommandBeforeSettings = new ArrayList<>(); + + @Option(name = "run-command", + description = "Run an adb shell command. Option may be repeated") + protected List<String> mRunCommandAfterSettings = new ArrayList<>(); + + @Option(name = "disconnect-wifi-after-test", + description = "Disconnect from wifi network after test completes.") private boolean mDisconnectWifiAfterTest = true; - @Option(name="min-external-store-space", description="the minimum amount of free space in KB" + - " that must be present on device's external storage.") - // require 500K by default. Values <=0 mean external storage is not required - private long mMinExternalStoreSpace = 500; + private static final long DEFAULT_MIN_EXTERNAL_STORAGE_KB = 500; + @Option(name = "min-external-storage-kb", + description="The minimum amount of free space in KB that must be present on device's " + + "external storage.") + protected long mMinExternalStorageKb = DEFAULT_MIN_EXTERNAL_STORAGE_KB; @Option(name = "local-data-path", - description = "optional local file path of test data to sync to device's external " + + description = "Optional local file path of test data to sync to device's external " + "storage. Use --remote-data-path to set remote location.") - private File mLocalDataFile = null; + protected File mLocalDataFile = null; @Option(name = "remote-data-path", - description = "optional file path on device's external storage to sync test data. " + + description = "Optional file path on device's external storage to sync test data. " + "Must be used with --local-data-path.") - private String mRemoteDataPath = null; - - @Option(name = "force-skip-system-props", description = - "force setup to not modify any device system properties. " + - "All other system property options will be ignored.") - private boolean mForceNoSystemProps = false; + protected String mRemoteDataPath = null; - @Option(name="disable-dialing", description="set disable dialing property on boot.") - private boolean mDisableDialing = true; + // Deprecated options follow + @Option(name = "min-external-store-space", + description = "deprecated, use option min-external-storage-kb. The minimum amount of " + + "free space in KB that must be present on device's external storage.") + @Deprecated + private long mDeprecatedMinExternalStoreSpace = DEFAULT_MIN_EXTERNAL_STORAGE_KB; - @Option(name="set-test-harness", description="set the read-only test harness flag on boot. " + - "Requires adb root.") - private boolean mSetTestHarness = true; + @Option(name = "audio-silent", + description = "deprecated, use option disable-audio. set ro.audio.silent on boot.") + @Deprecated + private boolean mDeprecatedSetAudioSilent = DEFAULT_DISABLE_AUDIO; - @Option(name="audio-silent", description="set ro.audio.silent on boot.") - private boolean mSetAudioSilent = true; + @Option(name = "setprop", + description = "deprecated, use option set-property. set the specified property on " + + "boot. Format: --setprop key=value. May be repeated.") + @Deprecated + private Collection<String> mDeprecatedSetProps = new ArrayList<String>(); - @Option(name="disable-dalvik-verifier", description="disable the dalvik verifier on device. " - + "Allows package-private framework tests to run.") - private boolean mDisableDalvikVerifier = false; - - @Option(name="setprop", description="set the specified property on boot. " + - "Format: --setprop key=value. May be repeated.") - private Collection<String> mSetProps = new ArrayList<String>(); + private static final String PERSIST_PREFIX = "persist."; /** - * Sets the local data path to use - * <p/> - * Exposed for unit testing + * {@inheritDoc} */ - void setLocalDataPath(File localPath) { - mLocalDataFile = localPath; - } + @Override + public void setUp(ITestDevice device, IBuildInfo buildInfo) throws DeviceNotAvailableException, + TargetSetupError { + if (mDisable) { + return; + } - /** - * Sets the remote data path to use - * <p/> - * Exposed for unit testing - */ - void setRemoteDataPath(String remotePath) { - mRemoteDataPath = remotePath; - } + CLog.i("Performing setup on %s", device.getSerialNumber()); - /** - * Sets the wifi network ssid to setup. - * <p/> - * Exposed for unit testing - */ - void setWifiNetwork(String network) { - mWifiNetwork = network; + if (!device.enableAdbRoot()) { + throw new TargetSetupError(String.format("Failed to enable adb root on %s", + device.getSerialNumber())); + } + + // Convert deprecated options into current options + processDeprecatedOptions(); + // Convert options into settings and run commands + processOptions(device); + // Change system props (will reboot device) + changeSystemProps(device); + // Run commands designated to be run before changing settings + runCommands(device, mRunCommandBeforeSettings); + // Change settings + changeSettings(device); + // Connect wifi after settings since this may take a while + connectWifi(device); + // Sync data after settings since this may take a while + syncTestData(device); + // Run commands designated to be run after changing settings + runCommands(device, mRunCommandAfterSettings); + // Throw an error if there is not enough storage space + checkExternalStoreSpace(device); + + device.clearErrorDialogs(); } /** - * Sets the minimum external store space - * <p/> - * Exposed for unit testing + * {@inheritDoc} */ - void setMinExternalStoreSpace(int minKBytes) { - mMinExternalStoreSpace = minKBytes; + @Override + public void tearDown(ITestDevice device, IBuildInfo buildInfo, Throwable e) + throws DeviceNotAvailableException { + if (mDisable) { + return; + } + + CLog.i("Performing teardown on %s", device.getSerialNumber()); + + if (e instanceof DeviceFailedToBootError) { + CLog.d("boot failure: skipping teardown"); + return; + } + + // Only try to disconnect if wifi ssid is set since isWifiEnabled() is a heavy operation + // which should be avoided when possible + if (mDisconnectWifiAfterTest && mWifiSsid != null && device.isWifiEnabled()) { + boolean result = device.disconnectFromWifi(); + if (result) { + CLog.i("Successfully disconnected from wifi network on %s", + device.getSerialNumber()); + } else { + CLog.w("Failed to disconnect from wifi network on %s", device.getSerialNumber()); + } + } } /** - * Adds a property to the list of properties to set - * <p/> - * Exposed for unit testing + * Processes the deprecated options converting them into the currently used options. + * <p> + * This method should be run before any other processing methods. Will throw a + * {@link TargetSetupError} if the deprecated option overrides a specified non-deprecated + * option. + * </p> + * @throws TargetSetupError if there is a conflict */ - void addSetProperty(String prop) { - mSetProps.add(prop); + public void processDeprecatedOptions() throws TargetSetupError { + if (mDeprecatedMinExternalStoreSpace != DEFAULT_MIN_EXTERNAL_STORAGE_KB) { + if (mMinExternalStorageKb != DEFAULT_MIN_EXTERNAL_STORAGE_KB) { + throw new TargetSetupError("Deprecated option min-external-store-space conflicts " + + "with option min-external-storage-kb"); + } + mMinExternalStorageKb = mDeprecatedMinExternalStoreSpace; + } + + if (mDeprecatedSetAudioSilent != DEFAULT_DISABLE_AUDIO) { + if (mDisableAudio != DEFAULT_DISABLE_AUDIO) { + throw new TargetSetupError("Deprecated option audio-silent conflicts with " + + "option disable-audio"); + } + mDisableAudio = mDeprecatedSetAudioSilent; + } + + if (!mDeprecatedSetProps.isEmpty()) { + if (!mSetProps.isEmpty()) { + throw new TargetSetupError("Deprecated option setprop conflicts with option " + + "set-property "); + } + for (String prop : mDeprecatedSetProps) { + String[] parts = prop.split("=", 2); + String key = parts[0].trim(); + String value = parts.length == 2 ? parts[1].trim() : ""; + mSetProps.put(key, value); + } + } } /** - * {@inheritDoc} + * Process all the {@link Option}s and turn them into system props, settings, or run commands. + * Does not run any commands on the device at this time. + * <p> + * Exposed so that children classes may override this. + * </p> + * + * @param device The {@link ITestDevice} + * @throws DeviceNotAvailableException if the device is not available + * @throws TargetSetupError if the {@link Option}s conflict */ - @Override - public void setUp(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError, - DeviceNotAvailableException, BuildError { - Log.i(LOG_TAG, String.format("Performing setup on %s", device.getSerialNumber())); + public void processOptions(ITestDevice device) throws DeviceNotAvailableException, + TargetSetupError { + setSettingForBinaryState(mWifi, mGlobalSettings, "wifi_on", "1", "0"); + setCommandForBinaryState(mWifi, mRunCommandAfterSettings, + "svc wifi enable", "svc wifi disable"); - if (!device.enableAdbRoot()) { - throw new TargetSetupError(String.format("failed to enable adb root on %s", - device.getSerialNumber())); + setSettingForBinaryState(mWifiWatchdog, mGlobalSettings, "wifi_watchdog", "1", "0"); + + setSettingForBinaryState(mWifiScanAlwaysEnabled, mGlobalSettings, + "wifi_scan_always_enabled", "1", "0"); + + setCommandForBinaryState(mEthernet, mRunCommandAfterSettings, + "ifconfig eth0 up", "ifconfig eth0 down"); + + setCommandForBinaryState(mBluetooth, mRunCommandAfterSettings, + "service call bluetooth_manager 6", "service call bluetooth_manager 8"); + + if (mScreenBrightness != null && BinaryState.ON.equals(mScreenAdaptiveBrightness)) { + throw new TargetSetupError("Option screen-brightness cannot be set when " + + "screen-adaptive-brightness is set to ON"); } - configureSystemProperties(device); + setSettingForBinaryState(mScreenAdaptiveBrightness, mSystemSettings, + "screen_brightness_mode", "1", "0"); - changeSettings(device); + if (mScreenBrightness != null) { + mSystemSettings.put("screen_brightness", Integer.toString(mScreenBrightness)); + } - keepScreenOn(device); + setCommandForBinaryState(mScreenAlwaysOn, mRunCommandBeforeSettings, + "svc power stayon true", "svc power stayon false"); - connectToWifi(device); + if (mScreenTimeoutSecs != null) { + mSystemSettings.put("screen_off_timeout", Long.toString(mScreenTimeoutSecs * 1000)); + } - syncTestData(device); + setSettingForBinaryState(mScreenAmbientMode, mSecureSettings, "doze_enabled", "1", "0"); - checkExternalStoreSpace(device); + setSettingForBinaryState(mWakeGesture, mSecureSettings, "wake_gesture_enabled", "1", "0"); - device.clearErrorDialogs(); - } + setSettingForBinaryState(mScreenSaver, mSecureSettings, "screensaver_enabled", "1", "0"); - /** - * Configures device system properties. - * <p/> - * Device will be rebooted if any property is changed. - * - * @param device - * @throws TargetSetupError - * @throws DeviceNotAvailableException - */ - private void configureSystemProperties(ITestDevice device) throws TargetSetupError, - DeviceNotAvailableException { - if (mForceNoSystemProps) { - return; + setSettingForBinaryState(mNotificationLed, mSystemSettings, + "notification_light_pulse", "1", "0"); + + if (mTriggerMediaMounted) { + mRunCommandAfterSettings.add("am broadcast -a android.intent.action.MEDIA_MOUNTED -d " + + "file://${EXTERNAL_STORAGE}"); + } + + setSettingForBinaryState(mLocationGps, mSecureSettings, + "location_providers_allowed", "+gps", "-gps"); + + setSettingForBinaryState(mLocationNetwork, mSecureSettings, + "location_providers_allowed", "+network", "-network"); + + setSettingForBinaryState(mAutoRotate, mSystemSettings, "accelerometer_rotation", "1", "0"); + + setCommandForBinaryState(mBatterySaver, mRunCommandBeforeSettings, + "dumpsys battery set usb 0", null); + setSettingForBinaryState(mBatterySaver, mGlobalSettings, "low_power", "1", "0"); + + if (mBatterySaverTrigger != null) { + mGlobalSettings.put("low_power_trigger_level", Integer.toString(mBatterySaverTrigger)); } - // build the local.prop file contents with properties to change - StringBuilder propertyBuilder = new StringBuilder(); + + setSettingForBinaryState(mAutoUpdateTime, mSystemSettings, "auto_time", "1", "0"); + + setSettingForBinaryState(mAutoUpdateTimezone, mSystemSettings, "auto_timezone", "1", "0"); + if (mDisableDialing) { - propertyBuilder.append("ro.telephony.disable-call=true\n"); + mSetProps.put("ro.telephony.disable-call", "true"); + } + + if (mDefaultSimData != null) { + mGlobalSettings.put("multi_sim_data_call", Integer.toString(mDefaultSimData)); } + + if (mDefaultSimVoice != null) { + mGlobalSettings.put("multi_sim_voice_call", Integer.toString(mDefaultSimVoice)); + } + + if (mDefaultSimSms != null) { + mGlobalSettings.put("multi_sim_sms", Integer.toString(mDefaultSimSms)); + } + + if (mDisableAudio) { + mSetProps.put("ro.audio.silent", "1"); + } + if (mSetTestHarness) { // set both ro.monkey and ro.test_harness, for compatibility with older platforms - propertyBuilder.append("ro.monkey=1\n"); - propertyBuilder.append("ro.test_harness=1\n"); - } - if (mSetAudioSilent) { - propertyBuilder.append("ro.audio.silent=1\n"); + mSetProps.put("ro.monkey", "1"); + mSetProps.put("ro.test_harness", "1"); } + if (mDisableDalvikVerifier) { - propertyBuilder.append("dalvik.vm.dexopt-flags = v=n\n"); + mSetProps.put("dalvik.vm.dexopt-flags", "v=n"); } - for (String prop : mSetProps) { - if (prop.startsWith(PERSIST_PREFIX)) { - prop = prop.replace('=', ' '); - device.executeShellCommand("setprop " + prop); + } + + /** + * Change the system properties on the device. + * + * @param device The {@link ITestDevice} + * @throws DeviceNotAvailableException if the device is not available + * @throws TargetSetupError if there was a failure setting the system properties + */ + private void changeSystemProps(ITestDevice device) throws DeviceNotAvailableException, + TargetSetupError { + if (mForceSkipSystemProps) { + CLog.d("Skipping system props due to force-skip-system-props"); + return; + } + + StringBuilder sb = new StringBuilder(); + for (Map.Entry<String, String> prop : mSetProps.entrySet()) { + if (prop.getKey().startsWith(PERSIST_PREFIX)) { + String command = String.format("setprop \"%s\" \"%s\"", + prop.getKey(), prop.getValue()); + device.executeShellCommand(command); } else { - propertyBuilder.append(prop); - propertyBuilder.append("\n"); + sb.append(String.format("%s=%s\n", prop.getKey(), prop.getValue())); } } - if (propertyBuilder.length() > 0) { - // create a local.prop file, and push it to /data/local.prop - boolean result = device.pushString(propertyBuilder.toString(), "/data/local.prop"); - if (!result) { - throw new TargetSetupError(String.format("Failed to push file to %s", - device.getSerialNumber())); - } - // Set reasonable permissions for /data/local.prop - device.executeShellCommand("chmod 644 /data/local.prop"); - Log.i(LOG_TAG, String.format( - "Setup requires system property change. Reboot of %s required", + + if (sb.length() == 0) { + return; + } + + boolean result = device.pushString(sb.toString(), "/data/local.prop"); + if (!result) { + throw new TargetSetupError(String.format("Failed to push /data/local.prop to %s", device.getSerialNumber())); - device.reboot(); } + // Set reasonable permissions for /data/local.prop + device.executeShellCommand("chmod 644 /data/local.prop"); + CLog.i("Rebooting %s due to system property change", device.getSerialNumber()); + device.reboot(); } /** - * Change additional settings for the device. This is intended to be overridden by subclass for - * additional change of settings. + * Change the settings on the device. + * <p> + * Exposed so children classes may override. + * </p> * - * @param device - * @throws DeviceNotAvailableException - * @throws TargetSetupError + * @param device The {@link ITestDevice} + * @throws DeviceNotAvailableException if the device is not available + * @throws TargetSetupError if there was a failure setting the settings */ - protected void changeSettings(ITestDevice device) throws DeviceNotAvailableException, + public void changeSettings(ITestDevice device) throws DeviceNotAvailableException, TargetSetupError { - // ignore - } + if (mForceSkipSettings) { + CLog.d("Skipping settings due to force-skip-setttings"); + return; + } - /** - * @param device - * @throws DeviceNotAvailableException - */ - private void keepScreenOn(ITestDevice device) throws DeviceNotAvailableException { - device.executeShellCommand("svc power stayon true"); + if (mSystemSettings.isEmpty() && mSecureSettings.isEmpty() && mGlobalSettings.isEmpty() && + BinaryState.IGNORE.equals(mAirplaneMode)) { + CLog.d("No settings to change"); + return; + } + + if (device.getApiLevel() < 22) { + throw new TargetSetupError(String.format("Changing setting not supported on %s, " + + "must be API 22+", device.getSerialNumber())); + } + + // Special case airplane mode since it needs to be set before other connectivity settings + // For example, it is possible to enable airplane mode and then turn wifi on + String command = "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state %s"; + switch (mAirplaneMode) { + case ON: + CLog.d("Changing global setting airplane_mode_on to 1"); + device.executeShellCommand("settings put global \"airplane_mode_on\" \"1\""); + if (!mForceSkipRunCommands) { + device.executeShellCommand(String.format(command, "true")); + } + break; + case OFF: + CLog.d("Changing global setting airplane_mode_on to 0"); + device.executeShellCommand("settings put global \"airplane_mode_on\" \"0\""); + if (!mForceSkipRunCommands) { + device.executeShellCommand(String.format(command, "false")); + } + break; + case IGNORE: + // No-op + break; + } + + String settingCommand = "settings put %s \"%s\" \"%s\""; + for (String key : mSystemSettings.keySet()) { + for (String value : mSystemSettings.get(key)) { + CLog.d("Changing system setting %s to %s", key, value); + device.executeShellCommand(String.format(settingCommand, "system", key, value)); + } + } + for (String key : mSecureSettings.keySet()) { + for (String value : mSecureSettings.get(key)) { + CLog.d("Changing secure setting %s to %s", key, value); + device.executeShellCommand(String.format(settingCommand, "secure", key, value)); + } + } + + for (String key : mGlobalSettings.keySet()) { + for (String value : mGlobalSettings.get(key)) { + CLog.d("Changing global setting %s to %s", key, value); + device.executeShellCommand(String.format(settingCommand, "global", key, value)); + } + } } /** - * Check that device external store has the required space + * Execute additional commands on the device. * - * @param device - * @throws DeviceNotAvailableException if device does not have required space + * @param device The {@link ITestDevice} + * @param commands The list of commands to run + * @throws DeviceNotAvailableException if the device is not available + * @throws TargetSetupError if there was a failure setting the settings */ - private void checkExternalStoreSpace(ITestDevice device) throws DeviceNotAvailableException { - if (mMinExternalStoreSpace > 0) { - long freeSpace = device.getExternalStoreFreeSpace(); - if (freeSpace < mMinExternalStoreSpace) { - throw new DeviceNotAvailableException(String.format( - "External store free space %dK is less than required %dK for device %s", - freeSpace , mMinExternalStoreSpace, device.getSerialNumber())); - } + private void runCommands(ITestDevice device, List<String> commands) + throws DeviceNotAvailableException, TargetSetupError { + if (mForceSkipRunCommands) { + CLog.d("Skipping run commands due to force-skip-run-commands"); + return; + } + + for (String command : commands) { + device.executeShellCommand(command); } } /** - * Connect to wifi network if specified + * Connects device to Wifi if SSID is specified. * - * @param device - * @throws DeviceNotAvailableException - * @throws TargetSetupError if failed to connect to wifi + * @param device The {@link ITestDevice} + * @throws DeviceNotAvailableException if the device is not available + * @throws TargetSetupError if there was a failure setting the settings */ - private void connectToWifi(ITestDevice device) throws DeviceNotAvailableException, + private void connectWifi(ITestDevice device) throws DeviceNotAvailableException, TargetSetupError { - if (mWifiNetwork != null) { - if (!device.connectToWifiNetwork(mWifiNetwork, mWifiPsk)) { + if (mForceSkipRunCommands) { + CLog.d("Skipping connect wifi due to force-skip-run-commands"); + return; + } + + if (mWifiSsid != null) { + if (!device.connectToWifiNetwork(mWifiSsid, mWifiPsk)) { throw new TargetSetupError(String.format( - "Failed to connect to wifi network %s on %s", mWifiNetwork, + "Failed to connect to wifi network %s on %s", mWifiSsid, device.getSerialNumber())); } } @@ -282,64 +717,360 @@ public class DeviceSetup implements ITargetPreparer, ITargetCleaner { /** * Syncs a set of test data files, specified via local-data-path, to devices external storage. * - * @param device the {@link ITestDevice} to sync data to + * @param device The {@link ITestDevice} + * @throws DeviceNotAvailableException if the device is not available * @throws TargetSetupError if data fails to sync */ - void syncTestData(ITestDevice device) throws TargetSetupError, DeviceNotAvailableException { - if (mLocalDataFile != null) { - if (!mLocalDataFile.exists() || !mLocalDataFile.isDirectory()) { - throw new TargetSetupError(String.format("local-data-path %s is not a directory", - mLocalDataFile.getAbsolutePath())); - - } - String fullRemotePath = device.getIDevice().getMountPoint(IDevice.MNT_EXTERNAL_STORAGE); - if (fullRemotePath == null) { - throw new TargetSetupError(String.format( - "failed to get external storage path on device %s", - device.getSerialNumber())); - } - if (mRemoteDataPath != null) { - fullRemotePath = String.format("%s/%s", fullRemotePath, mRemoteDataPath); - } - boolean result = device.syncFiles(mLocalDataFile, fullRemotePath); - if (!result) { - // TODO: get exact error code and respond accordingly - throw new TargetSetupError(String.format( - "failed to sync test data from local-data-path %s to %s on device %s", - mLocalDataFile.getAbsolutePath(), fullRemotePath, - device.getSerialNumber())); - } + private void syncTestData(ITestDevice device) throws DeviceNotAvailableException, + TargetSetupError { + if (mLocalDataFile == null) { + return; } - } - protected boolean isReleaseBuildName(String name) { - return RELEASE_BUILD_NAME_PATTERN.matcher(name).matches(); + if (!mLocalDataFile.exists() || !mLocalDataFile.isDirectory()) { + throw new TargetSetupError(String.format( + "local-data-path %s is not a directory", mLocalDataFile.getAbsolutePath())); + } + String fullRemotePath = device.getIDevice().getMountPoint(IDevice.MNT_EXTERNAL_STORAGE); + if (fullRemotePath == null) { + throw new TargetSetupError(String.format( + "failed to get external storage path on device %s", device.getSerialNumber())); + } + if (mRemoteDataPath != null) { + fullRemotePath = String.format("%s/%s", fullRemotePath, mRemoteDataPath); + } + boolean result = device.syncFiles(mLocalDataFile, fullRemotePath); + if (!result) { + // TODO: get exact error code and respond accordingly + throw new TargetSetupError(String.format( + "failed to sync test data from local-data-path %s to %s on device %s", + mLocalDataFile.getAbsolutePath(), fullRemotePath, device.getSerialNumber())); + } } /** - * {@inheritDoc} + * Check that device external store has the required space + * + * @param device The {@link ITestDevice} + * @throws DeviceNotAvailableException if the device is not available or if the device does not + * have the required space */ - @Override - public void tearDown(ITestDevice device, IBuildInfo buildInfo, Throwable e) - throws DeviceNotAvailableException { - Log.i(LOG_TAG, String.format("Performing teardown on %s", device.getSerialNumber())); - - if (e instanceof DeviceFailedToBootError) { - CLog.d("boot failure: skipping wifi teardown"); + private void checkExternalStoreSpace(ITestDevice device) throws DeviceNotAvailableException { + if (mMinExternalStorageKb <= 0) { return; } - if (mWifiNetwork != null && mDisconnectWifiAfterTest) { - disconnectFromWifi(device); + + long freeSpace = device.getExternalStoreFreeSpace(); + if (freeSpace < mMinExternalStorageKb) { + throw new DeviceNotAvailableException(String.format( + "External store free space %dK is less than required %dK for device %s", + freeSpace , mMinExternalStorageKb, device.getSerialNumber())); } } - private void disconnectFromWifi(ITestDevice device) throws DeviceNotAvailableException { - if (device.isWifiEnabled()) { - if (!device.disconnectFromWifi()) { - CLog.w("Failed to disconnect from wifi network on %s", device.getSerialNumber()); - return; - } - CLog.i("Successfully disconnected from wifi network on %s", device.getSerialNumber()); + /** + * Helper method to add an ON/OFF setting to a setting map. + * + * @param state The {@link BinaryState} + * @param settingsMap The {@link MultiMap} used to store the settings. + * @param setting The setting key + * @param onValue The value if ON + * @param offValue The value if OFF + */ + public static void setSettingForBinaryState(BinaryState state, + MultiMap<String, String> settingsMap, String setting, String onValue, String offValue) { + switch (state) { + case ON: + settingsMap.put(setting, onValue); + break; + case OFF: + settingsMap.put(setting, offValue); + break; + case IGNORE: + // Do nothing + break; } } + + /** + * Helper method to add an ON/OFF run command to be executed on the device. + * + * @param state The {@link BinaryState} + * @param commands The list of commands to add the on or off command to. + * @param onCommand The command to run if ON. Ignored if the command is {@code null} + * @param offCommand The command to run if OFF. Ignored if the command is {@code null} + */ + public static void setCommandForBinaryState(BinaryState state, List<String> commands, + String onCommand, String offCommand) { + switch (state) { + case ON: + if (onCommand != null) { + commands.add(onCommand); + } + break; + case OFF: + if (offCommand != null) { + commands.add(offCommand); + } + break; + case IGNORE: + // Do nothing + break; + } + } + + /** + * Exposed for unit testing + */ + protected void setAirplaneMode(BinaryState airplaneMode) { + mAirplaneMode = airplaneMode; + } + + /** + * Exposed for unit testing + */ + protected void setWifi(BinaryState wifi) { + mWifi = wifi; + } + + /** + * Exposed for unit testing + */ + protected void setWifiNetwork(String wifiNetwork) { + mWifiSsid = wifiNetwork; + } + + /** + * Exposed for unit testing + */ + protected void setWifiWatchdog(BinaryState wifiWatchdog) { + mWifiWatchdog = wifiWatchdog; + } + + /** + * Exposed for unit testing + */ + protected void setWifiScanAlwaysEnabled(BinaryState wifiScanAlwaysEnabled) { + mWifiScanAlwaysEnabled = wifiScanAlwaysEnabled; + } + + /** + * Exposed for unit testing + */ + protected void setEthernet(BinaryState ethernet) { + mEthernet = ethernet; + } + + /** + * Exposed for unit testing + */ + protected void setBluetooth(BinaryState bluetooth) { + mBluetooth = bluetooth; + } + + /** + * Exposed for unit testing + */ + protected void setScreenAdaptiveBrightness(BinaryState screenAdaptiveBrightness) { + mScreenAdaptiveBrightness = screenAdaptiveBrightness; + } + + /** + * Exposed for unit testing + */ + protected void setScreenBrightness(Integer screenBrightness) { + mScreenBrightness = screenBrightness; + } + + /** + * Exposed for unit testing + */ + protected void setScreenAlwaysOn(BinaryState screenAlwaysOn) { + mScreenAlwaysOn = screenAlwaysOn; + } + + /** + * Exposed for unit testing + */ + protected void setScreenTimeoutSecs(Long screenTimeoutSecs) { + mScreenTimeoutSecs = screenTimeoutSecs; + } + + /** + * Exposed for unit testing + */ + protected void setScreenAmbientMode(BinaryState screenAmbientMode) { + mScreenAmbientMode = screenAmbientMode; + } + + /** + * Exposed for unit testing + */ + protected void setWakeGesture(BinaryState wakeGesture) { + mWakeGesture = wakeGesture; + } + + /** + * Exposed for unit testing + */ + protected void setScreenSaver(BinaryState screenSaver) { + mScreenSaver = screenSaver; + } + + /** + * Exposed for unit testing + */ + protected void setNotificationLed(BinaryState notificationLed) { + mNotificationLed = notificationLed; + } + + /** + * Exposed for unit testing + */ + protected void setTriggerMediaMounted(boolean triggerMediaMounted) { + mTriggerMediaMounted = triggerMediaMounted; + } + + /** + * Exposed for unit testing + */ + protected void setLocationGps(BinaryState locationGps) { + mLocationGps = locationGps; + } + + /** + * Exposed for unit testing + */ + protected void setLocationNetwork(BinaryState locationNetwork) { + mLocationNetwork = locationNetwork; + } + + /** + * Exposed for unit testing + */ + protected void setAutoRotate(BinaryState autoRotate) { + mAutoRotate = autoRotate; + } + + /** + * Exposed for unit testing + */ + protected void setBatterySaver(BinaryState batterySaver) { + mBatterySaver = batterySaver; + } + + /** + * Exposed for unit testing + */ + protected void setBatterySaverTrigger(Integer batterySaverTrigger) { + mBatterySaverTrigger = batterySaverTrigger; + } + + /** + * Exposed for unit testing + */ + protected void setAutoUpdateTime(BinaryState autoUpdateTime) { + mAutoUpdateTime = autoUpdateTime; + } + + /** + * Exposed for unit testing + */ + protected void setAutoUpdateTimezone(BinaryState autoUpdateTimezone) { + mAutoUpdateTimezone = autoUpdateTimezone; + } + + /** + * Exposed for unit testing + */ + protected void setDisableDialing(boolean disableDialing) { + mDisableDialing = disableDialing; + } + + /** + * Exposed for unit testing + */ + protected void setDefaultSimData(Integer defaultSimData) { + mDefaultSimData = defaultSimData; + } + + /** + * Exposed for unit testing + */ + protected void setDefaultSimVoice(Integer defaultSimVoice) { + mDefaultSimVoice = defaultSimVoice; + } + + /** + * Exposed for unit testing + */ + protected void setDefaultSimSms(Integer defaultSimSms) { + mDefaultSimSms = defaultSimSms; + } + + /** + * Exposed for unit testing + */ + protected void setDisableAudio(boolean disable) { + mDisableAudio = disable; + } + + /** + * Exposed for unit testing + */ + protected void setTestHarness(boolean setTestHarness) { + mSetTestHarness = setTestHarness; + } + + /** + * Exposed for unit testing + */ + protected void setDisableDalvikVerifier(boolean disableDalvikVerifier) { + mDisableDalvikVerifier = disableDalvikVerifier; + } + + /** + * Exposed for unit testing + */ + protected void setLocalDataPath(File path) { + mLocalDataFile = path; + } + + /** + * Exposed for unit testing + */ + protected void setMinExternalStorageKb(long storageKb) { + mMinExternalStorageKb = storageKb; + } + + /** + * Exposed for unit testing + */ + protected void setProperty(String key, String value) { + mSetProps.put(key, value); + } + + /** + * Exposed for unit testing + */ + @Deprecated + protected void setDeprecatedMinExternalStoreSpace(long storeSpace) { + mDeprecatedMinExternalStoreSpace = storeSpace; + } + + /** + * Exposed for unit testing + */ + @Deprecated + protected void setDeprecatedAudioSilent(boolean silent) { + mDeprecatedSetAudioSilent = silent; + } + + /** + * Exposed for unit testing + */ + @Deprecated + protected void setDeprecatedSetProp(String prop) { + mDeprecatedSetProps.add(prop); + } } diff --git a/src/com/android/tradefed/targetprep/DeviceSetup2.java b/src/com/android/tradefed/targetprep/DeviceSetup2.java deleted file mode 100644 index ec73ed877..000000000 --- a/src/com/android/tradefed/targetprep/DeviceSetup2.java +++ /dev/null @@ -1,740 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.tradefed.targetprep; - -import com.android.ddmlib.IDevice; -import com.android.tradefed.build.IBuildInfo; -import com.android.tradefed.config.Option; -import com.android.tradefed.config.OptionClass; -import com.android.tradefed.device.DeviceNotAvailableException; -import com.android.tradefed.device.ITestDevice; -import com.android.tradefed.log.LogUtil.CLog; -import com.android.tradefed.util.MultiMap; - -import java.io.File; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * A {@link ITargetPreparer} that configures a device for testing based on provided {@link Option}s. - * <p> - * Requires a device where 'adb root' is possible, typically a userdebug build type. - * </p><p> - * Should be performed *after* a new build is flashed. - * </p><p> - * The preparer {@link DeviceSetup} requires all settings requires all properties and commands - * to be run manually, while this preparer emphasizes using {@link Option}s to enable or disable - * features. - * </p> - */ -@OptionClass(alias = "device-setup-2") -public class DeviceSetup2 implements ITargetPreparer, ITargetCleaner { - - /** - * Enum used to record ON/OFF state with a DEFAULT no-op state. - */ - protected enum BinaryState { - DEFAULT, - ON, - OFF; - } - - // Networking - @Option(name = "airplane-mode", - description = "Turn airplane mode on or off") - protected BinaryState mAirplaneMode = BinaryState.DEFAULT; - // ON: settings put global airplane_mode_on 1 - // am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true - // OFF: settings put global airplane_mode_on 0 - // am broadcast -a android.intent.action.AIRPLANE_MODE --ez state false - - @Option(name = "wifi", - description = "Turn wifi on or off") - protected BinaryState mWifi = BinaryState.DEFAULT; - // ON: settings put global wifi_on 1 - // svc wifi enable - // OFF: settings put global wifi_off 0 - // svc wifi disable - - @Option(name = "wifi-network", - description = "The SSID of the network to connect to. Will only attempt to " + - "connect to a network if set") - protected String mWifiSsid = null; - - @Option(name = "wifi-psk", - description = "The passphrase used to connect to a secured network") - protected String mWifiPsk = null; - - @Option(name = "wifi-watchdog", - description = "Turn wifi watchdog on or off") - protected BinaryState mWifiWatchdog = BinaryState.DEFAULT; - // ON: settings put global wifi_watchdog 1 - // OFF: settings put global wifi_watchdog 0 - - @Option(name = "wifi-scan-always-enabled", - description = "Turn wifi scan always enabled on or off") - protected BinaryState mWifiScanAlwaysEnabled = BinaryState.DEFAULT; - // ON: settings put global wifi_scan_always_enabled 1 - // OFF: settings put global wifi_scan_always_enabled 0 - - @Option(name = "ethernet", - description = "Turn ethernet on or off") - protected BinaryState mEthernet = BinaryState.DEFAULT; - // ON: ifconfig eth0 up - // OFF: ifconfig eth0 down - - @Option(name = "bluetooth", - description = "Turn bluetooth on or off") - protected BinaryState mBluetooth = BinaryState.DEFAULT; - // ON: service call bluetooth_manager 6 - // OFF: service call bluetooth_manager 8 - - // Screen - @Option(name = "screen-adaptive-brightness", - description = "Turn screen adaptive brightness on or off") - protected BinaryState mScreenAdaptiveBrightness = BinaryState.DEFAULT; - // ON: settings put system screen_brightness_mode 1 - // OFF: settings put system screen_brightness_mode 0 - - @Option(name = "screen-brightness", - description = "Set the screen brightness. This is uncalibrated from product to product") - protected Integer mScreenBrightness = null; - // settings put system screen_brightness $N - - @Option(name = "screen-always-on", - description = "Turn 'screen always on' on or off. If ON, then screen-timeout-secs " + - "must be unset. Will only work when the device is plugged in") - protected BinaryState mScreenAlwaysOn = BinaryState.ON; - // ON: svc power stayon true - // OFF: svc power stayon false - - @Option(name = "screen-timeout-secs", - description = "Set the screen timeout in seconds. If set, then screen-always-on must " + - "be OFF or DEFAULT") - protected Long mScreenTimeoutSecs = null; - // settings put system screen_off_timeout $(N * 1000) - - @Option(name = "screen-ambient-mode", - description = "Turn screen ambient mode on or off") - protected BinaryState mScreenAmbientMode = BinaryState.DEFAULT; - // ON: settings put secure doze_enabled 1 - // OFF: settings put secure doze_enabled 0 - - @Option(name = "wake-gesture", - description = "Turn wake gesture on or off") - protected BinaryState mWakeGesture = BinaryState.DEFAULT; - // ON: settings put secure wake_gesture_enabled 1 - // OFF: settings put secure wake_gesture_enabled 0 - - @Option(name = "screen-saver", - description = "Turn screen saver on or off") - protected BinaryState mScreenSaver = BinaryState.DEFAULT; - // ON: settings put secure screensaver_enabled 1 - // OFF: settings put secure screensaver_enabled 0 - - @Option(name = "notification-led", - description = "Turn the notification led on or off") - protected BinaryState mNotificationLed = BinaryState.DEFAULT; - // ON: settings put system notification_light_pulse 1 - // OFF: settings put system notification_light_pulse 0 - - // Media - @Option(name = "trigger-media-mounted", - description = "Trigger a MEDIA_MOUNTED broadcast") - protected boolean mTriggerMediaMounted = false; - // am broadcast -a android.intent.action.MEDIA_MOUNTED -d file://${EXTERNAL_STORAGE} - - // Location - @Option(name = "location-gps", - description = "Turn the GPS location on or off") - protected BinaryState mLocationGps = BinaryState.DEFAULT; - // ON: settings put secure location_providers_allowed +gps - // OFF: settings put secure location_providers_allowed -gps - - @Option(name = "location-network", - description = "Turn the network location on or off") - protected BinaryState mLocationNetwork = BinaryState.DEFAULT; - // ON: settings put secure location_providers_allowed +network - // OFF: settings put secure location_providers_allowed -network - - // Sensor - @Option(name = "auto-rotate", - description = "Turn auto rotate on or off") - protected BinaryState mAutoRotate = BinaryState.DEFAULT; - // ON: settings put system accelerometer_rotation 1 - // OFF: settings put system accelerometer_rotation 0 - - // Power - @Option(name = "battery-saver-mode", - description = "Turn battery saver mode manually on or off. If OFF but battery is " + - "less battery-saver-trigger, the device will still go into battery saver mode") - protected BinaryState mBatterySaver = BinaryState.DEFAULT; - // ON: settings put global low_power 1 - // OFF: settings put global low_power 0 - - @Option(name = "battery-saver-trigger", - description = "Set the battery saver trigger level. Should be [1-99] to enable, or " + - "0 to disable automatic battery saver mode") - protected Integer mBatterySaverTrigger = null; - // settings put global low_power_trigger_level $N - - // Time - @Option(name = "auto-update-time", - description = "Turn auto update time on or off") - protected BinaryState mAutoUpdateTime = BinaryState.DEFAULT; - // ON: settings put system auto_time 1 - // OFF: settings put system auto_time 0 - - @Option(name = "auto-update-timezone", - description = "Turn auto update timezone on or off") - protected BinaryState mAutoUpdateTimezone = BinaryState.DEFAULT; - // ON: settings put system auto_timezone 1 - // OFF: settings put system auto_timezone 0 - - // Calling - @Option(name = "disable-dialing", - description = "Disable dialing") - protected boolean mDisableDialing = true; - // setprop ro.telephony.disable-call true" - - @Option(name = "default-sim-data", - description = "Set the default sim card slot for data. Leave unset for single SIM " + - "devices") - protected Integer mDefaultSimData = null; - // settings put global multi_sim_data_call $N - - @Option(name = "default-sim-voice", - description = "Set the default sim card slot for voice calls. Leave unset for single " + - "SIM devices") - protected Integer mDefaultSimVoice = null; - // settings put global multi_sim_voice_call $N - - @Option(name = "default-sim-sms", - description = "Set the default sim card slot for SMS. Leave unset for single SIM " + - "devices") - protected Integer mDefaultSimSms = null; - // settings put global multi_sim_sms $N - - // Audio - @Option(name = "disable-audio", - description = "Disable the audio") - protected boolean mDisableAudio = true; - // setprop ro.audio.silent 1" - - // Test harness - @Option(name = "disable", - description = "Disable the entire setup") - protected boolean mDisable = false; - - @Option(name = "force-skip-system-props", - description = "Force setup to not modify any device system properties. All other " + - "system property options will be ignored") - protected boolean mForceSkipSystemProps = false; - - @Option(name = "force-skip-settings", - description = "Force setup to not modify any device settings. All other setting " + - "options will be ignored.") - protected boolean mForceSkipSettings = false; - - @Option(name = "force-skip-run-commands", - description = "Force setup to not run any additional commands. All other commands " + - "will be ignored.") - protected boolean mForceSkipRunCommands = false; - - @Option(name = "set-test-harness", - description = "Set the read-only test harness flag on boot") - protected boolean mSetTestHarness = true; - // setprop ro.monkey 1" - // setprop ro.test_harness 1" - - @Option(name = "disable-dalvik-verifier", - description = "Disable the dalvik verifier on device. Allows package-private " + - "framework tests to run.") - protected boolean mDisableDalvikVerifier = false; - // setprop dalvik.vm.dexopt-flags v=n - - @Option(name="setprop", - description="Set the specified property on boot. May be repeated.") - protected Map<String, String> mSetProps = new HashMap<>(); - - @Option(name = "system-setting", - description = "Change a system (non-secure) setting. May be repeated.") - protected MultiMap<String, String> mSystemSettings = new MultiMap<>(); - - @Option(name = "secure-setting", - description = "Change a secure setting. May be repeated.") - protected MultiMap<String, String> mSecureSettings = new MultiMap<>(); - - @Option(name = "global-setting", - description = "Change a global setting. May be repeated.") - protected MultiMap<String, String> mGlobalSettings = new MultiMap<>(); - - protected List<String> mRunCommandBeforeSettings = new ArrayList<>(); - - @Option(name = "run-command", - description = "Run an adb shell command. May be repeated") - protected List<String> mRunCommandAfterSettings = new ArrayList<>(); - - @Option(name = "disconnect-wifi-after-test", - description = "Disconnect from wifi network after test completes.") - private boolean mDisconnectWifiAfterTest = true; - - @Option(name = "min-external-store-space-kb", - description="The minimum amount of free space in KB that must be present on device's " + - "external storage.") - protected long mMinExternalStoreSpace = 500; - - @Option(name = "local-data-path", - description = "Optional local file path of test data to sync to device's external " + - "storage. Use --remote-data-path to set remote location.") - protected File mLocalDataFile = null; - - @Option(name = "remote-data-path", - description = "Optional file path on device's external storage to sync test data. " + - "Must be used with --local-data-path.") - protected String mRemoteDataPath = null; - - private static final String PERSIST_PREFIX = "persist."; - - /** - * {@inheritDoc} - */ - @Override - public void setUp(ITestDevice device, IBuildInfo buildInfo) throws DeviceNotAvailableException, - TargetSetupError { - if (mDisable) { - return; - } - - CLog.i("Performing setup on %s", device.getSerialNumber()); - - if (!device.enableAdbRoot()) { - throw new TargetSetupError(String.format("Failed to enable adb root on %s", - device.getSerialNumber())); - } - - processOptions(device); - changeSystemProps(device); - runCommands(device, mRunCommandBeforeSettings); - changeSettings(device); - syncTestData(device); - runCommands(device, mRunCommandAfterSettings); - connectWifi(device); - checkExternalStoreSpace(device); - - device.clearErrorDialogs(); - } - - /** - * {@inheritDoc} - */ - @Override - public void tearDown(ITestDevice device, IBuildInfo buildInfo, Throwable e) - throws DeviceNotAvailableException { - if (mDisable) { - return; - } - - CLog.i("Performing teardown on %s", device.getSerialNumber()); - - if (e instanceof DeviceFailedToBootError) { - CLog.d("boot failure: skipping teardown"); - return; - } - - // Only try to disconnect if wifi ssid is set since isWifiEnabled() is a heavy operation - // which should be avoided when possible - if (mDisconnectWifiAfterTest && mWifiSsid != null && device.isWifiEnabled()) { - boolean result = device.disconnectFromWifi(); - if (result) { - CLog.i("Successfully disconnected from wifi network on %s", - device.getSerialNumber()); - } else { - CLog.w("Failed to disconnect from wifi network on %s", device.getSerialNumber()); - } - } - } - - /** - * Process all the {@link Option}s and turn them into system props, settings, or run commands. - * Does not run any commands on the device at this time. - * <p> - * Exposed so that children classes may override this. - * </p> - * - * @param device The {@link ITestDevice} - * @throws DeviceNotAvailableException if the device is not available - * @throws TargetSetupError if the {@link Option}s conflict - */ - @SuppressWarnings("unused") - protected void processOptions(ITestDevice device) throws DeviceNotAvailableException, - TargetSetupError { - setSettingForBinaryState(mWifi, mGlobalSettings, "wifi_on", "1", "0"); - setCommandForBinaryState(mWifi, mRunCommandAfterSettings, - "svc wifi enable", "svc wifi disable"); - - setSettingForBinaryState(mWifiWatchdog, mGlobalSettings, "wifi_watchdog", "1", "0"); - - setSettingForBinaryState(mWifiScanAlwaysEnabled, mGlobalSettings, - "wifi_scan_always_enabled", "1", "0"); - - setCommandForBinaryState(mEthernet, mRunCommandAfterSettings, - "ifconfig eth0 up", "ifconfig eth0 down"); - - setCommandForBinaryState(mBluetooth, mRunCommandAfterSettings, - "service call bluetooth_manager 6", "service call bluetooth_manager 8"); - - if (mScreenBrightness != null && BinaryState.ON.equals(mScreenAdaptiveBrightness)) { - throw new TargetSetupError("Option screen-brightness cannot be set when " + - "screen-adaptive-brightness is set to ON"); - } - - setSettingForBinaryState(mScreenAdaptiveBrightness, mSystemSettings, - "screen_brightness_mode", "1", "0"); - - if (mScreenBrightness != null) { - mSystemSettings.put("screen_brightness", Integer.toString(mScreenBrightness)); - } - - setCommandForBinaryState(mScreenAlwaysOn, mRunCommandBeforeSettings, - "svc power stayon true", "svc power stayon false"); - - if (mScreenTimeoutSecs != null) { - mSystemSettings.put("screen_off_timeout", Long.toString(mScreenTimeoutSecs * 1000)); - } - - setSettingForBinaryState(mScreenAmbientMode, mSecureSettings, "doze_enabled", "1", "0"); - - setSettingForBinaryState(mWakeGesture, mSecureSettings, "wake_gesture_enabled", "1", "0"); - - setSettingForBinaryState(mScreenSaver, mSecureSettings, "screensaver_enabled", "1", "0"); - - setSettingForBinaryState(mNotificationLed, mSystemSettings, - "notification_light_pulse", "1", "0"); - - if (mTriggerMediaMounted) { - mRunCommandAfterSettings.add("am broadcast -a android.intent.action.MEDIA_MOUNTED -d " + - "file://${EXTERNAL_STORAGE}"); - } - - setSettingForBinaryState(mLocationGps, mSecureSettings, - "location_providers_allowed", "+gps", "-gps"); - - setSettingForBinaryState(mLocationNetwork, mSecureSettings, - "location_providers_allowed", "+network", "-network"); - - setSettingForBinaryState(mAutoRotate, mSystemSettings, "accelerometer_rotation", "1", "0"); - - setCommandForBinaryState(mBatterySaver, mRunCommandBeforeSettings, - "dumpsys battery set usb 0", null); - setSettingForBinaryState(mBatterySaver, mGlobalSettings, "low_power", "1", "0"); - - if (mBatterySaverTrigger != null) { - mGlobalSettings.put("low_power_trigger_level", Integer.toString(mBatterySaverTrigger)); - } - - setSettingForBinaryState(mAutoUpdateTime, mSystemSettings, "auto_time", "1", "0"); - - setSettingForBinaryState(mAutoUpdateTimezone, mSystemSettings, "auto_timezone", "1", "0"); - - if (mDisableDialing) { - mSetProps.put("ro.telephony.disable-call", "true"); - } - - if (mDefaultSimData != null) { - mGlobalSettings.put("multi_sim_data_call", Integer.toString(mDefaultSimData)); - } - - if (mDefaultSimVoice != null) { - mGlobalSettings.put("multi_sim_voice_call", Integer.toString(mDefaultSimVoice)); - } - - if (mDefaultSimSms != null) { - mGlobalSettings.put("multi_sim_sms", Integer.toString(mDefaultSimSms)); - } - - if (mDisableAudio) { - mSetProps.put("ro.audio.silent", "1"); - } - - if (mSetTestHarness) { - // set both ro.monkey and ro.test_harness, for compatibility with older platforms - mSetProps.put("ro.monkey", "1"); - mSetProps.put("ro.test_harness", "1"); - } - - if (mDisableDalvikVerifier) { - mSetProps.put("dalvik.vm.dexopt-flags", "v=n"); - } - } - - /** - * Change the system properties on the device. - * - * @param device The {@link ITestDevice} - * @throws DeviceNotAvailableException if the device is not available - * @throws TargetSetupError if there was a failure setting the system properties - */ - private void changeSystemProps(ITestDevice device) throws DeviceNotAvailableException, - TargetSetupError { - if (mForceSkipSystemProps) { - return; - } - - StringBuilder sb = new StringBuilder(); - for (Map.Entry<String, String> prop : mSetProps.entrySet()) { - if (prop.getKey().startsWith(PERSIST_PREFIX)) { - String command = String.format("setprop %s %s", prop.getKey(), prop.getValue()); - device.executeShellCommand(command); - } else { - sb.append(String.format("%s=%s\n", prop.getKey(), prop.getValue())); - } - } - - if (sb.length() == 0) { - return; - } - - boolean result = device.pushString(sb.toString(), "/data/local.prop"); - if (!result) { - throw new TargetSetupError(String.format("Failed to push file to %s", - device.getSerialNumber())); - } - // Set reasonable permissions for /data/local.prop - device.executeShellCommand("chmod 644 /data/local.prop"); - CLog.i("Setup requires system property change. Reboot of %s required", - device.getSerialNumber()); - device.reboot(); - } - - /** - * Change the settings on the device. - * <p> - * Exposed so children classes may override. - * </p> - * - * @param device The {@link ITestDevice} - * @throws DeviceNotAvailableException if the device is not available - * @throws TargetSetupError if there was a failure setting the settings - */ - protected void changeSettings(ITestDevice device) throws DeviceNotAvailableException, - TargetSetupError { - if (mForceSkipSettings) { - return; - } - - if (mSystemSettings.isEmpty() && mSecureSettings.isEmpty() && mGlobalSettings.isEmpty()) { - return; - } - - if (device.getApiLevel() < 22) { - throw new TargetSetupError(String.format("Changing setting not supported on %s, " + - "must be API 22+", device.getSerialNumber())); - } - - // Special case airplane mode since it needs to be set before other connectivity settings - // For example, it is possible to enable airplane mode and then turn wifi on - String command = "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state %s"; - switch (mAirplaneMode) { - case ON: - CLog.d("Changing global setting airplane_mode_on to 1"); - device.executeShellCommand("settings put global airplane_mode_on 1"); - if (!mForceSkipRunCommands) { - device.executeShellCommand(String.format(command, "true")); - } - break; - case OFF: - CLog.d("Changing global setting airplane_mode_on to 0"); - device.executeShellCommand("settings put global airplane_mode_on 0"); - if (!mForceSkipRunCommands) { - device.executeShellCommand(String.format(command, "false")); - } - break; - case DEFAULT: - // No-op - break; - } - - for (String key : mSystemSettings.keySet()) { - for (String value : mSystemSettings.get(key)) { - CLog.d("Changing system setting %s to %s", key, value); - device.executeShellCommand(String.format("settings put system %s %s", key, value)); - } - } - for (String key : mSecureSettings.keySet()) { - for (String value : mSecureSettings.get(key)) { - CLog.d("Changing secure setting %s to %s", key, value); - device.executeShellCommand(String.format("settings put secure %s %s", key, value)); - } - } - - for (String key : mGlobalSettings.keySet()) { - for (String value : mGlobalSettings.get(key)) { - CLog.d("Changing global setting %s to %s", key, value); - device.executeShellCommand(String.format("settings put global %s %s", key, value)); - } - } - } - - /** - * Execute additional commands on the device. - * - * @param device The {@link ITestDevice} - * @param commands The list of commands to run - * @throws DeviceNotAvailableException if the device is not available - * @throws TargetSetupError if there was a failure setting the settings - */ - private void runCommands(ITestDevice device, List<String> commands) - throws DeviceNotAvailableException, TargetSetupError { - if (mForceSkipRunCommands) { - return; - } - - for (String command : commands) { - device.executeShellCommand(command); - } - } - - /** - * Connects device to Wifi if SSID is specified. - * - * @param device The {@link ITestDevice} - * @throws DeviceNotAvailableException if the device is not available - * @throws TargetSetupError if there was a failure setting the settings - */ - private void connectWifi(ITestDevice device) throws DeviceNotAvailableException, - TargetSetupError { - if (mForceSkipRunCommands) { - return; - } - - if (mWifiSsid != null) { - if (!device.connectToWifiNetwork(mWifiSsid, mWifiPsk)) { - throw new TargetSetupError(String.format( - "Failed to connect to wifi network %s on %s", mWifiSsid, - device.getSerialNumber())); - } - } - } - - /** - * Syncs a set of test data files, specified via local-data-path, to devices external storage. - * - * @param device The {@link ITestDevice} - * @throws DeviceNotAvailableException if the device is not available - * @throws TargetSetupError if data fails to sync - */ - private void syncTestData(ITestDevice device) throws DeviceNotAvailableException, - TargetSetupError { - if (mLocalDataFile == null) { - return; - } - - if (!mLocalDataFile.exists() || !mLocalDataFile.isDirectory()) { - throw new TargetSetupError(String.format( - "local-data-path %s is not a directory", mLocalDataFile.getAbsolutePath())); - } - String fullRemotePath = device.getIDevice().getMountPoint(IDevice.MNT_EXTERNAL_STORAGE); - if (fullRemotePath == null) { - throw new TargetSetupError(String.format( - "failed to get external storage path on device %s", device.getSerialNumber())); - } - if (mRemoteDataPath != null) { - fullRemotePath = String.format("%s/%s", fullRemotePath, mRemoteDataPath); - } - boolean result = device.syncFiles(mLocalDataFile, fullRemotePath); - if (!result) { - // TODO: get exact error code and respond accordingly - throw new TargetSetupError(String.format( - "failed to sync test data from local-data-path %s to %s on device %s", - mLocalDataFile.getAbsolutePath(), fullRemotePath, device.getSerialNumber())); - } - } - - /** - * Check that device external store has the required space - * - * @param device The {@link ITestDevice} - * @throws DeviceNotAvailableException if the device is not available or if the device does not - * have the required space - */ - private void checkExternalStoreSpace(ITestDevice device) throws DeviceNotAvailableException { - if (mMinExternalStoreSpace <= 0) { - return; - } - - long freeSpace = device.getExternalStoreFreeSpace(); - if (freeSpace < mMinExternalStoreSpace) { - throw new DeviceNotAvailableException(String.format( - "External store free space %dK is less than required %dK for device %s", - freeSpace , mMinExternalStoreSpace, device.getSerialNumber())); - } - } - - /** - * Helper method to add an ON/OFF setting to a setting map. - * - * @param state The {@link BinaryState} - * @param settingsMap The {@link MultiMap} used to store the settings. - * @param setting The setting key - * @param onValue The value if ON - * @param offValue The value if OFF - */ - protected void setSettingForBinaryState(BinaryState state, MultiMap<String, String> settingsMap, - String setting, String onValue, String offValue) { - switch (state) { - case ON: - settingsMap.put(setting, onValue); - break; - case OFF: - settingsMap.put(setting, offValue); - break; - case DEFAULT: - // Do nothing - break; - } - } - - /** - * Helper method to add an ON/OFF run command to be executed on the device. - * - * @param state The {@link BinaryState} - * @param commands The list of commands to add the on or off command to. - * @param onCommand The command to run if ON. Ignored if the command is {@code null} - * @param offCommand The command to run if OFF. Ignored if the command is {@code null} - */ - protected void setCommandForBinaryState(BinaryState state, List<String> commands, - String onCommand, String offCommand) { - switch (state) { - case ON: - if (onCommand != null) { - commands.add(onCommand); - } - break; - case OFF: - if (offCommand != null) { - commands.add(offCommand); - } - break; - case DEFAULT: - // Do nothing - break; - } - } -} |