/* * Copyright 2010-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jetbrains.kotlin.android.tests.emulator; import com.intellij.execution.configurations.GeneralCommandLine; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.android.tests.OutputUtils; import org.jetbrains.kotlin.android.tests.PathManager; import org.jetbrains.kotlin.android.tests.run.RunResult; import org.jetbrains.kotlin.android.tests.run.RunUtils; import org.junit.Assert; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; public class Emulator { public static final String ARM = "arm"; public static final String X86 = "x86"; private final static Pattern EMULATOR_PATTERN = Pattern.compile("emulator-([0-9])*"); private final PathManager pathManager; private String platform; public Emulator(PathManager pathManager, String platform) { this.pathManager = pathManager; this.platform = platform; } private GeneralCommandLine getCreateCommand() { GeneralCommandLine commandLine = new GeneralCommandLine(); String androidCmdName = SystemInfo.isWindows ? "android.bat" : "android"; commandLine.setExePath(pathManager.getToolsFolderInAndroidSdk() + "/" + androidCmdName); commandLine.addParameter("create"); commandLine.addParameter("avd"); commandLine.addParameter("--force"); commandLine.addParameter("-n"); commandLine.addParameter("my_avd"); commandLine.addParameter("-p"); commandLine.addParameter(pathManager.getAndroidEmulatorRoot()); commandLine.addParameter("-t"); commandLine.addParameter("1"); commandLine.addParameter("-b"); commandLine.addParameter(getEmulatorAbi()); return commandLine; } private String getEmulatorAbi(){ return platform == X86 ? "x86" : "armeabi-v7a"; } private GeneralCommandLine getStartCommand() { GeneralCommandLine commandLine = new GeneralCommandLine(); String emulatorCmdName = SystemInfo.isWindows ? "emulator.exe" : "emulator"; commandLine.setExePath(pathManager.getToolsFolderInAndroidSdk() + "/" + emulatorCmdName); commandLine.addParameter("-avd"); commandLine.addParameter("my_avd"); commandLine.addParameter("-no-audio"); commandLine.addParameter("-no-window"); return commandLine; } private GeneralCommandLine getWaitCommand() { GeneralCommandLine commandLine = new GeneralCommandLine(); String adbCmdName = SystemInfo.isWindows ? "adb.exe" : "adb"; commandLine.setExePath(pathManager.getPlatformToolsFolderInAndroidSdk() + "/" + adbCmdName); commandLine.addParameter("wait-for-device"); return commandLine; } private GeneralCommandLine getStopCommandForAdb() { GeneralCommandLine commandLine = new GeneralCommandLine(); String adbCmdName = SystemInfo.isWindows ? "adb.exe" : "adb"; commandLine.setExePath(pathManager.getPlatformToolsFolderInAndroidSdk() + "/" + adbCmdName); commandLine.addParameter("kill-server"); return commandLine; } @Nullable private GeneralCommandLine getStopCommand() { if (SystemInfo.isWindows) { GeneralCommandLine commandLine = new GeneralCommandLine(); commandLine.setExePath("taskkill"); commandLine.addParameter("/F"); commandLine.addParameter("/IM"); commandLine.addParameter("emulator-" + platform + ".exe"); return commandLine; } return null; } public void createEmulator() { System.out.println("Creating emulator..."); OutputUtils.checkResult(RunUtils.execute(new RunUtils.RunSettings(getCreateCommand(), "no", true, null, false))); } private GeneralCommandLine createAdbCommand() { GeneralCommandLine commandLine = new GeneralCommandLine(); String adbCmdName = SystemInfo.isWindows ? "adb.exe" : "adb"; commandLine.setExePath(pathManager.getPlatformToolsFolderInAndroidSdk() + "/" + adbCmdName); return commandLine; } public void startServer() { GeneralCommandLine commandLine = createAdbCommand(); commandLine.addParameter("start-server"); System.out.println("Start adb server..."); OutputUtils.checkResult(RunUtils.execute(new RunUtils.RunSettings(commandLine, null, true, "ADB START:", true))); } public void startEmulator() { startServer(); System.out.println("Starting emulator..."); RunUtils.executeOnSeparateThread(new RunUtils.RunSettings(getStartCommand(), null, false, "START: ", true)); printLog(); } public void printLog() { GeneralCommandLine commandLine = createAdbCommand(); commandLine.addParameter("logcat"); commandLine.addParameter("-v"); commandLine.addParameter("time"); commandLine.addParameter("-s"); commandLine.addParameter("dalvikvm:W"); commandLine.addParameter("TestRunner:I"); RunUtils.executeOnSeparateThread(new RunUtils.RunSettings(commandLine, null, false, "LOGCAT: ", true)); } public void waitEmulatorStart() { System.out.println("Waiting for emulator start..."); OutputUtils.checkResult(RunUtils.execute(getWaitCommand())); GeneralCommandLine bootCheckCommand = createAdbCommand(); bootCheckCommand.addParameter("shell"); bootCheckCommand.addParameter("getprop"); bootCheckCommand.addParameter("sys.boot_completed"); int counter = 0; RunResult execute = RunUtils.execute(bootCheckCommand); while (counter < 12) { String output = execute.getOutput(); if (output.trim().endsWith("1")) { System.out.println("Emulator fully booted!"); return; } System.out.println("Waiting for emulator boot (" + counter + ")..."); try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } counter++; execute = RunUtils.execute(bootCheckCommand); } Assert.fail("Can't find booted emulator: " + execute.getOutput()); } public void stopEmulator() { System.out.println("Stopping emulator..."); GeneralCommandLine command = createAdbCommand(); command.addParameter("-s"); command.addParameter("emulator-5554"); command.addParameter("emu"); command.addParameter("kill"); RunUtils.execute(command); if (SystemInfo.isWindows) { //TODO check that command above works on windows and remove this OutputUtils.checkResult(RunUtils.execute(getStopCommand())); } finishProcess("emulator64-" + platform); finishProcess("emulator-" + platform); } //Only for Unix private static void stopDdmsProcess() { if (SystemInfo.isUnix) { GeneralCommandLine listOfEmulatorProcess = new GeneralCommandLine(); listOfEmulatorProcess.setExePath("sh"); listOfEmulatorProcess.addParameter("-c"); listOfEmulatorProcess.addParameter("ps aux | grep emulator"); RunResult runResult = RunUtils.execute(listOfEmulatorProcess); OutputUtils.checkResult(runResult); String pidFromPsCommand = OutputUtils.getPidFromPsCommand(runResult.getOutput()); if (pidFromPsCommand != null) { GeneralCommandLine killCommand = new GeneralCommandLine(); killCommand.setExePath("kill"); killCommand.addParameter(pidFromPsCommand); RunUtils.execute(killCommand); } } } public void finishEmulatorProcesses() { System.out.println("Stopping adb..."); OutputUtils.checkResult(RunUtils.execute(getStopCommandForAdb())); finishProcess("adb"); stopDdmsProcess(); } //Only for Unix private static void finishProcess(String processName) { if (SystemInfo.isUnix) { GeneralCommandLine pidOfProcess = new GeneralCommandLine(); pidOfProcess.setExePath("pidof"); pidOfProcess.addParameter(processName); RunResult runResult = RunUtils.execute(pidOfProcess); String processIdsStr = runResult.getOutput().substring(("pidof " + processName).length()); List<String> processIds = StringUtil.getWordsIn(processIdsStr); for (String pid : processIds) { GeneralCommandLine killCommand = new GeneralCommandLine(); killCommand.setExePath("kill"); killCommand.addParameter("-s"); killCommand.addParameter("9"); killCommand.addParameter(pid); RunUtils.execute(killCommand); } } } public String runTestsViaAdb() { System.out.println("Running tests via adb..."); GeneralCommandLine adbCommand = createAdbCommand(); //adb shell am instrument -w -r org.jetbrains.kotlin.android.tests/android.test.InstrumentationTestRunner adbCommand.addParameters("shell", "am", "instrument", "-w", "-r", "org.jetbrains.kotlin.android.tests/android.test.InstrumentationTestRunner"); RunResult execute = RunUtils.execute(adbCommand); return execute.getOutput(); } private void stopRedundantEmulators(PathManager pathManager) { GeneralCommandLine commandLineForListOfDevices = createAdbCommand(); commandLineForListOfDevices.addParameter("devices"); RunResult runResult = RunUtils.execute(commandLineForListOfDevices); OutputUtils.checkResult(runResult); Matcher matcher = EMULATOR_PATTERN.matcher(runResult.getOutput()); boolean isDdmsStopped = false; while (matcher.find()) { System.out.println("Stopping redundant emulator..."); GeneralCommandLine commandLineForStoppingEmulators = new GeneralCommandLine(); if (SystemInfo.isWindows) { commandLineForStoppingEmulators.setExePath("taskkill"); commandLineForStoppingEmulators.addParameter("/F"); commandLineForStoppingEmulators.addParameter("/IM"); commandLineForStoppingEmulators.addParameter("emulator-arm.exe"); OutputUtils.checkResult(RunUtils.execute(commandLineForStoppingEmulators)); break; } else { if (!isDdmsStopped && SystemInfo.isUnix) { stopEmulator(); stopDdmsProcess(); isDdmsStopped = true; } commandLineForStoppingEmulators.setExePath(pathManager.getPlatformToolsFolderInAndroidSdk() + "/adb"); commandLineForStoppingEmulators.addParameter("-s"); commandLineForStoppingEmulators.addParameter(matcher.group()); commandLineForStoppingEmulators.addParameter("emu"); commandLineForStoppingEmulators.addParameter("kill"); OutputUtils.checkResult(RunUtils.execute(commandLineForStoppingEmulators)); } } OutputUtils.checkResult(RunUtils.execute(commandLineForListOfDevices)); } }