1 /*
2  * Copyright (C) 2011 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 package com.android.tradefed.device;
17 
18 import com.android.ddmlib.Log.LogLevel;
19 import com.android.tradefed.config.Option;
20 import com.android.tradefed.util.ArrayUtil;
21 
22 import java.io.File;
23 import java.util.ArrayList;
24 import java.util.Collections;
25 import java.util.HashSet;
26 import java.util.List;
27 import java.util.Set;
28 
29 /**
30  * Container for {@link ITestDevice} {@link Option}s
31  */
32 public class TestDeviceOptions {
33 
34     public enum InstanceType {
35         /** A device that we remotely access via ssh and adb connect */
36         GCE,
37         REMOTE_AVD,
38         /**
39          * A remote device inside an emulator that we access via ssh to the instance hosting the
40          * emulator then adb connect.
41          */
42         CUTTLEFISH,
43         REMOTE_NESTED_AVD,
44         /** An android emulator. */
45         EMULATOR,
46         /** Chrome OS VM (betty) */
47         CHEEPS,
48     }
49 
50     public static final int DEFAULT_ADB_PORT = 5555;
51     public static final String INSTANCE_TYPE_OPTION = "instance-type";
52 
53     /** Do not provide a setter method for that Option as it might be misused. */
54     @Option(name = "enable-root", description = "enable adb root on boot.")
55     private boolean mEnableAdbRoot = true;
56 
57     @Option(name = "disable-keyguard",
58             description = "attempt to disable keyguard once boot is complete.")
59     private boolean mDisableKeyguard = true;
60 
61     @Option(name = "enable-logcat", description =
62             "Enable background logcat capture when invocation is running.")
63     private boolean mEnableLogcat = true;
64 
65     @Option(name = "max-tmp-logcat-file", description =
66         "The maximum size of tmp logcat data to retain, in bytes. " +
67         "Only used if --enable-logcat is set")
68     private long mMaxLogcatDataSize = 20 * 1024 * 1024;
69 
70     @Option(name = "logcat-options", description =
71             "Options to be passed down to logcat command, if unspecified, \"-v threadtime\" will " +
72             "be used. Only used if --enable-logcat is set")
73     private String mLogcatOptions = null;
74 
75     @Option(name = "fastboot-timeout", description =
76             "time in ms to wait for a device to boot into fastboot.")
77     private int mFastbootTimeout = 1 * 60 * 1000;
78 
79     @Option(name = "adb-recovery-timeout", description =
80             "time in ms to wait for a device to boot into recovery.")
81     private int mAdbRecoveryTimeout = 1 * 60 * 1000;
82 
83     @Option(name = "reboot-timeout", description =
84             "time in ms to wait for a device to reboot to full system.")
85     private int mRebootTimeout = 2 * 60 * 1000;
86 
87     @Option(name = "use-fastboot-erase", description =
88             "use fastboot erase instead of fastboot format to wipe partitions")
89     private boolean mUseFastbootErase = false;
90 
91     @Option(name = "unencrypt-reboot-timeout", description = "time in ms to wait for the device to "
92             + "format the filesystem and reboot after unencryption")
93     private int mUnencryptRebootTimeout = 0;
94 
95     @Option(name = "online-timeout", description = "default time in ms to wait for the device to "
96             + "be visible on adb.", isTimeVal = true)
97     private long mOnlineTimeout = 1 * 60 * 1000;
98 
99     @Option(name = "available-timeout", description = "default time in ms to wait for the device "
100             + "to be available aka fully boot.")
101     private long mAvailableTimeout = 6 * 60 * 1000;
102 
103     @Option(name = "conn-check-url",
104             description = "default URL to be used for connectivity checks.")
105     private String mConnCheckUrl = "http://www.google.com";
106 
107     @Option(name = "wifi-attempts",
108             description = "default number of attempts to connect to wifi network.")
109     private int mWifiAttempts = 5;
110 
111     @Option(name = "wifi-retry-wait-time",
112             description = "the base wait time in ms between wifi connect retries. "
113             + "The actual wait time would be a multiple of this value.")
114     private int mWifiRetryWaitTime = 60 * 1000;
115 
116     @Option(
117         name = "max-wifi-connect-time",
118         isTimeVal = true,
119         description = "the maximum amount of time to attempt to connect to wifi."
120     )
121     private long mMaxWifiConnectTime = 10 * 60 * 1000;
122 
123     @Option(name = "wifi-exponential-retry",
124             description = "Change the wifi connection retry strategy from a linear wait time into"
125                     + " a binary exponential back-offs when retrying.")
126     private boolean mWifiExpoRetryEnabled = true;
127 
128     @Option(name = "wifiutil-apk-path", description = "path to the wifiutil APK file")
129     private String mWifiUtilAPKPath = null;
130 
131     @Option(name = "post-boot-command",
132             description = "shell command to run after reboots during invocation")
133     private List<String> mPostBootCommands = new ArrayList<String>();
134 
135     @Option(name = "disable-reboot",
136             description = "disables device reboots globally, making them no-ops")
137     private boolean mDisableReboot = false;
138 
139     @Option(name = "cutoff-battery", description =
140             "the minimum battery level required to continue the invocation. Scale: 0-100")
141     private Integer mCutoffBattery = null;
142 
143     @Option(
144         name = "use-content-provider",
145         description =
146                 "Allow to disable the use of the content provider at the device level. "
147                         + "This results in falling back to standard adb push/pull."
148     )
149     private boolean mUseContentProvider = true;
150 
151     // ====================== Options Related to Virtual Devices ======================
152     @Option(
153             name = INSTANCE_TYPE_OPTION,
154             description = "The type of virtual device instance to create")
155     private InstanceType mInstanceType = InstanceType.GCE;
156 
157     @Option(
158             name = "gce-boot-timeout",
159             description = "timeout to wait in ms for GCE to be online.",
160             isTimeVal = true)
161     private long mGceCmdTimeout = 30 * 60 * 1000; // 30 minutes.
162 
163     @Option(
164             name = "allow-gce-boot-timeout-override",
165             description =
166                     "Acloud can take boot-timeout as an arg already, this flag allows to use "
167                             + "the Acloud value as a basis instead of the gce-boot-timeout option.")
168     private boolean mAllowGceCmdTimeoutOverride = false;
169 
170     @Option(name = "gce-driver-path", description = "path of the binary to launch GCE devices")
171     private File mAvdDriverBinary = null;
172 
173     @Option(
174             name = "gce-driver-config-path",
175             description = "path of the config to use to launch GCE devices.")
176     private File mAvdConfigFile = null;
177 
178     @Option(
179             name = "gce-driver-service-account-json-key-path",
180             description = "path to the service account json key location.")
181     private File mJsonKeyFile = null;
182 
183     @Option(
184             name = "gce-private-key-path",
185             description = "path to the ssh key private key location.")
186     private File mSshPrivateKeyPath = new File("~/.ssh/id_rsa");
187 
188     @Option(name = "gce-driver-log-level", description = "Log level for gce driver")
189     private LogLevel mGceDriverLogLevel = LogLevel.DEBUG;
190 
191     @Option(
192         name = "gce-driver-param",
193         description = "Additional args to pass to gce driver as parameters."
194     )
195     private List<String> mGceDriverParams = new ArrayList<>();
196 
197     @Deprecated
198     @Option(
199         name = "gce-driver-build-id-param",
200         description =
201                 "The parameter to be paired with "
202                         + "build id from build info when passed down to gce driver"
203     )
204     private String mGceDriverBuildIdParam = "build_id";
205 
206     @Option(name = "gce-account", description = "email account to use with GCE driver.")
207     private String mGceAccount = null;
208 
209     @Option(
210         name = "max-gce-attempt",
211         description = "Maximum number of attempts to start Gce before throwing an exception."
212     )
213     private int mGceMaxAttempt = 1;
214 
215     @Option(
216             name = "skip-gce-teardown",
217             description =
218                     "Whether or not to skip the GCE tear down. Skipping tear down will "
219                             + "result in the instance being left.")
220     private boolean mSkipTearDown = false;
221 
222     @Option(
223             name = "wait-gce-teardown",
224             description = "Whether or not to block on gce teardown before proceeding.")
225     private boolean mWaitForGceTearDown = false;
226 
227     @Option(
228             name = "instance-user",
229             description =
230                     "The account to be used to interact with the "
231                             + "outer layer of the GCE VM, e.g. to SSH in")
232     private String mInstanceUser = "root";
233 
234     @Option(
235             name = "remote-adb-port",
236             description = "The port on remote instance where the adb " + "server listens to.")
237     private int mRemoteAdbPort = DEFAULT_ADB_PORT;
238 
239     @Option(
240             name = "base-host-image",
241             description = "The base image to be used for the GCE VM to host emulator.")
242     private String mBaseImage = null;
243 
244     @Option(
245         name = "remote-fetch-file-pattern",
246         description =
247                 "Only for remote VM devices. Allows to specify patterns to fetch file on the "
248                         + "remote VM via scp. Pattern must follow the scp notations."
249     )
250     private Set<String> mRemoteFetchFilePattern = new HashSet<>();
251 
252     @Option(name = "cros-user", description = "(CHEEPS ONLY) Account to log in to Chrome OS with.")
253     private String mCrosUser = null;
254 
255     @Option(
256         name = "cros-password",
257         description =
258                 "(CHEEPS ONLY) Password to log in to Chrome OS with. Only used if cros-user "
259                         + "is specified."
260     )
261     private String mCrosPassword = null;
262 
263     // END ====================== Options Related to Virtual Devices ======================
264 
265     // Option related to Remote Device only
266 
267     public static final String REMOTE_TF_VERSION_OPTION = "remote-tf-version";
268 
269     @Option(
270         name = REMOTE_TF_VERSION_OPTION,
271         description =
272                 "The TF to push to the remote VM to drive the invocation. If null, current TF "
273                         + "will be pushed."
274     )
275     private File mRemoteTFVersion = null;
276 
277     /** Check whether adb root should be enabled on boot for this device */
isEnableAdbRoot()278     public boolean isEnableAdbRoot() {
279         return mEnableAdbRoot;
280     }
281 
282     /**
283      * Check whether or not we should attempt to disable the keyguard once boot has completed
284      */
isDisableKeyguard()285     public boolean isDisableKeyguard() {
286         return mDisableKeyguard;
287     }
288 
289     /**
290      * Set whether or not we should attempt to disable the keyguard once boot has completed
291      */
setDisableKeyguard(boolean disableKeyguard)292     public void setDisableKeyguard(boolean disableKeyguard) {
293         mDisableKeyguard = disableKeyguard;
294     }
295 
296     /**
297      * Get the approximate maximum size of a tmp logcat data to retain, in bytes.
298      */
getMaxLogcatDataSize()299     public long getMaxLogcatDataSize() {
300         return mMaxLogcatDataSize;
301     }
302 
303     /**
304      * Set the approximate maximum size of a tmp logcat to retain, in bytes
305      */
setMaxLogcatDataSize(long maxLogcatDataSize)306     public void setMaxLogcatDataSize(long maxLogcatDataSize) {
307         mMaxLogcatDataSize = maxLogcatDataSize;
308     }
309 
310     /**
311      * @return the timeout to boot into fastboot mode in msecs.
312      */
getFastbootTimeout()313     public int getFastbootTimeout() {
314         return mFastbootTimeout;
315     }
316 
317     /**
318      * @param fastbootTimeout the timout in msecs to boot into fastboot mode.
319      */
setFastbootTimeout(int fastbootTimeout)320     public void setFastbootTimeout(int fastbootTimeout) {
321         mFastbootTimeout = fastbootTimeout;
322     }
323 
324     /**
325      * @return the timeout in msecs to boot into recovery mode.
326      */
getAdbRecoveryTimeout()327     public int getAdbRecoveryTimeout() {
328         return mAdbRecoveryTimeout;
329     }
330 
331     /**
332      * @param adbRecoveryTimeout the timeout in msecs to boot into recovery mode.
333      */
setAdbRecoveryTimeout(int adbRecoveryTimeout)334     public void setAdbRecoveryTimeout(int adbRecoveryTimeout) {
335         mAdbRecoveryTimeout = adbRecoveryTimeout;
336     }
337 
338     /**
339      * @return the timeout in msecs for the full system boot.
340      */
getRebootTimeout()341     public int getRebootTimeout() {
342         return mRebootTimeout;
343     }
344 
345     /**
346      * @param rebootTimeout the timeout in msecs for the system to fully boot.
347      */
setRebootTimeout(int rebootTimeout)348     public void setRebootTimeout(int rebootTimeout) {
349         mRebootTimeout = rebootTimeout;
350     }
351 
352     /**
353      * @return whether to use fastboot erase instead of fastboot format to wipe partitions.
354      */
getUseFastbootErase()355     public boolean getUseFastbootErase() {
356         return mUseFastbootErase;
357     }
358 
359     /**
360      * @param useFastbootErase whether to use fastboot erase instead of fastboot format to wipe
361      * partitions.
362      */
setUseFastbootErase(boolean useFastbootErase)363     public void setUseFastbootErase(boolean useFastbootErase) {
364         mUseFastbootErase = useFastbootErase;
365     }
366 
367     /**
368      * @return the timeout in msecs for the filesystem to be formatted and the device to reboot
369      * after unencryption.
370      */
getUnencryptRebootTimeout()371     public int getUnencryptRebootTimeout() {
372         return mUnencryptRebootTimeout;
373     }
374 
375     /**
376      * @param unencryptRebootTimeout the timeout in msecs for the filesystem to be formatted and
377      * the device to reboot after unencryption.
378      */
setUnencryptRebootTimeout(int unencryptRebootTimeout)379     public void setUnencryptRebootTimeout(int unencryptRebootTimeout) {
380         mUnencryptRebootTimeout = unencryptRebootTimeout;
381     }
382 
383     /**
384      * @return the default time in ms to to wait for a device to be online.
385      */
getOnlineTimeout()386     public long getOnlineTimeout() {
387         return mOnlineTimeout;
388     }
389 
setOnlineTimeout(long onlineTimeout)390     public void setOnlineTimeout(long onlineTimeout) {
391         mOnlineTimeout = onlineTimeout;
392     }
393 
394     /**
395      * @return the default time in ms to to wait for a device to be available.
396      */
getAvailableTimeout()397     public long getAvailableTimeout() {
398         return mAvailableTimeout;
399     }
400 
401     /**
402      * @return the default URL to be used for connectivity tests.
403      */
getConnCheckUrl()404     public String getConnCheckUrl() {
405         return mConnCheckUrl;
406     }
407 
setConnCheckUrl(String url)408     public void setConnCheckUrl(String url) {
409       mConnCheckUrl = url;
410     }
411 
412     /**
413      * @return true if background logcat capture is enabled
414      */
isLogcatCaptureEnabled()415     public boolean isLogcatCaptureEnabled() {
416         return mEnableLogcat;
417     }
418 
419     /**
420      * @return the default number of attempts to connect to wifi network.
421      */
getWifiAttempts()422     public int getWifiAttempts() {
423         return mWifiAttempts;
424     }
425 
setWifiAttempts(int wifiAttempts)426     public void setWifiAttempts(int wifiAttempts) {
427         mWifiAttempts = wifiAttempts;
428     }
429 
430     /**
431      * @return the base wait time between wifi connect retries.
432      */
getWifiRetryWaitTime()433     public int getWifiRetryWaitTime() {
434         return mWifiRetryWaitTime;
435     }
436 
437     /** @return the maximum time to attempt to connect to wifi. */
getMaxWifiConnectTime()438     public long getMaxWifiConnectTime() {
439         return mMaxWifiConnectTime;
440     }
441 
442     /**
443      * @return a list of shell commands to run after reboots.
444      */
getPostBootCommands()445     public List<String> getPostBootCommands() {
446         return mPostBootCommands;
447     }
448 
449     /**
450      * @return the minimum battery level to continue the invocation.
451      */
getCutoffBattery()452     public Integer getCutoffBattery() {
453         return mCutoffBattery;
454     }
455 
456     /**
457      * set the minimum battery level to continue the invocation.
458      */
setCutoffBattery(int cutoffBattery)459     public void setCutoffBattery(int cutoffBattery) {
460         if (cutoffBattery < 0 || cutoffBattery > 100) {
461             // Prevent impossible value.
462             throw new RuntimeException(String.format("Battery cutoff wasn't changed,"
463                     + "the value %s isn't within possible range (0-100).", cutoffBattery));
464         }
465         mCutoffBattery = cutoffBattery;
466     }
467 
468     /**
469      * @return the configured logcat options
470      */
getLogcatOptions()471     public String getLogcatOptions() {
472         return mLogcatOptions;
473     }
474 
475     /**
476      * Set the options to be passed down to logcat
477      */
setLogcatOptions(String logcatOptions)478     public void setLogcatOptions(String logcatOptions) {
479         mLogcatOptions = logcatOptions;
480     }
481 
482     /**
483      * @return if device reboot should be disabled
484      */
shouldDisableReboot()485     public boolean shouldDisableReboot() {
486         return mDisableReboot;
487     }
488 
489     /**
490      * @return if the exponential retry strategy should be used.
491      */
isWifiExpoRetryEnabled()492     public boolean isWifiExpoRetryEnabled() {
493         return mWifiExpoRetryEnabled;
494     }
495 
496     /** @return the wifiutil apk path */
getWifiUtilAPKPath()497     public String getWifiUtilAPKPath() {
498         return mWifiUtilAPKPath;
499     }
500 
501     /** Returns the instance type of virtual device that should be created */
getInstanceType()502     public InstanceType getInstanceType() {
503         return mInstanceType;
504     }
505 
506     /** Returns whether or not the Tradefed content provider can be used to push/pull files. */
shouldUseContentProvider()507     public boolean shouldUseContentProvider() {
508         return mUseContentProvider;
509     }
510 
511     // =========================== Getter and Setter for Virtual Devices
512     /** Return the Gce Avd timeout for the instance to come online. */
getGceCmdTimeout()513     public long getGceCmdTimeout() {
514         return mGceCmdTimeout;
515     }
516 
517     /** Set the Gce Avd timeout for the instance to come online. */
setGceCmdTimeout(long gceCmdTimeout)518     public void setGceCmdTimeout(long gceCmdTimeout) {
519         mGceCmdTimeout = gceCmdTimeout;
520     }
521 
522     /** Returns whether or not we should rely on the boot-timeout args from acloud if present. */
allowGceCmdTimeoutOverride()523     public boolean allowGceCmdTimeoutOverride() {
524         return mAllowGceCmdTimeoutOverride;
525     }
526 
527     /** Return the path to the binary to start the Gce Avd instance. */
getAvdDriverBinary()528     public File getAvdDriverBinary() {
529         return mAvdDriverBinary;
530     }
531 
532     /** Set the path to the binary to start the Gce Avd instance. */
setAvdDriverBinary(File avdDriverBinary)533     public void setAvdDriverBinary(File avdDriverBinary) {
534         mAvdDriverBinary = avdDriverBinary;
535     }
536 
537     /** Return the Gce Avd config file to start the instance. */
getAvdConfigFile()538     public File getAvdConfigFile() {
539         return mAvdConfigFile;
540     }
541 
542     /** Set the Gce Avd config file to start the instance. */
setAvdConfigFile(File avdConfigFile)543     public void setAvdConfigFile(File avdConfigFile) {
544         mAvdConfigFile = avdConfigFile;
545     }
546 
547     /** @return the service account json key file. */
getServiceAccountJsonKeyFile()548     public File getServiceAccountJsonKeyFile() {
549         return mJsonKeyFile;
550     }
551 
552     /**
553      * Set the service account json key file.
554      *
555      * @param jsonKeyFile the key file.
556      */
setServiceAccountJsonKeyFile(File jsonKeyFile)557     public void setServiceAccountJsonKeyFile(File jsonKeyFile) {
558         mJsonKeyFile = jsonKeyFile;
559     }
560 
561     /** Return the path of the ssh key to use for operations with the Gce Avd instance. */
getSshPrivateKeyPath()562     public File getSshPrivateKeyPath() {
563         return mSshPrivateKeyPath;
564     }
565 
566     /** Set the path of the ssh key to use for operations with the Gce Avd instance. */
setSshPrivateKeyPath(File sshPrivateKeyPath)567     public void setSshPrivateKeyPath(File sshPrivateKeyPath) {
568         mSshPrivateKeyPath = sshPrivateKeyPath;
569     }
570 
571     /** Return the log level of the Gce Avd driver. */
getGceDriverLogLevel()572     public LogLevel getGceDriverLogLevel() {
573         return mGceDriverLogLevel;
574     }
575 
576     /** Set the log level of the Gce Avd driver. */
setGceDriverLogLevel(LogLevel mGceDriverLogLevel)577     public void setGceDriverLogLevel(LogLevel mGceDriverLogLevel) {
578         this.mGceDriverLogLevel = mGceDriverLogLevel;
579     }
580 
581     /** Return the additional GCE driver parameters provided via option */
getGceDriverParams()582     public List<String> getGceDriverParams() {
583         return mGceDriverParams;
584     }
585 
586     /** Add a param to the gce driver params. */
addGceDriverParams(String param)587     public void addGceDriverParams(String param) {
588         mGceDriverParams.add(param);
589     }
590 
591     /** Set the GCE driver parameter that should be paired with the build id from build info */
setGceDriverBuildIdParam(String gceDriverBuildIdParam)592     public void setGceDriverBuildIdParam(String gceDriverBuildIdParam) {
593         mGceDriverBuildIdParam = gceDriverBuildIdParam;
594     }
595 
596     /** Return the GCE driver parameter that should be paired with the build id from build info */
getGceDriverBuildIdParam()597     public String getGceDriverBuildIdParam() {
598         return mGceDriverBuildIdParam;
599     }
600 
601     /** Return the gce email account to use with the driver */
getGceAccount()602     public String getGceAccount() {
603         return mGceAccount;
604     }
605 
606     /** Return the max number of attempts to start a gce device */
getGceMaxAttempt()607     public int getGceMaxAttempt() {
608         if (mGceMaxAttempt < 1) {
609             throw new RuntimeException("--max-gce-attempt cannot be bellow 1 attempt.");
610         }
611         return mGceMaxAttempt;
612     }
613 
614     /** Set the max number of attempts to start a gce device */
setGceMaxAttempt(int gceMaxAttempt)615     public void setGceMaxAttempt(int gceMaxAttempt) {
616         mGceMaxAttempt = gceMaxAttempt;
617     }
618 
619     /** Returns true if GCE tear down should be skipped. False otherwise. */
shouldSkipTearDown()620     public boolean shouldSkipTearDown() {
621         return mSkipTearDown;
622     }
623 
624     /** Returns true if we should block on GCE tear down completion before proceeding. */
waitForGceTearDown()625     public boolean waitForGceTearDown() {
626         return mWaitForGceTearDown;
627     }
628 
629     /** Returns the instance type of GCE virtual device that should be created */
getInstanceUser()630     public String getInstanceUser() {
631         return mInstanceUser;
632     }
633 
634     /** Returns the remote port in instance that the adb server listens to */
getRemoteAdbPort()635     public int getRemoteAdbPort() {
636         return mRemoteAdbPort;
637     }
638 
639     /** Returns the base image name to be used for the current instance */
getBaseImage()640     public String getBaseImage() {
641         return mBaseImage;
642     }
643 
644     /** Returns the list of pattern to attempt to fetch via scp. */
getRemoteFetchFilePattern()645     public Set<String> getRemoteFetchFilePattern() {
646         return mRemoteFetchFilePattern;
647     }
648 
649     /** Returns the Chrome OS User to log in as. */
getCrosUser()650     public String getCrosUser() {
651         return mCrosUser;
652     }
653 
654     /** Returns the password to log in to Chrome OS with. */
getCrosPassword()655     public String getCrosPassword() {
656         return mCrosPassword;
657     }
658 
659     /** The file pointing to the directory of the Tradefed version to be pushed to the remote. */
getRemoteTf()660     public File getRemoteTf() {
661         return mRemoteTFVersion;
662     }
663 
getCreateCommandByInstanceType(InstanceType type)664     public static String getCreateCommandByInstanceType(InstanceType type) {
665         switch (type) {
666             case CHEEPS:
667             case GCE:
668             case REMOTE_AVD:
669                 return "create";
670             case CUTTLEFISH:
671             case REMOTE_NESTED_AVD:
672                 return "create_cf";
673             case EMULATOR:
674                 return "create_gf";
675         }
676         throw new RuntimeException("Unexpected InstanceType: " + type);
677     }
678 
getExtraParamsByInstanceType(InstanceType type, String baseImage)679     public static List<String> getExtraParamsByInstanceType(InstanceType type, String baseImage) {
680         if (InstanceType.EMULATOR.equals(type)) {
681             // TODO(b/119440413) remove when base image can be passed via extra gce driver params
682             List<String> params = ArrayUtil.list();
683             if (baseImage != null) {
684                 params.add("--base_image");
685                 params.add(baseImage);
686             }
687             return params;
688         }
689         return Collections.emptyList();
690     }
691 }
692