final AndroidEmulatorContext emu = new AndroidEmulatorContext(build, launcher, listener, androidSdk);
// We manually start the adb-server so that later commands will not have to start it,
// allowing them to complete faster.
Proc adbStart = emu.getToolProcStarter(Tool.ADB, "start-server").stdout(logger).start();
adbStart.joinWithTimeout(5L, TimeUnit.SECONDS, listener);
Proc adbStart2 = emu.getToolProcStarter(Tool.ADB, "start-server").stdout(logger).start();
adbStart2.joinWithTimeout(5L, TimeUnit.SECONDS, listener);
// Determine whether we need to create the first snapshot
final SnapshotState snapshotState;
if (useSnapshots && androidSdk.supportsSnapshots()) {
boolean hasSnapshot = emuConfig.hasExistingSnapshot(launcher, androidSdk);
if (hasSnapshot) {
// Boot from the existing "jenkins" snapshot
snapshotState = SnapshotState.BOOT;
} else {
// Create an initial "jenkins" snapshot...
snapshotState = SnapshotState.INITIALISE;
// ..with a clean start
emuConfig.setShouldWipeData();
}
} else {
// If snapshots are disabled or not supported, there's nothing to do
snapshotState = SnapshotState.NONE;
}
// Compile complete command for starting emulator
final String emulatorArgs = emuConfig.getCommandArguments(snapshotState,
androidSdk.supportsSnapshots(), emu.userPort(), emu.adbPort());
// Start emulator process
if (snapshotState == SnapshotState.BOOT) {
log(logger, Messages.STARTING_EMULATOR_FROM_SNAPSHOT());
} else if (snapshotState == SnapshotState.INITIALISE) {
log(logger, Messages.STARTING_EMULATOR_SNAPSHOT_INIT());
} else {
log(logger, Messages.STARTING_EMULATOR());
}
if (emulatorAlreadyExists && emuConfig.shouldWipeData()) {
log(logger, Messages.ERASING_EXISTING_EMULATOR_DATA());
}
final long bootTime = System.currentTimeMillis();
// Prepare to capture and log emulator standard output
ByteArrayOutputStream emulatorOutput = new ByteArrayOutputStream();
ForkOutputStream emulatorLogger = new ForkOutputStream(logger, emulatorOutput);
final Proc emulatorProcess = emu.getToolProcStarter(emuConfig.getExecutable(), emulatorArgs).stdout(emulatorLogger).start();
emu.setProcess(emulatorProcess);
// Give the emulator process a chance to initialise
Thread.sleep(5 * 1000);
// Check whether a failure was reported on stdout
if (emulatorOutput.toString().contains("image is used by another emulator")) {
log(logger, Messages.EMULATOR_ALREADY_IN_USE(emuConfig.getAvdName()));
return null;
}
// Wait for TCP socket to become available
boolean socket = waitForSocket(launcher, emu.adbPort(), ADB_CONNECT_TIMEOUT_MS);
if (!socket) {
log(logger, Messages.EMULATOR_DID_NOT_START());
build.setResult(Result.NOT_BUILT);
cleanUp(emuConfig, emu);
return null;
}
// As of SDK Tools r12, "emulator" is no longer the main process; it just starts a certain
// child process depending on the AVD architecture. Therefore on Windows, checking the
// status of this original process will not work, as it ends after it has started the child.
//
// With the adb socket open we know the correct process is running, so we set this flag to
// indicate that any methods wanting to check the "emulator" process state should ignore it.
boolean ignoreProcess = !launcher.isUnix() && androidSdk.getSdkToolsVersion() >= 12;
// Notify adb of our existence
int result = emu.getToolProcStarter(Tool.ADB, "connect " + emu.serial()).join();
if (result != 0) { // adb currently only ever returns 0!
log(logger, Messages.CANNOT_CONNECT_TO_EMULATOR());
build.setResult(Result.NOT_BUILT);
cleanUp(emuConfig, emu);
return null;
}
// Monitor device for boot completion signal
log(logger, Messages.WAITING_FOR_BOOT_COMPLETION());
int bootTimeout = BOOT_COMPLETE_TIMEOUT_MS;
if (!emulatorAlreadyExists || emuConfig.shouldWipeData() || snapshotState == SnapshotState.INITIALISE) {
bootTimeout *= 2;
}
boolean bootSucceeded = waitForBootCompletion(ignoreProcess, bootTimeout, emu);
if (!bootSucceeded) {
if ((System.currentTimeMillis() - bootTime) < bootTimeout) {
log(logger, Messages.EMULATOR_STOPPED_DURING_BOOT());
} else {
log(logger, Messages.BOOT_COMPLETION_TIMED_OUT(bootTimeout / 1000));
}
build.setResult(Result.NOT_BUILT);
cleanUp(emuConfig, emu);
return null;
}
// Start dumping logcat to temporary file
final File artifactsDir = build.getArtifactsDir();
final FilePath logcatFile = build.getWorkspace().createTextTempFile("logcat_", ".log", "", false);
final OutputStream logcatStream = logcatFile.write();
final String logcatArgs = String.format("-s %s logcat -v time", emu.serial());
final Proc logWriter = emu.getToolProcStarter(Tool.ADB, logcatArgs).stdout(logcatStream).stderr(new NullStream()).start();
// Unlock emulator by pressing the Menu key once, if required.
// Upon first boot (and when the data is wiped) the emulator is already unlocked
final long bootDuration = System.currentTimeMillis() - bootTime;
if (emulatorAlreadyExists && !wipeData && snapshotState != SnapshotState.BOOT) {