/* * Copyright (C) 2012 The Android Open Source Project * * 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 com.motorola.studio.android.devices.services.console; import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.sequoyah.device.framework.model.IInstance; import org.eclipse.sequoyah.device.framework.model.handler.IServiceHandler; import org.eclipse.sequoyah.device.framework.model.handler.ServiceHandler; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.PlatformUI; import com.motorola.studio.android.adt.ISerialNumbered; import com.motorola.studio.android.adt.SdkUtils; import com.motorola.studio.android.devices.services.DeviceServicesPlugin; import com.motorola.studio.android.devices.services.DeviceServicesPlugin.IConsoleKilledListener; import com.motorola.studio.android.devices.services.i18n.ServicesNLS; /** * Class responsible to implement the handler for the service * "ADB Shell" */ public class ADBShellHandler extends ServiceHandler { public static final String CONSOLE_NAME = "ADB Shell"; //$NON-NLS-1$ private static final String SERIAL_PARAMETER = "-s"; //$NON-NLS-1$ private static final String SHELL_COMMAND = "shell"; //$NON-NLS-1$ private static final Map<String, Integer> consolesCache = new HashMap<String, Integer>(); private static final Map<String, Process> consolesProcesses = new HashMap<String, Process>(); public ADBShellHandler() { } /* * (non-Javadoc) * @see org.eclipse.sequoyah.device.framework.model.handler.ServiceHandler#newInstance() */ @Override public IServiceHandler newInstance() { return new ADBShellHandler(); } /* * (non-Javadoc) * @see org.eclipse.sequoyah.device.framework.model.handler.ServiceHandler#runService(org.eclipse.sequoyah.device.framework.model.IInstance, java.util.Map, org.eclipse.core.runtime.IProgressMonitor) */ @Override public IStatus runService(IInstance theInstance, Map<Object, Object> arguments, IProgressMonitor monitor) { IStatus status = Status.OK_STATUS; List<String> command = new LinkedList<String>(); final IInstance instance = theInstance; File sdkPath = new File(SdkUtils.getSdkPath()); String adbPath = SdkUtils.getAdbPath(); File adb = new File(adbPath); if ((sdkPath != null) && sdkPath.exists() && sdkPath.isDirectory()) { if (adb.exists() && adb.isFile()) { if (instance instanceof ISerialNumbered) { final String[] serialNumber = new String[1]; serialNumber[0] = ((ISerialNumbered) instance).getSerialNumber(); if (serialNumber[0] == null) { PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() { public void run() { ProgressMonitorDialog dialog = new ProgressMonitorDialog(new Shell(PlatformUI .getWorkbench().getDisplay())); try { dialog.run(false, false, new IRunnableWithProgress() { public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { int limit = 20; SubMonitor theMonitor = SubMonitor.convert(monitor); theMonitor .beginTask( ServicesNLS.ADBShellHandler_WaitingDeviceToLoad, limit); int times = 0; while ((serialNumber[0] == null) && (times < limit)) { theMonitor.worked(1); Thread.sleep(500); serialNumber[0] = ((ISerialNumbered) instance) .getSerialNumber(); times++; } theMonitor.setWorkRemaining(0); } }); } catch (Exception e) { //do nothing } } }); } // Fix a condition that Studio holds the UI thread forever if (serialNumber[0] == null) { status = new Status(IStatus.ERROR, DeviceServicesPlugin.PLUGIN_ID, ServicesNLS.ERR_ADBShellHandler_CouldNotExecuteTheAdbShell); return status; } if (adbPath.contains(" ")) //$NON-NLS-1$ { if (DeviceServicesPlugin.IS_WIN32) { adbPath = "\"" + adbPath + "\""; //$NON-NLS-1$ //$NON-NLS-2$ } else { adbPath = adbPath.replace(" ", "\\ "); //$NON-NLS-1$ //$NON-NLS-2$ } } command.add(adbPath); command.add(SERIAL_PARAMETER); command.add(serialNumber[0]); command.add(SHELL_COMMAND); try { Integer i = consolesCache.get(serialNumber[0]); i = (i == null ? 1 : ++i); consolesCache.put(serialNumber[0], i); String[] cmdArray = command.toArray(new String[4]); StringBuffer sb = new StringBuffer(); for (String cmd : cmdArray) { sb.append(cmd); sb.append(" "); //$NON-NLS-1$ } Process p = Runtime.getRuntime().exec(cmdArray); String consoleName = CONSOLE_NAME + " - " + serialNumber[0]; //$NON-NLS-1$ if (i != null) { consoleName += " (" + i + ")"; //$NON-NLS-1$ //$NON-NLS-2$ } consolesProcesses.put(consoleName, p); DeviceServicesPlugin.redirectProcessStreamsToConsole(p, consoleName); DeviceServicesPlugin.addConsoleKilledListener(listener); } catch (IOException e) { status = new Status(IStatus.ERROR, DeviceServicesPlugin.PLUGIN_ID, ServicesNLS.ERR_ADBShellHandler_CouldNotExecuteTheAdbShell, e); } } } else { status = new Status(IStatus.ERROR, DeviceServicesPlugin.PLUGIN_ID, ServicesNLS.ERR_ADBShellHandler_MissingAdbShell); } } else { status = new Status(IStatus.ERROR, DeviceServicesPlugin.PLUGIN_ID, ServicesNLS.ERR_ADBShellHandler_AndroidSdkIsNotConfigured); } return status; } /* * (non-Javadoc) * @see org.eclipse.sequoyah.device.framework.model.handler.ServiceHandler#updatingService(org.eclipse.sequoyah.device.framework.model.IInstance, org.eclipse.core.runtime.IProgressMonitor) */ @Override public IStatus updatingService(IInstance arg0, IProgressMonitor arg1) { return Status.OK_STATUS; } private final IConsoleKilledListener listener = new IConsoleKilledListener() { public void consoleKilled(String name) { if (consolesProcesses.containsKey(name)) { Process p = consolesProcesses.get(name); p.destroy(); DeviceServicesPlugin.removeConsoleKilledListener(listener); consolesProcesses.remove(name); } } }; }