use of com.android.ddmlib.IDevice in project android by JetBrains.
the class AvdManagerConnection method startAvd.
/**
* Launch the given AVD in the emulator.
* @return a future with the device that was launched
*/
@NotNull
public ListenableFuture<IDevice> startAvd(@Nullable final Project project, @NotNull final AvdInfo info) {
if (!initIfNecessary()) {
return Futures.immediateFailedFuture(new RuntimeException("No Android SDK Found"));
}
AccelerationErrorCode error = checkAcceleration();
ListenableFuture<IDevice> errorResult = handleAccelerationError(project, info, error);
if (errorResult != null) {
return errorResult;
}
final File emulatorBinary = getEmulatorBinary();
if (!emulatorBinary.isFile()) {
IJ_LOG.error("No emulator binary found!");
return Futures.immediateFailedFuture(new RuntimeException("No emulator binary found"));
}
final String avdName = info.getName();
// perform the same action here. If it is not stale, then we should show this error and if possible, bring that window to the front.
if (myAvdManager.isAvdRunning(info, SDK_LOG)) {
String baseFolder;
try {
baseFolder = myAvdManager.getBaseAvdFolder().getAbsolutePath();
} catch (AndroidLocation.AndroidLocationException e) {
baseFolder = "$HOME";
}
String message = String.format("AVD %1$s is already running.\n" + "If that is not the case, delete the files at\n" + " %2$s/%1$s.avd/*.lock\n" + "and try again.", avdName, baseFolder);
Messages.showErrorDialog(project, message, "AVD Manager");
return Futures.immediateFailedFuture(new RuntimeException(message));
}
GeneralCommandLine commandLine = new GeneralCommandLine();
commandLine.setExePath(emulatorBinary.getPath());
addParameters(info, commandLine);
EmulatorRunner runner = new EmulatorRunner(commandLine, info);
EmulatorRunner.ProcessOutputCollector collector = new EmulatorRunner.ProcessOutputCollector();
runner.addProcessListener(collector);
final ProcessHandler processHandler;
try {
processHandler = runner.start();
} catch (ExecutionException e) {
IJ_LOG.error("Error launching emulator", e);
return Futures.immediateFailedFuture(new RuntimeException(String.format("Error launching emulator %1$s ", avdName), e));
}
// If we're using qemu2, it has its own progress bar, so put ours in the background. Otherwise show it.
final ProgressWindow p = hasQEMU2Installed() ? new BackgroundableProcessIndicator(project, "Launching Emulator", PerformInBackgroundOption.ALWAYS_BACKGROUND, "", "", false) : new ProgressWindow(false, true, project);
p.setIndeterminate(false);
p.setDelayInMillis(0);
// It takes >= 8 seconds to start the Emulator. Display a small progress indicator otherwise it seems like
// the action wasn't invoked and users tend to click multiple times on it, ending up with several instances of the emulator
ApplicationManager.getApplication().executeOnPooledThread(() -> {
try {
p.start();
p.setText("Starting AVD...");
for (double d = 0; d < 1; d += 1.0 / 80) {
p.setFraction(d);
//noinspection BusyWait
Thread.sleep(100);
if (processHandler.isProcessTerminated()) {
break;
}
}
} catch (InterruptedException ignore) {
} finally {
p.stop();
p.processFinish();
}
processHandler.removeProcessListener(collector);
String message = limitErrorMessage(collector.getText());
if (message.toLowerCase(Locale.ROOT).contains("error") || processHandler.isProcessTerminated() && !message.trim().isEmpty()) {
ApplicationManager.getApplication().invokeLater(() -> Messages.showErrorDialog(project, "Cannot launch AVD in emulator.\nOutput:\n" + message, avdName));
}
});
return EmulatorConnectionListener.getDeviceForEmulator(project, info.getName(), processHandler, 5, TimeUnit.MINUTES);
}
use of com.android.ddmlib.IDevice in project android by JetBrains.
the class AndroidLogcatView method updateLogConsole.
private void updateLogConsole() {
IDevice device = getSelectedDevice();
if (myDevice != device) {
AndroidLogcatService androidLogcatService = AndroidLogcatService.getInstance();
if (myDevice != null) {
androidLogcatService.removeListener(myDevice, myLogcatReceiver);
}
// We check for null, because myLogConsole.clear() depends on myLogConsole.getConsole() not being null
if (myLogConsole.getConsole() != null) {
myLogConsole.clear();
}
myLogFilterModel.processingStarted();
myDevice = device;
androidLogcatService.addListener(myDevice, myLogcatReceiver, true);
}
}
use of com.android.ddmlib.IDevice in project android by JetBrains.
the class DevicePanel method updateDeviceCombo.
private void updateDeviceCombo() {
myIgnoreActionEvents = true;
boolean update = true;
IDevice selected = (IDevice) myDeviceCombo.getSelectedItem();
myDeviceCombo.removeAllItems();
boolean shouldAddSelected = true;
if (myBridge != null) {
for (IDevice device : myBridge.getDevices()) {
myDeviceCombo.addItem(device);
// If we reattach an actual device into Studio, "device" will be the connected IDevice and "selected" will be the disconnected one.
boolean isSelectedReattached = selected != null && !selected.isEmulator() && selected.getSerialNumber().equals(device.getSerialNumber());
if (selected == device || isSelectedReattached) {
myDeviceCombo.setSelectedItem(device);
shouldAddSelected = false;
update = selected != device;
}
}
}
if (selected != null && shouldAddSelected) {
myDeviceCombo.addItem(selected);
myDeviceCombo.setSelectedItem(selected);
}
if (update) {
myDeviceContext.fireDeviceSelected((IDevice) myDeviceCombo.getSelectedItem());
updateClientCombo();
}
myIgnoreActionEvents = false;
}
use of com.android.ddmlib.IDevice in project android by JetBrains.
the class DeviceRenderer method renderDeviceName.
static void renderDeviceName(@NotNull IDevice d, @NotNull ColoredTextContainer component, @Nullable AvdManager avdManager) {
component.setIcon(d.isEmulator() ? AndroidIcons.Ddms.Emulator2 : AndroidIcons.Ddms.RealDevice);
String name;
if (d.isEmulator()) {
String avdName = d.getAvdName();
if (avdManager != null) {
AvdInfo info = avdManager.getAvd(avdName, true);
if (info != null) {
avdName = info.getProperties().get(AvdManager.AVD_INI_DISPLAY_NAME);
}
}
if (avdName == null) {
avdName = "unknown";
}
name = String.format("%1$s %2$s ", AndroidBundle.message("android.emulator"), avdName);
} else {
name = String.format("%1$s %2$s ", DevicePropertyUtil.getManufacturer(d, ""), DevicePropertyUtil.getModel(d, ""));
}
component.append(name, SimpleTextAttributes.REGULAR_ATTRIBUTES);
IDevice.DeviceState deviceState = d.getState();
if (deviceState != IDevice.DeviceState.ONLINE) {
String state = String.format("%1$s [%2$s] ", d.getSerialNumber(), d.getState());
component.append(state, SimpleTextAttributes.GRAYED_BOLD_ATTRIBUTES);
}
if (deviceState != IDevice.DeviceState.DISCONNECTED && deviceState != IDevice.DeviceState.OFFLINE) {
component.append(DevicePropertyUtil.getBuild(d), SimpleTextAttributes.GRAY_ATTRIBUTES);
}
}
use of com.android.ddmlib.IDevice in project android by JetBrains.
the class ConnectJavaDebuggerTask method launchDebugger.
@Override
public ProcessHandler launchDebugger(@NotNull LaunchInfo currentLaunchInfo, @NotNull final Client client, @NotNull ProcessHandlerLaunchStatus launchStatus, @NotNull ProcessHandlerConsolePrinter printer) {
String debugPort = Integer.toString(client.getDebuggerListenPort());
final int pid = client.getClientData().getPid();
Logger.getInstance(ConnectJavaDebuggerTask.class).info(String.format(Locale.US, "Attempting to connect debugger to port %1$s [client %2$d]", debugPort, pid));
// detach old process handler
RunContentDescriptor descriptor = currentLaunchInfo.env.getContentToReuse();
// reach here before the EDT gets around to creating the descriptor?
assert descriptor != null : "ConnectJavaDebuggerTask expects an existing descriptor that will be reused";
final ProcessHandler processHandler = descriptor.getProcessHandler();
assert processHandler != null;
// create a new process handler
RemoteConnection connection = new RemoteConnection(true, "localhost", debugPort, false);
final AndroidRemoteDebugProcessHandler debugProcessHandler = new AndroidRemoteDebugProcessHandler(myProject, myMonitorRemoteProcess);
// switch the launch status and console printers to point to the new process handler
// this is required, esp. for AndroidTestListener which holds a reference to the launch status and printers, and those should
// be updated to point to the new process handlers, otherwise test results will not be forwarded appropriately
launchStatus.setProcessHandler(debugProcessHandler);
printer.setProcessHandler(debugProcessHandler);
// detach after the launch status has been updated to point to the new process handler
processHandler.detachProcess();
AndroidDebugState debugState = new AndroidDebugState(myProject, debugProcessHandler, connection, currentLaunchInfo.consoleProvider);
RunContentDescriptor debugDescriptor;
try {
// @formatter:off
ExecutionEnvironment debugEnv = new ExecutionEnvironmentBuilder(currentLaunchInfo.env).executor(currentLaunchInfo.executor).runner(currentLaunchInfo.runner).contentToReuse(descriptor).build();
debugDescriptor = DebuggerPanelsManager.getInstance(myProject).attachVirtualMachine(debugEnv, debugState, connection, false);
// @formatter:on
} catch (ExecutionException e) {
processHandler.notifyTextAvailable("ExecutionException: " + e.getMessage() + '.', STDERR);
return null;
}
if (debugDescriptor == null) {
processHandler.notifyTextAvailable("Unable to connect debugger to Android application", STDERR);
return null;
}
// re-run the collected text from the old process handler to the new
// TODO: is there a race between messages received once the debugger has been connected, and these messages that are printed out?
final AndroidProcessText oldText = AndroidProcessText.get(processHandler);
if (oldText != null) {
oldText.printTo(debugProcessHandler);
}
RunProfile runProfile = currentLaunchInfo.env.getRunProfile();
int uniqueId = runProfile instanceof RunConfigurationBase ? ((RunConfigurationBase) runProfile).getUniqueID() : -1;
AndroidSessionInfo value = new AndroidSessionInfo(debugProcessHandler, debugDescriptor, uniqueId, currentLaunchInfo.executor.getId(), InstantRunUtils.isInstantRunEnabled(currentLaunchInfo.env));
debugProcessHandler.putUserData(AndroidSessionInfo.KEY, value);
debugProcessHandler.putUserData(AndroidSessionInfo.ANDROID_DEBUG_CLIENT, client);
debugProcessHandler.putUserData(AndroidSessionInfo.ANDROID_DEVICE_API_LEVEL, client.getDevice().getVersion());
final String pkgName = client.getClientData().getClientDescription();
final IDevice device = client.getDevice();
// kill the process when the debugger is stopped
debugProcessHandler.addProcessListener(new ProcessAdapter() {
@Override
public void processTerminated(ProcessEvent event) {
debugProcessHandler.removeProcessListener(this);
Client currentClient = device.getClient(pkgName);
if (currentClient != null && currentClient.getClientData().getPid() != pid) {
// a new process has been launched for the same package name, we aren't interested in killing this
return;
}
Logger.getInstance(ConnectJavaDebuggerTask.class).info("Debugger terminating, so terminating process: " + pkgName);
// Note: client.kill() doesn't work when the debugger is attached, we explicitly stop by package id..
try {
device.executeShellCommand("am force-stop " + pkgName, new NullOutputReceiver());
} catch (Exception e) {
// don't care..
}
}
});
return debugProcessHandler;
}
Aggregations