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