Support bring up multiple different CF instances on one host
Bug: 209690575
Test: tradefed.sh run singleCommand host --class com.android.tradefed.device.cloud.GceManagerTest -n
Change-Id: Idad3a0ce36e2fd98ce94b68fd076aa5607399a4c
diff --git a/device_build_interfaces/com/android/tradefed/device/IConfigurableIp.java b/device_build_interfaces/com/android/tradefed/device/IConfigurableVirtualDevice.java
similarity index 61%
rename from device_build_interfaces/com/android/tradefed/device/IConfigurableIp.java
rename to device_build_interfaces/com/android/tradefed/device/IConfigurableVirtualDevice.java
index e3547e8..b449641 100644
--- a/device_build_interfaces/com/android/tradefed/device/IConfigurableIp.java
+++ b/device_build_interfaces/com/android/tradefed/device/IConfigurableVirtualDevice.java
@@ -16,11 +16,24 @@
package com.android.tradefed.device;
-/** An interface to provide information about a possibly preconfigured IP */
-public interface IConfigurableIp {
+/**
+ * An interface to provide information about a possibly preconfigured virtual device info (host ip,
+ * host user, ports offset and etc.).
+ */
+public interface IConfigurableVirtualDevice {
/** Returns the known associated IP if available, returns null if no known ip. */
default String getKnownDeviceIp() {
return null;
}
+
+ /** Returns the known user if available, returns null if no known user. */
+ default String getKnownUser() {
+ return null;
+ }
+
+ /** Returns the known device num offset if available, returns 0 if device num offset not set. */
+ default Integer getDeviceNumOffset() {
+ return 0;
+ }
}
diff --git a/device_build_interfaces/com/android/tradefed/device/TcpDevice.java b/device_build_interfaces/com/android/tradefed/device/TcpDevice.java
index 1cb774c..c25d75d 100644
--- a/device_build_interfaces/com/android/tradefed/device/TcpDevice.java
+++ b/device_build_interfaces/com/android/tradefed/device/TcpDevice.java
@@ -21,7 +21,7 @@
* A placeholder {@link IDevice} used by {@link DeviceManager} to allocate when {@link
* DeviceSelectionOptions#tcpDeviceRequested()} is <code>true</code>
*/
-public class TcpDevice extends StubDevice implements IConfigurableIp {
+public class TcpDevice extends StubDevice implements IConfigurableVirtualDevice {
private String mKnownDeviceIp = null;
diff --git a/device_build_interfaces/com/android/tradefed/device/TestDeviceOptions.java b/device_build_interfaces/com/android/tradefed/device/TestDeviceOptions.java
index b9f4967..858c7f0 100644
--- a/device_build_interfaces/com/android/tradefed/device/TestDeviceOptions.java
+++ b/device_build_interfaces/com/android/tradefed/device/TestDeviceOptions.java
@@ -674,16 +674,26 @@
return mUseOxygen;
}
- /** Returns the instance type of GCE virtual device that should be created */
+ /** Returns the instance user of GCE virtual device that should be created */
public String getInstanceUser() {
return mInstanceUser;
}
+ /** Set the instance user of GCE virtual device that should be created. */
+ public void setInstanceUser(String instanceUser) {
+ mInstanceUser = instanceUser;
+ }
+
/** Returns the remote port in instance that the adb server listens to */
public int getRemoteAdbPort() {
return mRemoteAdbPort;
}
+ /** Set the remote port in instance that the adb server listens to */
+ public void setRemoteAdbPort(int remoteAdbPort) {
+ mRemoteAdbPort = remoteAdbPort;
+ }
+
/** Returns the base image name to be used for the current instance */
public String getBaseImage() {
return mBaseImage;
diff --git a/global_configuration/com/android/tradefed/host/HostOptions.java b/global_configuration/com/android/tradefed/host/HostOptions.java
index ea4cbc0..1d0fe52 100644
--- a/global_configuration/com/android/tradefed/host/HostOptions.java
+++ b/global_configuration/com/android/tradefed/host/HostOptions.java
@@ -119,6 +119,11 @@
description = "The network interface used to connect to test devices.")
private String mNetworkInterface = null;
+ @Option(
+ name = "preconfigured-virtual-device-pool",
+ description = "Preconfigured virtual device pool. (Value format: $hostname:$user.)")
+ private List<String> mPreconfiguredVirtualDevicePool = new ArrayList<>();
+
private Map<PermitLimitType, Semaphore> mConcurrentLocks = new HashMap<>();
/** {@inheritDoc} */
@@ -195,6 +200,12 @@
/** {@inheritDoc} */
@Override
+ public Set<String> getKnownPreconfigureVirtualDevicePool() {
+ return new HashSet<>(mPreconfiguredVirtualDevicePool);
+ }
+
+ /** {@inheritDoc} */
+ @Override
public boolean getUseZip64InPartialDownload() {
return mUseZip64InPartialDownload;
}
diff --git a/global_configuration/com/android/tradefed/host/IHostOptions.java b/global_configuration/com/android/tradefed/host/IHostOptions.java
index 05f974f..5e3283a 100644
--- a/global_configuration/com/android/tradefed/host/IHostOptions.java
+++ b/global_configuration/com/android/tradefed/host/IHostOptions.java
@@ -82,6 +82,9 @@
/** Known remote-device associated with a specific IP. */
Set<String> getKnownRemoteDeviceIpPool();
+ /** Known preconfigured virtual device pool. */
+ Set<String> getKnownPreconfigureVirtualDevicePool();
+
/** Check if it should use the zip64 format in partial download or not. */
boolean getUseZip64InPartialDownload();
diff --git a/javatests/com/android/tradefed/device/cloud/GceManagerTest.java b/javatests/com/android/tradefed/device/cloud/GceManagerTest.java
index 23ea730..fd9a71d 100644
--- a/javatests/com/android/tradefed/device/cloud/GceManagerTest.java
+++ b/javatests/com/android/tradefed/device/cloud/GceManagerTest.java
@@ -176,7 +176,8 @@
try {
reportFile = FileUtil.createTempFile("test-gce-cmd", "report");
List<String> result =
- mGceManager.buildGceCmd(reportFile, mockBuildInfo, null, stubAttributes);
+ mGceManager.buildGceCmd(
+ reportFile, mockBuildInfo, null, null, null, stubAttributes);
List<String> expected =
ArrayUtil.list(
mOptions.getAvdDriverBinary().getAbsolutePath(),
@@ -215,7 +216,8 @@
setter.setOptionValue("gce-driver-service-account-json-key-path", "/path/to/key.json");
try {
reportFile = FileUtil.createTempFile("test-gce-cmd", "report");
- List<String> result = mGceManager.buildGceCmd(reportFile, mMockBuildInfo, null, null);
+ List<String> result =
+ mGceManager.buildGceCmd(reportFile, mMockBuildInfo, null, null, null, null);
List<String> expected =
ArrayUtil.list(
mOptions.getAvdDriverBinary().getAbsolutePath(),
@@ -256,7 +258,8 @@
setter.setOptionValue("instance-user", "foo");
try {
reportFile = FileUtil.createTempFile("test-gce-cmd", "report");
- List<String> result = mGceManager.buildGceCmd(reportFile, mMockBuildInfo, "bar", null);
+ List<String> result =
+ mGceManager.buildGceCmd(reportFile, mMockBuildInfo, "bar", null, null, null);
List<String> expected =
ArrayUtil.list(
mOptions.getAvdDriverBinary().getAbsolutePath(),
@@ -310,7 +313,8 @@
}
};
reportFile = FileUtil.createTempFile("test-gce-cmd", "report");
- List<String> result = mGceManager.buildGceCmd(reportFile, mMockBuildInfo, null, null);
+ List<String> result =
+ mGceManager.buildGceCmd(reportFile, mMockBuildInfo, null, null, null, null);
List<String> expected =
ArrayUtil.list(
mOptions.getAvdDriverBinary().getAbsolutePath(),
@@ -358,7 +362,8 @@
}
};
reportFile = FileUtil.createTempFile("test-gce-cmd", "report");
- List<String> result = mGceManager.buildGceCmd(reportFile, mMockBuildInfo, null, null);
+ List<String> result =
+ mGceManager.buildGceCmd(reportFile, mMockBuildInfo, null, null, null, null);
List<String> expected =
ArrayUtil.list(
mOptions.getAvdDriverBinary().getAbsolutePath(),
@@ -378,6 +383,60 @@
}
}
+ /**
+ * Test {@link GceManager#buildGceCmd(File, IBuildInfo, String, String, Integer,
+ * MultiMap<String, String>)} with preconfigured virtual device.
+ */
+ @Test
+ public void testBuildGceCommand_withPreconfiguredVirtualDevice() throws Exception {
+ IBuildInfo mMockBuildInfo = mock(IBuildInfo.class);
+ when(mMockBuildInfo.getBuildAttributes())
+ .thenReturn(Collections.<String, String>emptyMap());
+ when(mMockBuildInfo.getBuildFlavor()).thenReturn("FLAVOR");
+ when(mMockBuildInfo.getBuildBranch()).thenReturn("BRANCH");
+ when(mMockBuildInfo.getBuildId()).thenReturn("BUILDID");
+
+ File reportFile = null;
+ OptionSetter setter = new OptionSetter(mOptions);
+ setter.setOptionValue("gce-driver-service-account-json-key-path", "/path/to/key.json");
+ setter.setOptionValue("gce-private-key-path", "/path/to/id_rsa");
+
+ try {
+ reportFile = FileUtil.createTempFile("test-gce-cmd", "report");
+ List<String> result =
+ mGceManager.buildGceCmd(reportFile, mMockBuildInfo, "bar", "vsoc-1", 2, null);
+ List<String> expected =
+ ArrayUtil.list(
+ mOptions.getAvdDriverBinary().getAbsolutePath(),
+ "create",
+ "--build-target",
+ "FLAVOR",
+ "--branch",
+ "BRANCH",
+ "--build-id",
+ "BUILDID",
+ "--config_file",
+ mGceManager.getAvdConfigFile().getAbsolutePath(),
+ "--service-account-json-private-key-path",
+ "/path/to/key.json",
+ "--host",
+ "bar",
+ "--host-user",
+ "vsoc-1",
+ "--host-ssh-private-key-path",
+ "/path/to/id_rsa",
+ "--report_file",
+ reportFile.getAbsolutePath(),
+ "--base-instance-num",
+ "3",
+ "--launch-args=\"--base_instance_num=3\"",
+ "-v");
+ assertEquals(expected, result);
+ } finally {
+ FileUtil.deleteFile(reportFile);
+ }
+ }
+
/** Test {@link GceManager#buildGceCmd(File, IBuildInfo, String)}. */
@Test
public void testBuildGceCommandWithGceDriverParam() throws Exception {
@@ -394,7 +453,8 @@
setter.setOptionValue("gce-driver-param", "--no-autoconnect");
try {
reportFile = FileUtil.createTempFile("test-gce-cmd", "report");
- List<String> result = mGceManager.buildGceCmd(reportFile, mMockBuildInfo, null, null);
+ List<String> result =
+ mGceManager.buildGceCmd(reportFile, mMockBuildInfo, null, null, null, null);
List<String> expected =
ArrayUtil.list(
mOptions.getAvdDriverBinary().getAbsolutePath(),
@@ -444,7 +504,8 @@
}
};
reportFile = FileUtil.createTempFile("test-gce-cmd", "report");
- List<String> result = mGceManager.buildGceCmd(reportFile, mMockBuildInfo, null, null);
+ List<String> result =
+ mGceManager.buildGceCmd(reportFile, mMockBuildInfo, null, null, null, null);
List<String> expected =
ArrayUtil.list(
mOptions.getAvdDriverBinary().getAbsolutePath(),
@@ -492,6 +553,8 @@
File reportFile,
IBuildInfo b,
String ipDevice,
+ String user,
+ Integer offset,
MultiMap<String, String> attributes) {
List<String> tmp = new ArrayList<String>();
tmp.add("");
@@ -535,7 +598,8 @@
setter.setOptionValue("gce-driver-param", "--kernel-build-id");
setter.setOptionValue("gce-driver-param", "KERNELBUILDID");
reportFile = FileUtil.createTempFile("test-gce-cmd", "report");
- List<String> result = mGceManager.buildGceCmd(reportFile, mMockBuildInfo, null, null);
+ List<String> result =
+ mGceManager.buildGceCmd(reportFile, mMockBuildInfo, null, null, null, null);
List<String> expected =
ArrayUtil.list(
mOptions.getAvdDriverBinary().getAbsolutePath(),
@@ -579,6 +643,8 @@
File reportFile,
IBuildInfo b,
String ipDevice,
+ String user,
+ Integer offset,
MultiMap<String, String> attributes) {
String valid =
" {\n"
@@ -635,6 +701,8 @@
File reportFile,
IBuildInfo b,
String ipDevice,
+ String user,
+ Integer offset,
MultiMap<String, String> attributes) {
// We delete the potential report file to create an issue.
FileUtil.deleteFile(reportFile);
@@ -675,6 +743,8 @@
File reportFile,
IBuildInfo b,
String ipDevice,
+ String user,
+ Integer offset,
MultiMap<String, String> attributes) {
String validFail =
" {\n"
@@ -1028,6 +1098,8 @@
File reportFile,
IBuildInfo b,
String ipDevice,
+ String user,
+ Integer offset,
MultiMap<String, String> attributes) {
// We delete the potential report file to create an issue.
FileUtil.deleteFile(reportFile);
diff --git a/javatests/com/android/tradefed/device/cloud/RemoteAndroidVirtualDeviceTest.java b/javatests/com/android/tradefed/device/cloud/RemoteAndroidVirtualDeviceTest.java
index a0d9050..c533590 100644
--- a/javatests/com/android/tradefed/device/cloud/RemoteAndroidVirtualDeviceTest.java
+++ b/javatests/com/android/tradefed/device/cloud/RemoteAndroidVirtualDeviceTest.java
@@ -183,6 +183,8 @@
File reportFile,
IBuildInfo b,
String ipDevice,
+ String user,
+ Integer offset,
MultiMap<String, String> attributes) {
FileUtil.deleteFile(reportFile);
List<String> tmp = new ArrayList<String>();
@@ -406,7 +408,7 @@
"acloud error",
GceStatus.BOOT_FAIL))
.when(mGceHandler)
- .startGce(null, null);
+ .startGce(null, null, null, null);
try {
mTestDevice.launchGce(new BuildInfo(), null);
@@ -446,7 +448,7 @@
};
doReturn(new GceAvdInfo("ins-name", null, null, "acloud error", GceStatus.BOOT_FAIL))
.when(mGceHandler)
- .startGce(null, null);
+ .startGce(null, null, null, null);
when(mMockStateMonitor.waitForDeviceNotAvailable(Mockito.anyLong())).thenReturn(true);
@@ -538,7 +540,7 @@
null,
GceStatus.SUCCESS))
.when(mGceHandler)
- .startGce(null, null);
+ .startGce(null, null, null, null);
// Run device a first time
mTestDevice.preInvocationSetup(mMockBuildInfo, null);
@@ -639,7 +641,7 @@
null,
GceStatus.SUCCESS))
.when(mGceHandler)
- .startGce(null, null);
+ .startGce(null, null, null, null);
// Run device a first time
mTestDevice.preInvocationSetup(mMockBuildInfo, null);
@@ -726,7 +728,7 @@
null,
GceStatus.SUCCESS))
.when(mGceHandler)
- .startGce(null, null);
+ .startGce(null, null, null, null);
CommandResult bugreportzResult = new CommandResult(CommandStatus.SUCCESS);
bugreportzResult.setStdout("OK: bugreportz-file");
@@ -852,7 +854,7 @@
null,
null,
GceStatus.SUCCESS);
- doReturn(gceAvd).when(mGceHandler).startGce(null, null);
+ doReturn(gceAvd).when(mGceHandler).startGce(null, null, null, null);
OutputStream stdout = null;
OutputStream stderr = null;
CommandResult powerwashCmdResult = new CommandResult(CommandStatus.SUCCESS);
@@ -918,7 +920,7 @@
null,
null,
GceStatus.SUCCESS);
- doReturn(gceAvd).when(mGceHandler).startGce(null, null);
+ doReturn(gceAvd).when(mGceHandler).startGce(null, null, null, null);
OutputStream stdout = null;
OutputStream stderr = null;
CommandResult locateCmdResult = new CommandResult(CommandStatus.SUCCESS);
diff --git a/src/com/android/tradefed/device/DeviceManager.java b/src/com/android/tradefed/device/DeviceManager.java
index f7e8977..dbfc9d4 100644
--- a/src/com/android/tradefed/device/DeviceManager.java
+++ b/src/com/android/tradefed/device/DeviceManager.java
@@ -545,6 +545,32 @@
index++;
}
+ Map<String, List<String>> preconfigureHostUsers = new HashMap<>();
+ for (String preconfigureDevice :
+ getGlobalConfig().getHostOptions().getKnownPreconfigureVirtualDevicePool()) {
+ // Expect the preconfigureDevice string in a certain format($hostname:$user).
+ // hostname.google.com:vsoc-1
+ String[] parts = preconfigureDevice.split(":", 2);
+ preconfigureHostUsers.putIfAbsent(parts[0], new ArrayList<>());
+ preconfigureHostUsers.get(parts[0]).add(parts[1]);
+ }
+ for (Map.Entry<String, List<String>> hostUsers : preconfigureHostUsers.entrySet()) {
+ for (int i = 0; i < hostUsers.getValue().size(); i++) {
+ addAvailableDevice(
+ new RemoteAvdIDevice(
+ String.format(
+ "%s-%d-%s-%s",
+ GCE_DEVICE_SERIAL_PREFIX,
+ index,
+ hostUsers.getKey(),
+ hostUsers.getValue().get(i)),
+ hostUsers.getKey(),
+ hostUsers.getValue().get(i),
+ i));
+ index++;
+ }
+ }
+
index = mNumRemoteDevicesSupported;
for (String ip : getGlobalConfig().getHostOptions().getKnownRemoteDeviceIpPool()) {
addAvailableDevice(
diff --git a/src/com/android/tradefed/device/RemoteAndroidDevice.java b/src/com/android/tradefed/device/RemoteAndroidDevice.java
index 7fbd336..9a86960 100644
--- a/src/com/android/tradefed/device/RemoteAndroidDevice.java
+++ b/src/com/android/tradefed/device/RemoteAndroidDevice.java
@@ -53,6 +53,8 @@
private File mAdbConnectLogs = null;
private String mInitialSerial;
private String mInitialIpDevice;
+ private String mInitialUser;
+ private Integer mInitialDeviceNumOffset;
/**
* Creates a {@link RemoteAndroidDevice}.
@@ -64,8 +66,11 @@
public RemoteAndroidDevice(IDevice device, IDeviceStateMonitor stateMonitor,
IDeviceMonitor allocationMonitor) {
super(device, stateMonitor, allocationMonitor);
- if (getIDevice() instanceof IConfigurableIp) {
- mInitialIpDevice = ((IConfigurableIp) getIDevice()).getKnownDeviceIp();
+ if (getIDevice() instanceof IConfigurableVirtualDevice) {
+ mInitialIpDevice = ((IConfigurableVirtualDevice) getIDevice()).getKnownDeviceIp();
+ mInitialUser = ((IConfigurableVirtualDevice) getIDevice()).getKnownUser();
+ mInitialDeviceNumOffset =
+ ((IConfigurableVirtualDevice) getIDevice()).getDeviceNumOffset();
}
mInitialSerial = getSerialNumber();
}
@@ -328,6 +333,16 @@
return mInitialIpDevice;
}
+ /** Returns the initial known user if any. Returns null if no initial known user. */
+ protected String getInitialUser() {
+ return mInitialUser;
+ }
+
+ /** Returns the known device num offset if any. Returns null if not available. */
+ protected Integer getInitialDeviceNumOffset() {
+ return mInitialDeviceNumOffset;
+ }
+
/** Returns the initial serial name of the device. */
protected String getInitialSerial() {
return mInitialSerial;
diff --git a/src/com/android/tradefed/device/RemoteAvdIDevice.java b/src/com/android/tradefed/device/RemoteAvdIDevice.java
index 18d2d19..846fbec 100644
--- a/src/com/android/tradefed/device/RemoteAvdIDevice.java
+++ b/src/com/android/tradefed/device/RemoteAvdIDevice.java
@@ -23,6 +23,9 @@
*/
public class RemoteAvdIDevice extends TcpDevice {
+ protected String mUser = null;
+ protected Integer mDeviceNumOffset = null;
+
/** @param serial placeholder for the real serial */
public RemoteAvdIDevice(String serial) {
super(serial);
@@ -31,4 +34,22 @@
public RemoteAvdIDevice(String serial, String knowDeviceIp) {
super(serial, knowDeviceIp);
}
+
+ public RemoteAvdIDevice(String serial, String knowDeviceIp, String user, Integer offset) {
+ super(serial, knowDeviceIp);
+ this.mUser = user;
+ this.mDeviceNumOffset = offset;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String getKnownUser() {
+ return mUser;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Integer getDeviceNumOffset() {
+ return mDeviceNumOffset;
+ }
}
diff --git a/src/com/android/tradefed/device/cloud/GceManager.java b/src/com/android/tradefed/device/cloud/GceManager.java
index 2fa6146..501e79d 100644
--- a/src/com/android/tradefed/device/cloud/GceManager.java
+++ b/src/com/android/tradefed/device/cloud/GceManager.java
@@ -151,11 +151,11 @@
}
public GceAvdInfo startGce() throws TargetSetupError {
- return startGce(null, null);
+ return startGce(null, null, null, null);
}
/**
- * Attempt to start a gce instance
+ * Attempt to start a gce instance.
*
* @param ipDevice the initial IP of the GCE instance to run AVD in, <code>null</code> if not
* applicable
@@ -166,6 +166,25 @@
*/
public GceAvdInfo startGce(String ipDevice, MultiMap<String, String> attributes)
throws TargetSetupError {
+ return startGce(ipDevice, null, null, attributes);
+ }
+
+ /**
+ * Attempt to start a gce instance
+ *
+ * @param ipDevice the initial IP of the GCE instance to run AVD in, <code>null</code> if not
+ * applicable
+ * @param user the host running user of AVD, <code>null</code> if not applicable
+ * @param offset the device num offset of the AVD in the host, <code>null</code> if not
+ * applicable
+ * @param attributes attributes associated with current invocation, used for passing applicable
+ * information down to the GCE instance to be added as VM metadata
+ * @return a {@link GceAvdInfo} describing the GCE instance. Could be a BOOT_FAIL instance.
+ * @throws TargetSetupError
+ */
+ public GceAvdInfo startGce(
+ String ipDevice, String user, Integer offset, MultiMap<String, String> attributes)
+ throws TargetSetupError {
mGceAvdInfo = null;
// For debugging purposes bypass.
if (mGceHost != null && mGceInstanceName != null) {
@@ -189,7 +208,12 @@
File reportFile = null;
try {
reportFile = FileUtil.createTempFile("gce_avd_driver", ".json");
- List<String> gceArgs = buildGceCmd(reportFile, mBuildInfo, ipDevice, attributes);
+ // Override the instance name by specified user
+ if (user != null) {
+ getTestDeviceOptions().setInstanceUser(user);
+ }
+ List<String> gceArgs =
+ buildGceCmd(reportFile, mBuildInfo, ipDevice, user, offset, attributes);
long driverTimeoutMs = getTestDeviceOptions().getGceCmdTimeout();
if (!getTestDeviceOptions().allowGceCmdTimeoutOverride()) {
@@ -296,7 +320,12 @@
/** Build and return the command to launch GCE. Exposed for testing. */
protected List<String> buildGceCmd(
- File reportFile, IBuildInfo b, String ipDevice, MultiMap<String, String> attributes) {
+ File reportFile,
+ IBuildInfo b,
+ String ipDevice,
+ String user,
+ Integer offset,
+ MultiMap<String, String> attributes) {
File avdDriverFile = getTestDeviceOptions().getAvdDriverBinary();
if (!avdDriverFile.exists()) {
throw new HarnessRuntimeException(
@@ -394,16 +423,30 @@
gceArgs.add("--service-account-json-private-key-path");
gceArgs.add(getTestDeviceOptions().getServiceAccountJsonKeyFile().getAbsolutePath());
}
+
if (ipDevice != null) {
gceArgs.add("--host");
gceArgs.add(ipDevice);
gceArgs.add("--host-user");
- gceArgs.add(getTestDeviceOptions().getInstanceUser());
+ if (user != null) {
+ gceArgs.add(user);
+ } else {
+ gceArgs.add(getTestDeviceOptions().getInstanceUser());
+ }
gceArgs.add("--host-ssh-private-key-path");
gceArgs.add(getTestDeviceOptions().getSshPrivateKeyPath().getAbsolutePath());
}
gceArgs.add("--report_file");
gceArgs.add(reportFile.getAbsolutePath());
+
+ // Add base-instance-num args with offset, and override the remote adb port.
+ // When offset is 1, base-instance-num=2 and virtual device adb forward port is 6521.
+ if (offset != null) {
+ getTestDeviceOptions().setRemoteAdbPort(6520 + offset);
+ gceArgs.add("--base-instance-num");
+ gceArgs.add(String.valueOf(offset + 1));
+ gceArgs.add("--launch-args=\"" + "--base_instance_num=" + (offset + 1) + "\"");
+ }
switch (getTestDeviceOptions().getGceDriverLogLevel()) {
case DEBUG:
gceArgs.add("-v");
diff --git a/src/com/android/tradefed/device/cloud/ManagedRemoteDevice.java b/src/com/android/tradefed/device/cloud/ManagedRemoteDevice.java
index dc97da4..6a920ec 100644
--- a/src/com/android/tradefed/device/cloud/ManagedRemoteDevice.java
+++ b/src/com/android/tradefed/device/cloud/ManagedRemoteDevice.java
@@ -26,7 +26,7 @@
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.IDeviceMonitor;
import com.android.tradefed.device.IDeviceStateMonitor;
-import com.android.tradefed.device.IConfigurableIp;
+import com.android.tradefed.device.IConfigurableVirtualDevice;
import com.android.tradefed.device.StubDevice;
import com.android.tradefed.device.TestDevice;
import com.android.tradefed.device.TestDeviceOptions;
@@ -175,10 +175,20 @@
TargetSetupError exception = null;
for (int attempt = 0; attempt < getOptions().getGceMaxAttempt(); attempt++) {
try {
+ CLog.i(
+ "Launch AVD on %s by user %s (Device offset: %d).",
+ ((IConfigurableVirtualDevice) getIDevice()).getKnownDeviceIp(),
+ ((IConfigurableVirtualDevice) getIDevice()).getKnownUser(),
+ ((IConfigurableVirtualDevice) getIDevice()).getDeviceNumOffset());
+
mGceAvd =
getGceHandler()
.startGce(
- ((IConfigurableIp) getIDevice()).getKnownDeviceIp(),
+ ((IConfigurableVirtualDevice) getIDevice())
+ .getKnownDeviceIp(),
+ ((IConfigurableVirtualDevice) getIDevice()).getKnownUser(),
+ ((IConfigurableVirtualDevice) getIDevice())
+ .getDeviceNumOffset(),
attributes);
if (mGceAvd != null) {
break;
diff --git a/src/com/android/tradefed/device/cloud/RemoteAndroidVirtualDevice.java b/src/com/android/tradefed/device/cloud/RemoteAndroidVirtualDevice.java
index 0d58038..01e39fd 100644
--- a/src/com/android/tradefed/device/cloud/RemoteAndroidVirtualDevice.java
+++ b/src/com/android/tradefed/device/cloud/RemoteAndroidVirtualDevice.java
@@ -228,7 +228,12 @@
mGceAvd = null;
if (getInitialSerial() != null) {
- setIDevice(new RemoteAvdIDevice(getInitialSerial(), getInitialIp()));
+ setIDevice(
+ new RemoteAvdIDevice(
+ getInitialSerial(),
+ getInitialIp(),
+ getInitialUser(),
+ getInitialDeviceNumOffset()));
}
setFastbootEnabled(false);
@@ -272,7 +277,13 @@
TargetSetupError exception = null;
for (int attempt = 0; attempt < getOptions().getGceMaxAttempt(); attempt++) {
try {
- mGceAvd = getGceHandler().startGce(getInitialIp(), attributes);
+ mGceAvd =
+ getGceHandler()
+ .startGce(
+ getInitialIp(),
+ getInitialUser(),
+ getInitialDeviceNumOffset(),
+ attributes);
if (mGceAvd != null) {
break;
}
diff --git a/src/com/android/tradefed/device/cloud/VmRemoteDevice.java b/src/com/android/tradefed/device/cloud/VmRemoteDevice.java
index d52f4a5..a5aeab9 100644
--- a/src/com/android/tradefed/device/cloud/VmRemoteDevice.java
+++ b/src/com/android/tradefed/device/cloud/VmRemoteDevice.java
@@ -15,11 +15,11 @@
*/
package com.android.tradefed.device.cloud;
-import com.android.tradefed.device.IConfigurableIp;
+import com.android.tradefed.device.IConfigurableVirtualDevice;
import com.android.tradefed.device.StubDevice;
/** A Remote virtual device that we will manage from inside the Virtual Machine. */
-public class VmRemoteDevice extends StubDevice implements IConfigurableIp {
+public class VmRemoteDevice extends StubDevice implements IConfigurableVirtualDevice {
private String mKnownDeviceIp = null;