Home | History | Annotate | Download | only in adt
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.motorola.studio.android.adt;
     18 
     19 import java.io.BufferedReader;
     20 import java.io.File;
     21 import java.io.FileNotFoundException;
     22 import java.io.IOException;
     23 import java.io.InputStream;
     24 import java.io.InputStreamReader;
     25 import java.io.OutputStream;
     26 import java.util.ArrayList;
     27 import java.util.Collection;
     28 import java.util.HashMap;
     29 import java.util.HashSet;
     30 import java.util.LinkedHashMap;
     31 import java.util.List;
     32 import java.util.Map;
     33 import java.util.Properties;
     34 import java.util.Set;
     35 import java.util.concurrent.TimeoutException;
     36 import java.util.regex.Matcher;
     37 import java.util.regex.Pattern;
     38 
     39 import org.eclipse.core.runtime.IProgressMonitor;
     40 import org.eclipse.core.runtime.IStatus;
     41 import org.eclipse.core.runtime.NullProgressMonitor;
     42 import org.eclipse.core.runtime.Path;
     43 import org.eclipse.core.runtime.Status;
     44 import org.eclipse.core.runtime.SubMonitor;
     45 import org.eclipse.jface.preference.IPreferenceStore;
     46 import org.eclipse.osgi.util.NLS;
     47 import org.eclipse.swt.widgets.Shell;
     48 import org.eclipse.ui.PlatformUI;
     49 
     50 import com.android.ddmlib.AdbCommandRejectedException;
     51 import com.android.ddmlib.AndroidDebugBridge;
     52 import com.android.ddmlib.AndroidDebugBridge.IClientChangeListener;
     53 import com.android.ddmlib.Client;
     54 import com.android.ddmlib.ClientData;
     55 import com.android.ddmlib.EmulatorConsole;
     56 import com.android.ddmlib.FileListingService;
     57 import com.android.ddmlib.FileListingService.FileEntry;
     58 import com.android.ddmlib.IDevice;
     59 import com.android.ddmlib.IDevice.DeviceState;
     60 import com.android.ddmlib.MultiLineReceiver;
     61 import com.android.ddmlib.SyncException;
     62 import com.android.ddmlib.SyncService;
     63 import com.android.ddmlib.SyncService.ISyncProgressMonitor;
     64 import com.android.ide.eclipse.adt.AdtPlugin;
     65 import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs;
     66 import com.android.ide.eclipse.ddms.DdmsPlugin;
     67 import com.motorola.studio.android.AndroidPlugin;
     68 import com.motorola.studio.android.adt.StudioAndroidEventManager.EventType;
     69 import com.motorola.studio.android.common.IAndroidConstants;
     70 import com.motorola.studio.android.common.exception.AndroidException;
     71 import com.motorola.studio.android.common.log.StudioLogger;
     72 import com.motorola.studio.android.i18n.AndroidNLS;
     73 import com.motorola.studio.android.utilities.TelnetFrameworkAndroid;
     74 
     75 /**
     76  * DESCRIPTION:
     77  * This class is the common interface to functionalities from DDMS
     78  *
     79  * RESPONSIBILITY:
     80  * Centralizes the access to DDMS.
     81  *
     82  * COLABORATORS:
     83  * None.
     84  *
     85  * USAGE:
     86  * Use the public methods to use DDMS
     87  */
     88 public class DDMSFacade
     89 {
     90     /**
     91      * Command for switching back to USB connection mode.
     92      */
     93     private static final String USB_SWITCH_BACK_COMMAND = "usb"; //$NON-NLS-1$
     94 
     95     /**
     96      * Argument which indicates the device to apply a certain command.
     97      */
     98     private static final String DEVICE_ID_INDICATOR = "-s"; //$NON-NLS-1$
     99 
    100     private static final String DEFAULT_WIRELESS_DEVICE_PROPERTY = "tiwlan0"; //$NON-NLS-1$
    101 
    102     /**
    103      * Map containing all connected devices.
    104      * It is being kept for us not to depend on ADT every time we need one, preventing
    105      * deadlocks.
    106      */
    107     private static final Map<String, IDevice> connectedDevices = new HashMap<String, IDevice>();
    108 
    109     /**
    110      * Set containing the serial numbers of the devices completely loaded.
    111      * A device is considered completely loaded if it has already loaded the HOME application.
    112      */
    113     private static final Set<String> completelyUpDevices = new HashSet<String>();
    114 
    115     /**
    116      * Folder located inside the SDK folder containing some sdk tools.
    117      */
    118     static final String TOOLS_FOLDER = IAndroidConstants.FD_TOOLS;
    119 
    120     /**
    121      * Folder located inside the SDK folder and containing the ADB.
    122      */
    123     static final String PLATFORM_TOOLS_FOLDER = IAndroidConstants.FD_PLATFORM_TOOLS;
    124 
    125     /**
    126      * adb (android debug bridge) command.
    127      */
    128     static final String ADB_COMMAND = "adb"; //$NON-NLS-1$
    129 
    130     /**
    131      * Command to concatenate with "adb" to have the device shell.
    132      */
    133     static final String SHELL_CMD = "shell"; //$NON-NLS-1$
    134 
    135     /**
    136      * Options to be used with adb to indicate run operation.
    137      */
    138     private static final String AM_CMD = "am"; //$NON-NLS-1$
    139 
    140     /**
    141      * Command to concatenate with "am" to have an activity executed at the device.
    142      */
    143     private static final String START_CMD = "start"; //$NON-NLS-1$
    144 
    145     /**
    146      * Parameter for running in debug mode.
    147      */
    148     private static final String ADB_AM_DEBUG = "-D"; //$NON-NLS-1$
    149 
    150     /**
    151      * Parameter provided before the application package/name.
    152      */
    153     private static final String ADB_AM_NAME = "-n"; //$NON-NLS-1$
    154 
    155     /**
    156      * Parameter for selecting emulator instance.
    157      */
    158     static final String ADB_INSTANCE_PARAMETER = DEVICE_ID_INDICATOR; //$NON-NLS-1$
    159 
    160     /**
    161      * Folder for the SDK.
    162      */
    163     private static final String SDCARD_FOLDER = "sdcard"; //$NON-NLS-1$
    164 
    165     /**
    166      * Folder for the SDK.
    167      */
    168     private static final String MNT_SDCARD_FOLDER = "mnt/sdcard"; //$NON-NLS-1$
    169 
    170     /*
    171      * TCP/IP
    172      */
    173     private static final String CONNECT_TCPIP_CMD = "connect"; //$NON-NLS-1$
    174 
    175     private static final String DISCONNECT_TCPIP_CMD = "disconnect"; //$NON-NLS-1$
    176 
    177     private static final String TCPIP_CMD = "tcpip"; //$NON-NLS-1$
    178 
    179     private static final String IFCONFIG_CMD = "ifconfig"; //$NON-NLS-1$
    180 
    181     static Object consoleLock = new Object();
    182 
    183     private static Map<String, String> avdNameMap = new HashMap<String, String>();
    184 
    185     /**
    186      * Property from device which represents the wi-fi value to use ipconfig command.
    187      */
    188     private static final String WIFI_INTERFACE_DEVICE_PROPERTY = "wifi.interface"; //$NON-NLS-1$
    189 
    190     // IP validation
    191     private static final String ZERO_TO_255_PATTERN =
    192             "((\\d)|(\\d\\d)|([0-1]\\d\\d)|(2[0-4]\\d)|(25[0-5]))"; //$NON-NLS-1$
    193 
    194     private static final String IP_PATTERN = "(" + ZERO_TO_255_PATTERN + "\\." //$NON-NLS-1$ //$NON-NLS-2$
    195             + ZERO_TO_255_PATTERN + "\\." + ZERO_TO_255_PATTERN + "\\." + ZERO_TO_255_PATTERN //$NON-NLS-1$ //$NON-NLS-2$
    196             + ")+"; //$NON-NLS-1$
    197 
    198     /**
    199      * Must be called only once, during AndroidPlugin start-up.
    200      * This method configures all necessary device listeners.
    201      */
    202     public static void setup()
    203     {
    204         AndroidPlugin.getDefault().addSDKLoaderListener(new Runnable()
    205         {
    206 
    207             public void run()
    208             {
    209                 AndroidDebugBridge adb = AndroidDebugBridge.getBridge();
    210                 if (adb == null)
    211                 {
    212                     AndroidDebugBridge.disconnectBridge();
    213                     DdmsPlugin.setToolsLocation(AdtPlugin.getOsAbsoluteAdb(), true,
    214                             AdtPlugin.getOsAbsoluteHprofConv(), AdtPlugin.getOsAbsoluteTraceview());
    215                 }
    216 
    217                 if (adb != null)
    218                 {
    219                     IDevice[] x = adb.getDevices();
    220                     IDevice[] newDevices = x;
    221                     List<IDevice> oldDevList = new ArrayList<IDevice>(connectedDevices.values());
    222 
    223                     for (IDevice newDev : newDevices)
    224                     {
    225                         String serialNum = newDev.getSerialNumber();
    226                         if (connectedDevices.containsKey(serialNum))
    227                         {
    228                             IDevice oldDev = connectedDevices.get(serialNum);
    229                             oldDevList.remove(oldDev);
    230                             if (oldDev.getState().compareTo((newDev).getState()) != 0)
    231                             {
    232                                 if ((newDev).getState() == DeviceState.OFFLINE)
    233                                 {
    234                                     deviceDisconnected(newDev);
    235                                 }
    236                                 else if ((newDev).getState() == DeviceState.ONLINE)
    237                                 {
    238                                     deviceConnected(newDev);
    239                                 }
    240                             }
    241                         }
    242                         else
    243                         {
    244                             deviceConnected(newDev);
    245                         }
    246                     }
    247 
    248                     for (IDevice oldDev : oldDevList)
    249                     {
    250                         deviceDisconnected(oldDev);
    251                     }
    252                 }
    253 
    254             }
    255         });
    256 
    257         // Adds listener for the HOME application. It adds the serial number of the
    258         // device to a collection when it identifies that the HOME application has
    259         // loaded
    260         AndroidDebugBridge.addClientChangeListener(new IClientChangeListener()
    261         {
    262 
    263             public void clientChanged(Client client, int changeMask)
    264             {
    265                 if ((changeMask & Client.CHANGE_NAME) == Client.CHANGE_NAME)
    266                 {
    267                     final Client finalClient = client;
    268                     Thread t = new Thread()
    269                     {
    270 
    271                         @Override
    272                         public void run()
    273                         {
    274                             String applicationName =
    275                                     finalClient.getClientData().getClientDescription();
    276                             if (applicationName != null)
    277                             {
    278                                 IPreferenceStore store =
    279                                         AdtPlugin.getDefault().getPreferenceStore();
    280                                 String home = store.getString(AdtPrefs.PREFS_HOME_PACKAGE);
    281                                 if (home.equals(applicationName))
    282                                 {
    283                                     String serialNum = finalClient.getDevice().getSerialNumber();
    284                                     synchronized (completelyUpDevices)
    285                                     {
    286                                         StudioLogger.debug("Completely Up Device: " + serialNum); //$NON-NLS-1$
    287                                         completelyUpDevices.add(serialNum);
    288                                     }
    289                                 }
    290                             }
    291                         }
    292                     };
    293                     t.start();
    294                 }
    295             }
    296         });
    297     }
    298 
    299     static void deviceStatusChanged(IDevice device)
    300     {
    301         StudioLogger.debug("Device changed: " + device.getSerialNumber()); //$NON-NLS-1$
    302         synchronized (connectedDevices)
    303         {
    304             connectedDevices.put(device.getSerialNumber(), device);
    305         }
    306         if ((device).getState() == DeviceState.ONLINE)
    307         {
    308             IPreferenceStore store = AdtPlugin.getDefault().getPreferenceStore();
    309             String home = store.getString(AdtPrefs.PREFS_HOME_PACKAGE);
    310             if (device.getClient(home) != null)
    311             {
    312                 synchronized (completelyUpDevices)
    313                 {
    314                     StudioLogger.debug("Completely Up Device: " + device.getSerialNumber()); //$NON-NLS-1$
    315                     if (!completelyUpDevices.contains(device.getSerialNumber()))
    316                     {
    317                         completelyUpDevices.add(device.getSerialNumber());
    318                     }
    319                 }
    320             }
    321         }
    322     }
    323 
    324     /**
    325      * Registers a device as connected
    326      *
    327      * @param device
    328      */
    329     static void deviceConnected(IDevice device)
    330     {
    331         final String serialNumber = device.getSerialNumber();
    332         StudioLogger.debug("Device connected: " + serialNumber); //$NON-NLS-1$
    333         synchronized (connectedDevices)
    334         {
    335             connectedDevices.put(serialNumber, device);
    336         }
    337 
    338         if (!device.isEmulator() && !device.hasClients())
    339         {
    340             boolean timeout = false;
    341             long startTime = System.currentTimeMillis();
    342             int maxInterval = 10000;
    343             do
    344             {
    345                 try
    346                 {
    347                     Thread.sleep(250);
    348                 }
    349                 catch (InterruptedException e)
    350                 {
    351                     //do nothing
    352                 }
    353                 long currentTime = System.currentTimeMillis();
    354                 timeout = ((startTime + maxInterval) < currentTime);
    355 
    356             }
    357             while (!device.hasClients() && !timeout);
    358             if (timeout)
    359             {
    360                 synchronized (completelyUpDevices)
    361                 {
    362                     //put the device up anyway.
    363                     completelyUpDevices.add(serialNumber);
    364                 }
    365             }
    366         }
    367 
    368         if (device.hasClients())
    369         {
    370             // When a device is connected, look for the HOME application and add
    371             // the device serial number to a collection if it is already running.
    372             IPreferenceStore store = AdtPlugin.getDefault().getPreferenceStore();
    373             String home = store.getString(AdtPrefs.PREFS_HOME_PACKAGE);
    374             if (device.getClient(home) != null)
    375             {
    376                 StudioLogger.debug("Completely Up Device: " + serialNumber); //$NON-NLS-1$
    377                 synchronized (completelyUpDevices)
    378                 {
    379                     completelyUpDevices.add(serialNumber);
    380                 }
    381             }
    382         }
    383 
    384         StudioAndroidEventManager.fireEvent(EventType.DEVICE_CONNECTED, serialNumber);
    385     }
    386 
    387     /**
    388      * Unregisters a device as connected
    389      *
    390      * @param device
    391      */
    392     static void deviceDisconnected(IDevice device)
    393     {
    394         final String serialNumber = device.getSerialNumber();
    395         StudioLogger.debug("Device disconnected: " + serialNumber); //$NON-NLS-1$
    396         synchronized (completelyUpDevices)
    397         {
    398             completelyUpDevices.remove(serialNumber);
    399         }
    400         synchronized (connectedDevices)
    401         {
    402             connectedDevices.remove(serialNumber);
    403         }
    404         StudioAndroidEventManager.fireEvent(EventType.DEVICE_DISCONNECTED, serialNumber);
    405         avdNameMap.remove(device.getSerialNumber());
    406 
    407     }
    408 
    409     /**
    410      * Get all connected device serial numbers
    411      *
    412      * @return
    413      */
    414     public static Collection<String> getConnectedSerialNumbers()
    415     {
    416         return connectedDevices.keySet();
    417     }
    418 
    419     /**
    420      * Get the Device associated with the given serial number
    421      *
    422      * @param serialNumber Serial number of the device to retrieve
    423      * @return Device associated with the given serial number
    424      */
    425     public static IDevice getDeviceBySerialNumber(String serialNumber)
    426     {
    427         return connectedDevices.get(serialNumber);
    428     }
    429 
    430     /**
    431      * Runs an activity at the given device
    432      *
    433      * @param serialNumber The serial number of the device to have the activity executed
    434      * @param activityName The activity to execute
    435      * @param debugMode Whether the activity shall be run in debug mode or not
    436      * @param processOut The output stream of the process running "adb"
    437      *
    438      * @return An IStatus object with the result of the operation
    439      */
    440     public static IStatus runActivity(String serialNumber, String activityName, boolean debugMode,
    441             OutputStream processOut)
    442     {
    443         IStatus status = Status.OK_STATUS;
    444 
    445         // Return if no instance is selected
    446         if (serialNumber == null)
    447         {
    448             StudioLogger.error("Abort run operation. Serial number is null."); //$NON-NLS-1$
    449             return new Status(IStatus.ERROR, AndroidPlugin.PLUGIN_ID,
    450                     AndroidNLS.ERR_DDMSFacade_SerialNumberNullPointer);
    451         }
    452 
    453         // Return if instance is not started
    454         if (!isDeviceOnline(serialNumber))
    455         {
    456             StudioLogger.error("Abort run operation. Device is not online."); //$NON-NLS-1$
    457             return new Status(IStatus.ERROR, AndroidPlugin.PLUGIN_ID, ""); //$NON-NLS-1$
    458         }
    459 
    460         try
    461         {
    462             String[] cmd = createRunCommand(serialNumber, activityName, debugMode);
    463             executeCommand(cmd, processOut);
    464         }
    465         catch (IOException e)
    466         {
    467             StudioLogger.error("Deploy: Could not execute adb install command."); //$NON-NLS-1$
    468             status = new Status(IStatus.ERROR, AndroidPlugin.PLUGIN_ID, e.getMessage());
    469         }
    470 
    471         return status;
    472     }
    473 
    474     static String executeCommand(String[] cmd, OutputStream out) throws IOException
    475     {
    476         return executeCommand(cmd, out, null);
    477     }
    478 
    479     /**
    480      * DOCUMENT ME!!
    481      * @param cmd
    482      * @param out
    483      * @param serialNumber
    484      * @return
    485      * @throws IOException
    486      */
    487     static String executeCommand(String[] cmd, OutputStream out, String serialNumber)
    488             throws IOException
    489     {
    490         String fullCmd = ""; //$NON-NLS-1$
    491         if (out != null)
    492         {
    493             for (String cmdArg : cmd)
    494             {
    495                 fullCmd += cmdArg + " "; //$NON-NLS-1$
    496             }
    497             out.write(fullCmd.getBytes());
    498             out.write("\n".getBytes()); //$NON-NLS-1$
    499         }
    500 
    501         Runtime r = Runtime.getRuntime();
    502         Process p = r.exec(cmd);
    503 
    504         String command_results = ""; //$NON-NLS-1$
    505         InputStream processIn = p.getInputStream();
    506         final BufferedReader br = new BufferedReader(new InputStreamReader(processIn));
    507         String line;
    508         try
    509         {
    510             while ((line = br.readLine()) != null)
    511             {
    512                 command_results += line;
    513                 command_results += "\n"; //$NON-NLS-1$
    514                 if (out != null)
    515                 {
    516                     if (serialNumber != null)
    517                     {
    518                         out.write((serialNumber + ": ").getBytes()); //$NON-NLS-1$
    519                     }
    520                     out.write(line.getBytes());
    521                     out.write("\n".getBytes()); //$NON-NLS-1$
    522                 }
    523             }
    524         }
    525         finally
    526         {
    527             br.close();
    528         }
    529 
    530         return command_results;
    531     }
    532 
    533     /**
    534      * See http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html
    535      * to understand how Process.exec works and its problems
    536      *
    537      * @param cmd Command to be executed.
    538      * @param out Output Stream.
    539      * @param timeout Timeout (secs.)
    540      * @param monitor {@link IProgressMonitor}
    541      *
    542      * @return the {@link IStatus} of this process execution.
    543      *
    544      * @throws IOException Exception thrown in case there is any problem
    545      * executing the command.
    546      */
    547     private static IStatus executeRemoteDevicesCommand(String[] cmd, OutputStream out, int timeout,
    548             String timeoutMsg, IStopCondition stopCondition, IProgressMonitor monitor)
    549             throws IOException
    550     {
    551 
    552         IStatus status = Status.OK_STATUS;
    553 
    554         long timeoutLimit = -1;
    555         if (timeout != 0)
    556         {
    557             timeoutLimit = System.currentTimeMillis() + (timeout * 1000);
    558         }
    559 
    560         String fullCmd = ""; //$NON-NLS-1$
    561         for (String cmdArg : cmd)
    562         {
    563             fullCmd += cmdArg + " "; //$NON-NLS-1$
    564         }
    565         if (out != null)
    566         {
    567             out.write(fullCmd.getBytes());
    568             out.write("\n".getBytes()); //$NON-NLS-1$
    569         }
    570 
    571         Runtime r = Runtime.getRuntime();
    572         Process p = r.exec(cmd);
    573 
    574         int errorCode = 0;
    575 
    576         //  inputStream / errorStream;
    577         String[] commandResults = new String[]
    578         {
    579                 "", "" //$NON-NLS-1$ //$NON-NLS-2$
    580         };
    581 
    582         commandResults =
    583                 readCmdOutputFromStreams(commandResults[0], commandResults[1], p.getInputStream(),
    584                         p.getErrorStream(), out);
    585 
    586         while (!stopCondition.canStop())
    587         {
    588             if ((monitor != null) && (monitor.isCanceled()))
    589             {
    590                 p.destroy();
    591                 return Status.CANCEL_STATUS;
    592             }
    593 
    594             try
    595             {
    596                 errorCode = p.exitValue();
    597                 if (errorCode != 0)
    598                 {
    599                     break;
    600                 }
    601 
    602             }
    603             catch (IllegalThreadStateException e)
    604             {
    605                 // Process is still running... Proceed with loop
    606             }
    607 
    608             try
    609             {
    610                 Thread.sleep(1000);
    611             }
    612             catch (InterruptedException e)
    613             {
    614                 StudioLogger.error("Execute command: thread has been interrupted"); //$NON-NLS-1$
    615             }
    616 
    617             if (timeout > 0)
    618             {
    619                 try
    620                 {
    621                     testTimeout(timeoutLimit, ((timeoutMsg != null) ? timeoutMsg
    622                             : AndroidNLS.ERR_GenericTimeout));
    623                 }
    624                 catch (TimeoutException e)
    625                 {
    626                     p.destroy();
    627                     StudioLogger.debug("The timeout " + timeout //$NON-NLS-1$
    628                             + " has been reached when executing the command " + fullCmd); //$NON-NLS-1$
    629                     return new Status(IStatus.ERROR, AndroidPlugin.PLUGIN_ID, e.getMessage(), e);
    630                 }
    631             }
    632 
    633         }
    634 
    635         commandResults =
    636                 readCmdOutputFromStreams(commandResults[0], commandResults[1], p.getInputStream(),
    637                         p.getErrorStream(), out);
    638 
    639         if (errorCode != 0)
    640         {
    641             StudioLogger.debug("Command " + cmd + " returned an error code: " + errorCode); //$NON-NLS-1$ //$NON-NLS-2$
    642             status =
    643                     new Status(IStatus.ERROR, AndroidPlugin.PLUGIN_ID, NLS.bind(
    644                             AndroidNLS.ERR_CommandError, errorCode) + "\n" //$NON-NLS-1$
    645                             + ((!commandResults[1].equals("")) ? commandResults[1] //$NON-NLS-1$
    646                                     : commandResults[0]));
    647         }
    648         else
    649         {
    650             status = new Status(IStatus.OK, AndroidPlugin.PLUGIN_ID, commandResults[0]);
    651         }
    652 
    653         return status;
    654     }
    655 
    656     /**
    657      * Defines a stop condition
    658      */
    659     interface IStopCondition
    660     {
    661         public boolean canStop();
    662     }
    663 
    664     /**
    665      * @param commandResults
    666      * @param errorResults
    667      * @param inputStream
    668      * @param errorStream
    669      * @param out
    670      */
    671     private static String[] readCmdOutputFromStreams(String commandResults, String errorResults,
    672             InputStream inputStream, InputStream errorStream, OutputStream out)
    673     {
    674         String[] results = new String[2];
    675         String line = ""; //$NON-NLS-1$
    676 
    677         BufferedReader brInput = new BufferedReader(new InputStreamReader(inputStream));
    678         BufferedReader brError = new BufferedReader(new InputStreamReader(errorStream));
    679 
    680         try
    681         {
    682 
    683             // input stream
    684             if (brInput.ready())
    685             {
    686                 while ((line = brInput.readLine()) != null)
    687                 {
    688                     commandResults += line;
    689                     commandResults += "\n"; //$NON-NLS-1$
    690                     if (out != null)
    691                     {
    692                         out.write(line.getBytes());
    693                         out.write("\n".getBytes()); //$NON-NLS-1$
    694                     }
    695                 }
    696             }
    697 
    698             // error stream
    699             if (brError.ready())
    700             {
    701                 while ((line = brError.readLine()) != null)
    702                 {
    703                     errorResults += "\n"; //$NON-NLS-1$
    704                     if (out != null)
    705                     {
    706                         out.write(line.getBytes());
    707                         out.write("\n".getBytes()); //$NON-NLS-1$
    708                     }
    709                 }
    710             }
    711         }
    712         catch (IOException e)
    713         {
    714             StudioLogger.error("Cannot read command outputs"); //$NON-NLS-1$
    715         }
    716         finally
    717         {
    718             try
    719             {
    720                 brInput.close();
    721                 brError.close();
    722             }
    723             catch (IOException e)
    724             {
    725                 StudioLogger.error("Could not close console stream: " + e.getMessage());
    726             }
    727         }
    728 
    729         results[0] = commandResults;
    730         results[1] = errorResults;
    731 
    732         return results;
    733 
    734     }
    735 
    736     /**
    737      * Checks if the timeout limit has reached.
    738      *
    739      * @param timeoutLimit The system time limit that cannot be overtaken, in milliseconds.
    740      * @throws StartTimeoutException When the system time limit is overtaken.
    741      */
    742     private static void testTimeout(long timeoutLimit, String timeoutErrorMessage)
    743             throws TimeoutException
    744     {
    745         if (System.currentTimeMillis() > timeoutLimit)
    746         {
    747             throw new TimeoutException(timeoutErrorMessage);
    748         }
    749     }
    750 
    751     /**
    752      * Creates a string with the command that should
    753      * be called in order to run the application.
    754      */
    755     private static String[] createRunCommand(String serialNumber, String activityName,
    756             boolean debugMode)
    757     {
    758         String cmd[];
    759         String sdkPath = SdkUtils.getSdkPath();
    760 
    761         // The tools folder should exist and be here, but double-cheking
    762         // once more wont kill
    763         File f = new File(sdkPath + PLATFORM_TOOLS_FOLDER + File.separator);
    764         if (!f.exists())
    765         {
    766             StudioLogger
    767                     .error("Run: Could not find tools folder on " + sdkPath + PLATFORM_TOOLS_FOLDER //$NON-NLS-1$
    768                             + File.separator);
    769         }
    770         else
    771         {
    772             if (!f.isDirectory())
    773             {
    774                 StudioLogger.error("Run: Invalid tools folder " + sdkPath + PLATFORM_TOOLS_FOLDER //$NON-NLS-1$
    775                         + File.separator);
    776             }
    777         }
    778 
    779         String completeAppPath =
    780                 activityName.substring(0, activityName.lastIndexOf(".")) + "/" + activityName; //$NON-NLS-1$ //$NON-NLS-2$
    781         if (debugMode)
    782         {
    783             // If debugMode option is checked, create command with the -D paramater
    784             String cmdTemp[] =
    785                     {
    786                             sdkPath + PLATFORM_TOOLS_FOLDER + File.separator + ADB_COMMAND,
    787                             ADB_INSTANCE_PARAMETER, serialNumber, SHELL_CMD, AM_CMD, START_CMD,
    788                             ADB_AM_DEBUG, ADB_AM_NAME, completeAppPath
    789                     };
    790             cmd = cmdTemp;
    791         }
    792         else
    793         {
    794             // If debugMode option is unchecked, create command without the -D paramater
    795             String cmdTemp[] =
    796                     {
    797                             sdkPath + PLATFORM_TOOLS_FOLDER + File.separator + ADB_COMMAND,
    798                             ADB_INSTANCE_PARAMETER, serialNumber, SHELL_CMD, AM_CMD, START_CMD,
    799                             ADB_AM_NAME, completeAppPath
    800                     };
    801             cmd = cmdTemp;
    802         }
    803 
    804         return cmd;
    805     }
    806 
    807     /**
    808      * Check if the device is Online (i.e. if it's possible to communicate with it)
    809      * Notice it is a verification of the status of the Device which may be different than the status of the Tml Instance.
    810      *
    811      * @param serialNumber
    812      * @return true if the Device is online, false otherwise
    813      */
    814     public static boolean isDeviceOnline(String serialNumber)
    815     {
    816         IDevice device = getDeviceBySerialNumber(serialNumber);
    817         if ((device == null) || !device.isOnline())
    818         {
    819             return false;
    820         }
    821         return true;
    822     }
    823 
    824     /**
    825      * Return true if the Device is being shown on the OFFLINE state.
    826      *
    827      * @param serialNumber Devices serial number.
    828      *
    829      * @return <code>true</code> in case the Device if offline,
    830      * <code>false</code> otherwise.
    831      */
    832     public static boolean isDeviceOffline(String serialNumber)
    833     {
    834 
    835         IDevice device = getDeviceBySerialNumber(serialNumber);
    836         return ((device == null) || ((device != null) && device.isOffline()));
    837     }
    838 
    839     /**
    840      * Check if the device is completely loaded
    841      * A device is completely loaded when it loads the HOME application
    842      *
    843      * @param serialNumber
    844      * @return true if the Device has completely loaded; false otherwise
    845      */
    846     public static boolean isDeviceCompletelyLoaded(String serialNumber)
    847     {
    848         return completelyUpDevices.contains(serialNumber);
    849     }
    850 
    851     /**
    852      * Tests if the device represented by the serial number (if it exists) is an emulator
    853      *
    854      * @param serialNumber
    855      * @return true if it is an emulator, false if not or non existent
    856      */
    857     public static boolean isEmulator(String serialNumber)
    858     {
    859         IDevice device = getDeviceBySerialNumber(serialNumber);
    860         if ((device != null) && device.isEmulator())
    861         {
    862             return true;
    863         }
    864         return false;
    865     }
    866 
    867     public static boolean isRemote(String serialNumber)
    868     {
    869         // firstly, test if the serial number has the format "anything:digits"
    870         Pattern p = Pattern.compile("(.)+:(\\d)+"); //$NON-NLS-1$
    871         Matcher m = p.matcher(serialNumber);
    872         if (m.matches())
    873         {
    874             IDevice device = getDeviceBySerialNumber(serialNumber);
    875             if ((device != null) && !device.isEmulator())
    876             {
    877                 return true;
    878             }
    879         }
    880 
    881         return false;
    882     }
    883 
    884     /**
    885      * Execute an app in the Device
    886      *
    887      * @param serialNumber Serial number of the device where to execute the command
    888      * @param remoteCommand command to be executed remotely on the Device
    889      * @param monitor monitor associated with the operation
    890      *
    891      * @return The lines read from the command output
    892      *
    893      * @throws IOException
    894      */
    895     public static Collection<String> execRemoteApp(String serialNumber, String remoteCommand,
    896             final IProgressMonitor monitor) throws IOException
    897     {
    898         return executeShellCmd(serialNumber, remoteCommand, monitor);
    899     }
    900 
    901     /**
    902      * Execute an app in the Device
    903      *
    904      * @param serialNumber Serial number of the device where to execute the command
    905      * @param remoteCommands commands to be executed remotely on the Device
    906      * @param monitor monitor associated with the operation
    907      *
    908      * @throws IOException
    909      */
    910     public static Map<String, Collection<String>> execRemoteApp(String serialNumber,
    911             Collection<String> remoteCommands, final IProgressMonitor monitor) throws IOException
    912     {
    913         Map<String, Collection<String>> cmdAnswers =
    914                 new LinkedHashMap<String, Collection<String>>();
    915         for (String remoteCommand : remoteCommands)
    916         {
    917             StudioLogger.debug(remoteCommand);
    918             Collection<String> answers = executeShellCmd(serialNumber, remoteCommand, monitor);
    919             cmdAnswers.put(remoteCommand, answers);
    920         }
    921 
    922         return cmdAnswers;
    923     }
    924 
    925     private static Collection<String> executeShellCmd(String serialNumber, final String cmd,
    926             final IProgressMonitor monitor)
    927     {
    928         final Collection<String> results = new ArrayList<String>();
    929         IDevice d = getDeviceBySerialNumber(serialNumber);
    930         if (d != null)
    931         {
    932             try
    933             {
    934                 d.executeShellCommand(cmd, new MultiLineReceiver()
    935                 {
    936                     public boolean isCancelled()
    937                     {
    938                         return monitor.isCanceled();
    939                     }
    940 
    941                     @Override
    942                     public void processNewLines(String[] lines)
    943                     {
    944                         for (String line : lines)
    945                         {
    946                             if ((!line.equals("")) && (!line.equals(cmd))) //$NON-NLS-1$
    947                             {
    948                                 results.add(line);
    949                             }
    950                         }
    951                     }
    952                 }, 0);
    953             }
    954             catch (Exception e)
    955             {
    956                 StudioLogger.error(DDMSFacade.class, "Error executing shell command " + cmd //$NON-NLS-1$
    957                         + " at device " + serialNumber, e); //$NON-NLS-1$
    958             }
    959         }
    960         return results;
    961     }
    962 
    963     /**
    964      * Retrieves all properties from the device with provided serial number.
    965      * @param serialNumber
    966      * @return
    967      */
    968     public static Properties getDeviceProperties(String serialNumber)
    969     {
    970         Properties instanceProperties = new Properties();
    971         if (serialNumber != null)
    972         {
    973             String key = ""; //$NON-NLS-1$
    974             String value = ""; //$NON-NLS-1$
    975             Collection<String> lines;
    976             try
    977             {
    978                 lines = execRemoteApp(serialNumber, "getprop", new NullProgressMonitor()); //$NON-NLS-1$
    979 
    980                 for (String line : lines)
    981                 {
    982                     String[] split = line.split("]:"); //$NON-NLS-1$
    983                     if (split.length >= 2)
    984                     {
    985                         if (!split[0].equals("")) //$NON-NLS-1$
    986                         {
    987                             key = split[0].substring(1, split[0].length());
    988                             if (!split[1].equals("")) //$NON-NLS-1$
    989                             {
    990                                 value = split[1].substring(2, split[1].length() - 1);
    991                                 instanceProperties.setProperty(key, value);
    992                             }
    993                         }
    994 
    995                     }
    996                 }
    997             }
    998             catch (IOException e)
    999             {
   1000                 StudioLogger.error("IOException while executing an app on device. "
   1001                         + e.getMessage());
   1002             }
   1003         }
   1004         return instanceProperties;
   1005     }
   1006 
   1007     /**
   1008     * Retrieves a given property from the device with provided serial number.
   1009     *
   1010     * @param serialNumber
   1011     * @param propertyName
   1012     *
   1013     * @return
   1014     */
   1015     public static String getDeviceProperty(String serialNumber, String propertyName)
   1016     {
   1017         String result = null;
   1018         IDevice device = DDMSFacade.getDeviceBySerialNumber(serialNumber);
   1019         if (device != null)
   1020         {
   1021             result = device.getProperty(propertyName);
   1022         }
   1023         return result;
   1024     }
   1025 
   1026     /**
   1027      * Get the name of the VM associated to the emulator running in the given deviceSerial identification.
   1028      *
   1029      * @param deviceSerial identification of the emulator whose vm name must be retrieved.
   1030      * @return the name of the VM used by the emulator running with the given id,
   1031      * or null if the vmname could be retrieved.
   1032      */
   1033     public static String getVmName(final IDevice d)
   1034     {
   1035         String vmName = null;
   1036         String serialNumber = d.getSerialNumber();
   1037         int MAX_TRIES = 120;
   1038         int tries = 0;
   1039 
   1040         while ((vmName == null) && (tries < MAX_TRIES))
   1041         {
   1042             synchronized (avdNameMap)
   1043             {
   1044                 vmName = avdNameMap.get(serialNumber);
   1045             }
   1046 
   1047             if (vmName == null)
   1048             {
   1049                 vmName = d.getAvdName();
   1050             }
   1051 
   1052             if (vmName == null)
   1053             {
   1054                 try
   1055                 {
   1056                     Thread.sleep(1000);
   1057                 }
   1058                 catch (InterruptedException e)
   1059                 {
   1060                     //do nothing
   1061                 }
   1062                 finally
   1063                 {
   1064                     tries++;
   1065                 }
   1066             }
   1067 
   1068             //try to get vmname by telnet as last option
   1069             if (vmName == null)
   1070             {
   1071                 vmName = getVmNameByTelnet(serialNumber);
   1072             }
   1073 
   1074         }
   1075 
   1076         if (vmName != null)
   1077         {
   1078             synchronized (avdNameMap)
   1079             {
   1080                 if (avdNameMap.get(serialNumber) == null)
   1081                 {
   1082                     avdNameMap.put(serialNumber, vmName);
   1083                 }
   1084             }
   1085 
   1086         }
   1087 
   1088         return vmName;
   1089     }
   1090 
   1091     private static String getVmNameByTelnet(String serialNumber)
   1092     {
   1093         Pattern pattern = Pattern.compile("emulator-([0-9]+)"); //$NON-NLS-1$
   1094         TelnetFrameworkAndroid telnet = new TelnetFrameworkAndroid();
   1095         Matcher matcher = pattern.matcher(serialNumber);
   1096         matcher.matches();
   1097         String avdName = null;
   1098 
   1099         try
   1100         {
   1101             Integer telnetPort = Integer.valueOf(matcher.group(1));
   1102             telnet.connect("localhost", telnetPort); //$NON-NLS-1$
   1103             String avdNameRaw = telnet.write("avd name\r\n", new String[] //$NON-NLS-1$
   1104                     {
   1105                         "KO" //$NON-NLS-1$
   1106                 });
   1107 
   1108             String split = avdNameRaw.contains("\r\n") ? "\r\n" : "\n";
   1109 
   1110             String[] outputArray = avdNameRaw.split(split); //$NON-NLS-1$
   1111             if (outputArray.length > 2)
   1112             {
   1113                 avdName = outputArray[2];
   1114             }
   1115 
   1116             if (avdName != null)
   1117             {
   1118                 avdNameMap.put(serialNumber, avdName);
   1119             }
   1120         }
   1121         catch (NumberFormatException e)
   1122         {
   1123             avdName = serialNumber;
   1124         }
   1125         catch (IOException e)
   1126         {
   1127             avdName = serialNumber;
   1128         }
   1129         finally
   1130         {
   1131             try
   1132             {
   1133                 telnet.disconnect();
   1134             }
   1135             catch (IOException e)
   1136             {
   1137                 //Do nothing.
   1138             }
   1139         }
   1140         return avdName;
   1141     }
   1142 
   1143     /**
   1144      * Get the Device associated with the Android VM
   1145      *
   1146      * @param vmName Android VM name
   1147      * @return Device associated with the given Android VM
   1148      */
   1149     public static IDevice getDeviceWithVmName(String vmName)
   1150     {
   1151         IDevice toReturn = null;
   1152         if (vmName != null)
   1153         {
   1154             Collection<IDevice> devices = connectedDevices.values();
   1155             for (IDevice d : devices)
   1156             {
   1157                 if (d.isEmulator())
   1158                 {
   1159                     String deviceVmName = DDMSFacade.getVmName(d);
   1160                     if (vmName.equals(deviceVmName))
   1161                     {
   1162                         toReturn = d;
   1163                         break;
   1164                     }
   1165                 }
   1166             }
   1167         }
   1168         return toReturn;
   1169     }
   1170 
   1171     /**
   1172      * Securely get the name of the AVD associated to the given device.
   1173      *
   1174      * @param serialNumber The serialNumber of the device that we want the AVD name for
   1175      * @return the name of the AVD used by the emulator running with the given device,
   1176      * or null if the vmname could be retrieved.
   1177      */
   1178     public static String getNameBySerialNumber(String serialNumber)
   1179     {
   1180         String avdName = null;
   1181         IDevice d = getDeviceBySerialNumber(serialNumber);
   1182         avdName = getNameByDevice(d);
   1183 
   1184         return avdName;
   1185     }
   1186 
   1187     /**
   1188      * Securely get the serial number of the given instance.
   1189      *
   1190      * @param instanceName The name of the instance we want the serial number of
   1191      * @return the serial number of the given instance, or <code>null</code> if no instance with the
   1192      * given name is online
   1193      */
   1194     public static String getSerialNumberByName(String instanceName)
   1195     {
   1196         String serialNumber = null;
   1197         if (instanceName != null)
   1198         {
   1199             List<IDevice> devices = null;
   1200             synchronized (connectedDevices)
   1201             {
   1202                 devices = new ArrayList<IDevice>(connectedDevices.size());
   1203                 devices.addAll(connectedDevices.values());
   1204             }
   1205             if (devices != null)
   1206             {
   1207                 for (IDevice dev : devices)
   1208                 {
   1209                     if (instanceName.equals(getNameByDevice(dev)))
   1210                     {
   1211                         serialNumber = dev.getSerialNumber();
   1212                         break;
   1213                     }
   1214                 }
   1215             }
   1216         }
   1217 
   1218         return serialNumber;
   1219     }
   1220 
   1221     public static Collection<String> getRunningApplications(String serialNumber)
   1222     {
   1223         Collection<String> apps = new ArrayList<String>();
   1224         if (serialNumber != null)
   1225         {
   1226             IDevice dev = getDeviceBySerialNumber(serialNumber);
   1227             if (dev != null)
   1228             {
   1229                 Client[] clients = dev.getClients();
   1230                 if ((clients != null) && (clients.length > 0))
   1231                 {
   1232                     for (Client c : clients)
   1233                     {
   1234                         apps.add(c.getClientData().getClientDescription());
   1235                     }
   1236                 }
   1237             }
   1238         }
   1239 
   1240         return apps;
   1241     }
   1242 
   1243     /**
   1244      * Dumps a HPROF file based on a client description and a device serial number
   1245      * @param clientDescription A client description of a running application
   1246      */
   1247     public static IStatus dumpHprofFile(String clientDescription, String serialNumber,
   1248             IProgressMonitor monitor)
   1249     {
   1250         IStatus status = Status.OK_STATUS;
   1251         monitor.beginTask(AndroidNLS.DumpHprofFile_GeneratingMemoryAnalysisOutput, 100);
   1252 
   1253         // Retrive running apps
   1254         monitor.setTaskName(AndroidNLS.DumpHprofFile_GettingRunningApplications);
   1255         IDevice dev = getDeviceBySerialNumber(serialNumber);
   1256         Client[] clients = dev.getClients();
   1257         monitor.worked(25);
   1258 
   1259         // Store the shell
   1260         final Shell[] shell = new Shell[1];
   1261 
   1262         PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable()
   1263         {
   1264             public void run()
   1265             {
   1266 
   1267                 shell[0] = new Shell(PlatformUI.getWorkbench().getDisplay());
   1268 
   1269             }
   1270         });
   1271 
   1272         MotodevHProfDumpHandler hprofHandler = new MotodevHProfDumpHandler(shell[0], monitor);
   1273         monitor.setTaskName(AndroidNLS.DumpHprofFile_SettingApplicationToAnalyse);
   1274         hprofHandler.setSelectedApp(clientDescription);
   1275         monitor.worked(25);
   1276 
   1277         try
   1278         {
   1279             // Find a client with matching description and dum the HPROF file
   1280             for (Client c : clients)
   1281             {
   1282                 if (c.getClientData().getClientDescription().equals(clientDescription))
   1283                 {
   1284                     // Set our handler as the HprofDumpHandler
   1285                     ClientData.setHprofDumpHandler(hprofHandler);
   1286                     monitor.setTaskName(AndroidNLS.DumpHprofFile_DumpingHprofFile);
   1287                     c.dumpHprof();
   1288                     synchronized (DDMSFacade.class)
   1289                     {
   1290                         DDMSFacade.class.wait();
   1291                     }
   1292 
   1293                     monitor.worked(50);
   1294                 }
   1295             }
   1296         }
   1297         catch (Exception e)
   1298         {
   1299             // Status not ok
   1300             status = Status.CANCEL_STATUS;
   1301         }
   1302         finally
   1303         {
   1304             monitor.done();
   1305         }
   1306 
   1307         return status;
   1308 
   1309     }
   1310 
   1311     /**
   1312      * Gets the AVD name of the device
   1313      *
   1314      * @param d The device to be searched for the AVD name
   1315      *
   1316      * @return The AVD name
   1317      */
   1318     private static String getNameByDevice(final IDevice d)
   1319     {
   1320         String name = null;
   1321         if (d != null)
   1322         {
   1323             if (d.isEmulator())
   1324             {
   1325 
   1326                 name = getVmName(d);
   1327             }
   1328             else
   1329             {
   1330                 name = d.getSerialNumber();
   1331             }
   1332         }
   1333 
   1334         return name;
   1335     }
   1336 
   1337     /**
   1338      * Create port forward for a given VM
   1339      *
   1340      * @param serialNumber Android serial number
   1341      * @param from port number from
   1342      * @param to port number to
   1343      * @return true is the port forward was successful, false otherwise
   1344      */
   1345     public static boolean createForward(String serialNumber, int from, int to)
   1346     {
   1347         boolean ok = true;
   1348         IDevice device = getDeviceBySerialNumber(serialNumber);
   1349         try
   1350         {
   1351             device.createForward(from, to);
   1352         }
   1353         catch (Exception e)
   1354         {
   1355             StudioLogger.error(DDMSFacade.class, "Error creating forward of device: " //$NON-NLS-1$
   1356                     + serialNumber + " from " + from + " to " + to, e); //$NON-NLS-1$ //$NON-NLS-2$
   1357             ok = false;
   1358         }
   1359         return ok;
   1360     }
   1361 
   1362     /**
   1363      * Kill the communication channel
   1364      *
   1365      * @param serialNumber The serial number of the device to kill
   1366      */
   1367     public static void kill(String serialNumber)
   1368     {
   1369         if (isDeviceOnline(serialNumber))
   1370         {
   1371             IDevice deviceToKill = getDeviceBySerialNumber(serialNumber);
   1372             if (deviceToKill != null)
   1373             {
   1374                 synchronized (consoleLock)
   1375                 {
   1376                     EmulatorConsole console = EmulatorConsole.getConsole(deviceToKill);
   1377                     if (console != null)
   1378                     {
   1379                         console.kill();
   1380                     }
   1381                 }
   1382             }
   1383         }
   1384     }
   1385 
   1386     /**
   1387      * Push files to device
   1388      *
   1389      * @param serialNumber Android device serial number
   1390      * @param localDir local folder path
   1391      * @param fileNames files to transfer
   1392      * @param remoteDir destination folder path
   1393      * @param timeout timeout for the operation
   1394      * @param monitor monitor associated with the operation
   1395      */
   1396     public static IStatus pushFiles(String serialNumber, String localDir,
   1397             Collection<String> fileNames, String remoteDir, int timeout,
   1398             final IProgressMonitor monitor, OutputStream outputStream)
   1399     {
   1400         return transferFiles(true, serialNumber, localDir, fileNames, remoteDir, timeout, monitor,
   1401                 outputStream);
   1402     }
   1403 
   1404     /**
   1405      * Push files to device
   1406      *
   1407      * @param serialNumber Android device serial number
   1408      * @param localFiles destination local files
   1409      * @param remoteFiles remote files to transfer as localFiles to desktop
   1410      * @param timeout timeout for the operation
   1411      * @param monitor monitor associated with the operation
   1412      */
   1413     public static IStatus pushFiles(String serialNumber, List<File> localFiles,
   1414             List<String> remoteFiles, int timeout, final IProgressMonitor monitor,
   1415             OutputStream outputStream)
   1416     {
   1417         return transferFiles(true, serialNumber, localFiles, remoteFiles, timeout, monitor,
   1418                 outputStream);
   1419     }
   1420 
   1421     /**
   1422      * Pull files from device
   1423      *
   1424      * @param serialNumber Android device serial number
   1425      * @param localDir local folder path
   1426      * @param fileNames files to transfer
   1427      * @param remoteDir destination folder path
   1428      * @param timeout timeout for the operation
   1429      * @param monitor monitor associated with the operation
   1430      */
   1431     public static IStatus pullFiles(String serialNumber, String localDir,
   1432             Collection<String> fileNames, String remoteDir, int timeout,
   1433             final IProgressMonitor monitor, OutputStream outputStream)
   1434     {
   1435         return transferFiles(false, serialNumber, localDir, fileNames, remoteDir, timeout, monitor,
   1436                 outputStream);
   1437     }
   1438 
   1439     /**
   1440      * Pull files from device
   1441      *
   1442      * @param serialNumber Android device serial number
   1443      * @param localFiles local files to transfer as remoteFiles to device
   1444      * @param remoteFiles destination remote files
   1445      * @param timeout timeout for the operation
   1446      * @param monitor monitor associated with the operation
   1447      */
   1448     public static IStatus pullFiles(String serialNumber, List<File> localFiles,
   1449             List<String> remoteFiles, int timeout, final IProgressMonitor monitor,
   1450             OutputStream outputStream)
   1451     {
   1452         return transferFiles(false, serialNumber, localFiles, remoteFiles, timeout, monitor,
   1453                 outputStream);
   1454     }
   1455 
   1456     /**
   1457      * Get the service used to transfer files to the Device
   1458      *
   1459      * @param device Device
   1460      * @param timeout timeout for the operation
   1461      * @param monitor monitor associated with the operation
   1462      * @return The service used to transfer files to the Device
   1463      *
   1464      * @throws AndroidException
   1465      */
   1466     private static SyncService getSyncService(IDevice device, int timeout,
   1467             final IProgressMonitor monitor) throws AndroidException
   1468     {
   1469 
   1470         SyncService service = null;
   1471         long timeoutLimit = System.currentTimeMillis() + timeout;
   1472         do
   1473         {
   1474             if ((device != null) && (device.isOnline()))
   1475             {
   1476                 try
   1477                 {
   1478                     service = device.getSyncService();
   1479                 }
   1480                 catch (IOException e)
   1481                 {
   1482                     StudioLogger.debug("Couldn't get sync service; cause: " + e.getMessage()); //$NON-NLS-1$
   1483                 }
   1484                 catch (com.android.ddmlib.TimeoutException e)
   1485                 {
   1486                     StudioLogger.debug("Couldn't get sync service; cause: " + e.getMessage()); //$NON-NLS-1$
   1487                 }
   1488                 catch (AdbCommandRejectedException e)
   1489                 {
   1490                     StudioLogger.debug("Couldn't get sync service; cause: " + e.getMessage()); //$NON-NLS-1$
   1491                 }
   1492             }
   1493 
   1494             try
   1495             {
   1496                 Thread.sleep(100);
   1497             }
   1498             catch (InterruptedException e)
   1499             {
   1500                 //do nothing
   1501             }
   1502 
   1503             if (monitor.isCanceled())
   1504             {
   1505                 StudioLogger.info("Operation canceled by the user"); //$NON-NLS-1$
   1506                 return null;
   1507             }
   1508 
   1509             if (System.currentTimeMillis() > timeoutLimit)
   1510             {
   1511                 StudioLogger.error("The emulator was not up within the set timeout"); //$NON-NLS-1$
   1512                 throw new AndroidException(
   1513                         "Timeout while preparing to transfer files to the Device. " + device); //$NON-NLS-1$
   1514             }
   1515         }
   1516         while (service == null);
   1517 
   1518         return service;
   1519     }
   1520 
   1521     private static IStatus transferFiles(boolean isPush, String serialNumber, String localDir,
   1522             Collection<String> fileNames, String remoteDir, int timeout,
   1523             final IProgressMonitor monitor, OutputStream outputStream)
   1524     {
   1525         List<File> localList = new ArrayList<File>();
   1526         List<String> remoteList = new ArrayList<String>();
   1527         for (String name : fileNames)
   1528         {
   1529             localList.add(new File(localDir, name));
   1530             remoteList.add(remoteDir + "/" + name); //$NON-NLS-1$
   1531         }
   1532         return transferFiles(isPush, serialNumber, localList, remoteList, timeout, monitor,
   1533                 outputStream);
   1534     }
   1535 
   1536     private static IStatus transferFiles(boolean isPush, String serialNumber,
   1537             List<File> localFiles, List<String> remoteFiles, int timeout,
   1538             final IProgressMonitor monitor, OutputStream outputStream)
   1539     {
   1540         if (localFiles.size() != remoteFiles.size())
   1541         {
   1542             return new Status(IStatus.ERROR, AndroidPlugin.PLUGIN_ID,
   1543                     AndroidNLS.ERR_DDMSFacade_IncompatibleFileLists);
   1544         }
   1545 
   1546         IStatus status = Status.OK_STATUS;
   1547         IDevice device = DDMSFacade.getDeviceBySerialNumber(serialNumber);
   1548 
   1549         SyncService service = null;
   1550         try
   1551         {
   1552             service = getSyncService(device, timeout, monitor);
   1553             if (service == null)
   1554             {
   1555                 status = Status.CANCEL_STATUS;
   1556             }
   1557             else
   1558             {
   1559                 final ISyncProgressMonitor syncMonitor = new ISyncProgressMonitor()
   1560                 {
   1561                     public void start(int i)
   1562                     {
   1563                         //do nothing
   1564                     }
   1565 
   1566                     public void stop()
   1567                     {
   1568                         //do nothing
   1569                     }
   1570 
   1571                     public void advance(int i)
   1572                     {
   1573                         //do nothing
   1574                     }
   1575 
   1576                     public boolean isCanceled()
   1577                     {
   1578                         return monitor.isCanceled();
   1579                     }
   1580 
   1581                     public void startSubTask(String s)
   1582                     {
   1583                         //do nothing
   1584                     }
   1585                 };
   1586 
   1587                 FileListingService flService = device.getFileListingService();
   1588 
   1589                 for (int i = 0; i < localFiles.size(); i++)
   1590                 {
   1591                     File localFile = localFiles.get(i);
   1592                     String remotePath = remoteFiles.get(i);
   1593                     String absLocalFile = localFile.getAbsolutePath();
   1594 
   1595                     String resultMessage = null;
   1596                     if (isPush)
   1597                     {
   1598                         StudioLogger.debug("Push " + absLocalFile + " to " + remotePath); //$NON-NLS-1$ //$NON-NLS-2$
   1599                         try
   1600                         {
   1601                             service.pushFile(absLocalFile, remotePath, syncMonitor);
   1602                         }
   1603                         catch (SyncException e1)
   1604                         {
   1605                             StudioLogger
   1606                                     .debug("Push result: " + "SyncException occured " + e1.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$
   1607                             resultMessage =
   1608                                     NLS.bind(AndroidNLS.CON_ConsolePush, absLocalFile, remotePath)
   1609                                             + ": " + e1.getLocalizedMessage(); //$NON-NLS-1$
   1610                         }
   1611                         catch (FileNotFoundException e1)
   1612                         {
   1613                             StudioLogger.debug("Push result: " + "FileNotFoundException occured " //$NON-NLS-1$ //$NON-NLS-2$
   1614                                     + e1.getMessage());
   1615                             resultMessage =
   1616                                     NLS.bind(AndroidNLS.CON_ConsolePush, absLocalFile, remotePath)
   1617                                             + ": " + e1.getLocalizedMessage(); //$NON-NLS-1$
   1618                         }
   1619                         catch (IOException e1)
   1620                         {
   1621                             StudioLogger
   1622                                     .debug("Push result: " + "IOException occured " + e1.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$
   1623                             resultMessage =
   1624                                     NLS.bind(AndroidNLS.CON_ConsolePush, absLocalFile, remotePath)
   1625                                             + ": " + e1.getLocalizedMessage(); //$NON-NLS-1$
   1626                         }
   1627                         catch (com.android.ddmlib.TimeoutException e1)
   1628                         {
   1629                             StudioLogger
   1630                                     .debug("Push result: " + "TimeoutException occured " + e1.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$
   1631                             resultMessage =
   1632                                     NLS.bind(AndroidNLS.CON_ConsolePush, absLocalFile, remotePath)
   1633                                             + ": " + e1.getLocalizedMessage(); //$NON-NLS-1$
   1634                         }
   1635 
   1636                         if ((outputStream != null) && (resultMessage != null))
   1637                         {
   1638                             try
   1639                             {
   1640                                 outputStream.write(resultMessage.getBytes());
   1641                                 outputStream.write('\n');
   1642                                 outputStream.flush();
   1643                             }
   1644                             catch (Exception e)
   1645                             {
   1646                                 // Do nothing
   1647                             }
   1648                         }
   1649 
   1650                     }
   1651                     else
   1652                     {
   1653                         FileEntry f1 = null;
   1654                         FileEntry f2 = null;
   1655 
   1656                         f2 = flService.getRoot();
   1657                         flService.getChildren(f2, false, null);
   1658                         String[] dirs = remotePath.split("/"); //$NON-NLS-1$
   1659 
   1660                         for (int j = 1; j < (dirs.length - 1); j++)
   1661                         {
   1662                             f1 = f2.findChild(dirs[j]);
   1663                             flService.getChildren(f1, false, null);
   1664                             f2 = f1;
   1665                         }
   1666 
   1667                         final FileEntry fileToPull = f2.findChild(dirs[dirs.length - 1]);
   1668 
   1669                         if (fileToPull != null)
   1670                         {
   1671                             try
   1672                             {
   1673                                 service.pullFile(fileToPull, absLocalFile, syncMonitor);
   1674                             }
   1675                             catch (FileNotFoundException e)
   1676                             {
   1677                                 resultMessage = e.getLocalizedMessage();
   1678                                 StudioLogger.debug("Pull result: " + e.getMessage()); //$NON-NLS-1$
   1679                             }
   1680                             catch (SyncException e)
   1681                             {
   1682                                 resultMessage = e.getLocalizedMessage();
   1683                                 StudioLogger.debug("Pull result: " + e.getMessage()); //$NON-NLS-1$
   1684                             }
   1685                             catch (IOException e)
   1686                             {
   1687                                 resultMessage = e.getLocalizedMessage();
   1688                                 StudioLogger.debug("Pull result: " + e.getMessage()); //$NON-NLS-1$
   1689                             }
   1690                             catch (com.android.ddmlib.TimeoutException e)
   1691                             {
   1692                                 resultMessage = e.getLocalizedMessage();
   1693                                 StudioLogger.debug("Pull result: " + e.getMessage()); //$NON-NLS-1$
   1694                             }
   1695 
   1696                             if ((outputStream != null) && (resultMessage != null))
   1697                             {
   1698                                 String message =
   1699                                         NLS.bind(AndroidNLS.CON_ConsolePull,
   1700                                                 fileToPull.getFullPath(), absLocalFile)
   1701                                                 + ": " + resultMessage; //$NON-NLS-1$
   1702                                 try
   1703                                 {
   1704                                     outputStream.write(message.getBytes());
   1705                                     outputStream.write('\n');
   1706                                     outputStream.flush();
   1707                                 }
   1708                                 catch (IOException e)
   1709                                 {
   1710                                     //do nothing
   1711                                 }
   1712                             }
   1713                         }
   1714                         else
   1715                         {
   1716                             resultMessage =
   1717                                     NLS.bind(AndroidNLS.DDMSFacade_Remote_File_Not_Found,
   1718                                             remotePath);
   1719                             StudioLogger.debug("Pull result: File not found " + remotePath); //$NON-NLS-1$
   1720                         }
   1721                     }
   1722 
   1723                     if (resultMessage != null)
   1724                     {
   1725                         status = new Status(IStatus.ERROR, AndroidPlugin.PLUGIN_ID, resultMessage);
   1726                     }
   1727                     if (syncMonitor.isCanceled())
   1728                     {
   1729                         status = Status.CANCEL_STATUS;
   1730                         break;
   1731                     }
   1732                 }
   1733             }
   1734         }
   1735         catch (AndroidException e)
   1736         {
   1737             status = new Status(IStatus.ERROR, AndroidPlugin.PLUGIN_ID, e.getMessage());
   1738         }
   1739         catch (NullPointerException e1)
   1740         {
   1741             status =
   1742                     new Status(IStatus.ERROR, AndroidPlugin.PLUGIN_ID,
   1743                             AndroidNLS.ERR_DDMSFacade_FileNotFound);
   1744         }
   1745         finally
   1746         {
   1747             if (service != null)
   1748             {
   1749                 service.close();
   1750             }
   1751         }
   1752 
   1753         return status;
   1754     }
   1755 
   1756     /**
   1757      * Check if the application is running in the device with specified serial number
   1758      * @param serialNumber
   1759      * @param applicationName
   1760      * @return true if it is running, false otherwise
   1761      */
   1762     public static boolean isApplicationRunning(String serialNumber, String applicationName)
   1763     {
   1764         IDevice dev = null;
   1765         boolean running = false;
   1766         dev = connectedDevices.get(serialNumber);
   1767         if (dev != null)
   1768         {
   1769             running = dev.getClient(applicationName) != null;
   1770         }
   1771         return running;
   1772     }
   1773 
   1774     /**
   1775      * Connect to a Remote Device given its IP/Port
   1776      *
   1777      * @param device the Remote Device Instance
   1778      * @param host device host (IP)
   1779      * @param port device port
   1780      * @param timeout the maximum time allowed to successfully connect to the device
   1781      * @param monitor the monitor of the operation
   1782      * @return the status of the operation
   1783      * @throws IOException
   1784      */
   1785     public static IStatus connectTcpIp(final ISerialNumbered device, String host, String port,
   1786             int timeout, IProgressMonitor monitor) throws IOException
   1787     {
   1788         SubMonitor subMonitor = SubMonitor.convert(monitor, 1000);
   1789 
   1790         subMonitor.beginTask(AndroidNLS.DDMSFacade_MsgConnectingToDeviceViaTCPIP, 10);
   1791 
   1792         IStatus status = Status.OK_STATUS;
   1793 
   1794         String serialNumber = device.getSerialNumber();
   1795         if (!isDeviceOnline(serialNumber)) // check if it's already connected
   1796         {
   1797             String[] cmd = createConnectTcpIpCommand(host, port);
   1798 
   1799             status =
   1800                     executeRemoteDevicesCommand(
   1801                             cmd,
   1802                             null,
   1803                             timeout,
   1804                             NLS.bind(AndroidNLS.ERR_RemoteDevice_TimeoutWhileConnecting,
   1805                                     device.getDeviceName()), new IStopCondition()
   1806                             {
   1807 
   1808                                 public boolean canStop()
   1809                                 {
   1810                                     String serialNumber = device.getSerialNumber();
   1811                                     if (serialNumber != null)
   1812                                     {
   1813                                         return isDeviceOnline(serialNumber);
   1814                                     }
   1815                                     else
   1816                                     {
   1817                                         return false;
   1818                                     }
   1819                                 }
   1820                             }, subMonitor.newChild(1000));
   1821 
   1822         }
   1823 
   1824         subMonitor.worked(1000);
   1825 
   1826         return status;
   1827     }
   1828 
   1829     /**
   1830      * Method which switches the device connection mode from TCP/IP
   1831      * to USB.
   1832      *
   1833      * @param device {@link ISerialNumbered} device to have its connection mode changed.
   1834      * @param host The IP of the device.
   1835      * @param port The port in which the TCP/IP connection is established.
   1836      * @param timeout The maximum time which the switching operation is attempted.
   1837      * @param monitor The {@link IProgressMonitor} which this operation is being computed.
   1838      *
   1839      * @return Returns the {@link IStatus} of this operation.
   1840      *
   1841      * @throws IOException Exception thrown in case something goes wrong while trying
   1842      * to switch the device connection mode from TCP/IP to USB.
   1843      */
   1844     public static IStatus switchFromTCPConnectionModeToUSBConnectionMode(
   1845             final ISerialNumbered device, String host, String port, int timeout,
   1846             IProgressMonitor monitor) throws IOException
   1847     {
   1848         SubMonitor subMonitor = SubMonitor.convert(monitor, 1000);
   1849 
   1850         subMonitor.beginTask(AndroidNLS.DDMSFacade_MsgSwitchingDeviceFromTCPIPToUSB, 10);
   1851 
   1852         IStatus status = Status.OK_STATUS;
   1853 
   1854         String serialNumber = device.getSerialNumber();
   1855         if (isDeviceOnline(serialNumber)) // check if it's already connected
   1856         {
   1857             String[] cmd = createSwitchToUSBConnectionModeCommand(host, port);
   1858 
   1859             status =
   1860                     executeRemoteDevicesCommand(cmd, null, timeout, NLS.bind(
   1861                             AndroidNLS.DDMSFacade_MsgTimeoutReachedSwitchingFromTCPToUSB,
   1862                             device.getDeviceName()), new IStopCondition()
   1863                     {
   1864 
   1865                         public boolean canStop()
   1866                         {
   1867                             String serialNumber = device.getSerialNumber();
   1868                             if (serialNumber != null)
   1869                             {
   1870                                 return isDeviceOnline(serialNumber);
   1871                             }
   1872                             else
   1873                             {
   1874                                 return false;
   1875                             }
   1876                         }
   1877                     }, subMonitor.newChild(1000));
   1878 
   1879         }
   1880 
   1881         subMonitor.worked(1000);
   1882 
   1883         if (status.isOK())
   1884         {
   1885             StudioLogger.collectUsageData(StudioLogger.WHAT_REMOTE_USB,
   1886                     StudioLogger.KIND_REMOTE_DEVICE, StudioLogger.DESCRIPTION_DEFAULT,
   1887                     AndroidPlugin.PLUGIN_ID, AndroidPlugin.getDefault().getBundle().getVersion()
   1888                             .toString());
   1889         }
   1890 
   1891         return status;
   1892     }
   1893 
   1894     /**
   1895      * Get the wireless ip from the connected handset
   1896      * @param serialNumber
   1897      * @param monitor
   1898      * @return the ip or null if not possible to retrieve it
   1899      */
   1900     public static String getWirelessIPfromHandset(String serialNumber, IProgressMonitor monitor)
   1901     {
   1902         String handset_wireless_ip = null;
   1903         IDevice device = null;
   1904 
   1905         device = connectedDevices.get(serialNumber);
   1906         if (device != null)
   1907         {
   1908             // get the wi-fi name for executing the ipconfig command
   1909             String wifiProperty = device.getProperty(WIFI_INTERFACE_DEVICE_PROPERTY);
   1910             if (wifiProperty == null)
   1911             {
   1912                 wifiProperty = DEFAULT_WIRELESS_DEVICE_PROPERTY;
   1913             }
   1914             // execute ipconfig command
   1915             Collection<String> answers =
   1916                     executeShellCmd(serialNumber, IFCONFIG_CMD + " " + wifiProperty, monitor); //$NON-NLS-1$
   1917 
   1918             // Success message - for example
   1919             // [tiwlan0: ip 192.168.0.174 mask 255.255.255.0 flags [up broadcast running multicast]]
   1920 
   1921             if (answers != null)
   1922             {
   1923                 String result = answers.toString();
   1924                 if (result != null)
   1925                 {
   1926                     // splits the result of the shell command and gets the third position
   1927                     // that should be the IP number
   1928                     String[] result_splited = result.split(" "); //$NON-NLS-1$
   1929                     if (result_splited.length >= 3)
   1930                     {
   1931                         // check whether there is an IP
   1932                         Pattern pattern = Pattern.compile(IP_PATTERN);
   1933                         Matcher matcher = pattern.matcher(result);
   1934                         if (matcher.find())
   1935                         {
   1936                             handset_wireless_ip = result_splited[2];
   1937                         }
   1938                     }
   1939                 }
   1940             }
   1941         }
   1942         return handset_wireless_ip;
   1943     }
   1944 
   1945     /**
   1946      * Switch adb connection mode of an specific device to TCPIP
   1947      *
   1948      * @param deviceName name of the handset instance
   1949      * @param host wireless ip of the handset instance
   1950      * @param port number of the port to be using during the connection
   1951      * @param timeout the maximum time allowed to successfully connect to the device
   1952      * @param monitor the monitor of the operation
   1953      * @return the status of the operation
   1954      *
   1955      * @throws IOException Exception thrown in case there are problems switching the device.
   1956      */
   1957     public static IStatus switchUSBtoTcpIp(String deviceName, final String serialNumber,
   1958             String port, int timeout, IProgressMonitor monitor) throws IOException
   1959     {
   1960         SubMonitor subMonitor = SubMonitor.convert(monitor, 1000);
   1961 
   1962         subMonitor.beginTask(AndroidNLS.DDMSFacade_MsgSwitchingFromUSBConnection, 10);
   1963 
   1964         IStatus status = Status.OK_STATUS;
   1965 
   1966         if (isDeviceOnline(serialNumber))
   1967         {
   1968             String[] cmd = createSwitchToTcpIpCommand(serialNumber, port);
   1969 
   1970             status =
   1971                     executeRemoteDevicesCommand(cmd, null, timeout,
   1972                             NLS.bind(AndroidNLS.ERR_WirelessRemoteDevice_TimeoutWhileConnecting,
   1973                                     deviceName), new IStopCondition()
   1974                             {
   1975 
   1976                                 public boolean canStop()
   1977                                 {
   1978                                     if (serialNumber != null)
   1979                                     {
   1980                                         return isDeviceOffline(serialNumber);
   1981                                     }
   1982                                     else
   1983                                     {
   1984                                         return false;
   1985                                     }
   1986                                 }
   1987                             }, subMonitor.newChild(1000));
   1988 
   1989         }
   1990 
   1991         monitor.worked(1000);
   1992 
   1993         return status;
   1994     }
   1995 
   1996     /**
   1997      * Disconnect from a Remote Device given its IP/Port
   1998      *
   1999      * @param device the Remote Device Instance
   2000      * @param host device host (IP)
   2001      * @param port device port
   2002      * @param timeout the maximum time allowed to successfully disconnect from the device
   2003      * @param monitor the monitor of the operation
   2004      * @return the status of the operation
   2005      * @throws IOException
   2006      */
   2007     public static IStatus disconnectTcpIp(final ISerialNumbered device, String host, String port,
   2008             int timeout, IProgressMonitor monitor) throws IOException
   2009     {
   2010         IStatus status = Status.OK_STATUS;
   2011 
   2012         String serialNumber = device.getSerialNumber();
   2013         if (isDeviceOnline(serialNumber)) // check if it's already disconnected
   2014         {
   2015             String[] cmd = createDisconnectTcpIpCommand(host, port);
   2016 
   2017             status =
   2018                     executeRemoteDevicesCommand(
   2019                             cmd,
   2020                             null,
   2021                             timeout,
   2022                             NLS.bind(AndroidNLS.ERR_RemoteDevice_TimeoutWhileDisconnecting,
   2023                                     device.getDeviceName()), new IStopCondition()
   2024                             {
   2025 
   2026                                 public boolean canStop()
   2027                                 {
   2028                                     String serialNumber = device.getSerialNumber();
   2029                                     return !isDeviceOnline(serialNumber);
   2030                                 }
   2031                             }, monitor);
   2032 
   2033         }
   2034 
   2035         return status;
   2036     }
   2037 
   2038     /**
   2039      * Creates a string with the command that should
   2040      * be called in order to connect to an IP/Port
   2041      *
   2042      * @param host device host (IP)
   2043      * @param port device port
   2044      * @return the command to be used to connect to an IP/Port
   2045      */
   2046     private static String[] createConnectTcpIpCommand(String host, String port)
   2047     {
   2048 
   2049         String hostPort = host + ":" + port; //$NON-NLS-1$
   2050 
   2051         String sdkPath = SdkUtils.getSdkPath();
   2052 
   2053         String cmd[] =
   2054                 {
   2055                         sdkPath + PLATFORM_TOOLS_FOLDER + File.separator + ADB_COMMAND,
   2056                         CONNECT_TCPIP_CMD, hostPort
   2057                 };
   2058 
   2059         return cmd;
   2060     }
   2061 
   2062     /**
   2063      * Creates a string with the command switches
   2064      * a device from the TCP/IP connection mode
   2065      * to the USB connection mode.
   2066      *
   2067      * @param host Device host (IP).
   2068      * @param port Device port.
   2069      *
   2070      * @return The command to be used to switch back to USB connection mode.
   2071      */
   2072     private static String[] createSwitchToUSBConnectionModeCommand(String host, String port)
   2073     {
   2074 
   2075         String hostPort = host + ":" + port; //$NON-NLS-1$
   2076 
   2077         String sdkPath = SdkUtils.getSdkPath();
   2078 
   2079         String cmd[] =
   2080                 {
   2081                         sdkPath + PLATFORM_TOOLS_FOLDER + File.separator + ADB_COMMAND,
   2082                         DEVICE_ID_INDICATOR, hostPort, USB_SWITCH_BACK_COMMAND
   2083                 };
   2084 
   2085         return cmd;
   2086     }
   2087 
   2088     /**
   2089      * Creates a string with the command that should
   2090      * be called in order to switch adb connection from USB to TPCIP mode
   2091      *
   2092      * @param serialNumber device serial number
   2093      * @param port device port
   2094      * @return the command to be used to switch adb connection to TCPIP mode
   2095      */
   2096     private static String[] createSwitchToTcpIpCommand(String serialNumber, String port)
   2097     {
   2098         String sdkPath = SdkUtils.getSdkPath();
   2099 
   2100         String cmd[] =
   2101                 {
   2102                         sdkPath + PLATFORM_TOOLS_FOLDER + File.separator + ADB_COMMAND,
   2103                         ADB_INSTANCE_PARAMETER, serialNumber, TCPIP_CMD, port
   2104                 };
   2105 
   2106         return cmd;
   2107     }
   2108 
   2109     /**
   2110      * Creates a string with the command that should
   2111      * be called to delete a file from device
   2112      *
   2113      * @param serialNumber
   2114      * @param file
   2115      * @param folder
   2116      * @return
   2117      */
   2118     private static String[] createDeleteFileFromDeviceCommand(String serialNumber, String file,
   2119             String folder)
   2120     {
   2121         String sdkPath = SdkUtils.getSdkPath();
   2122 
   2123         // The tools folder should exist and be here, but double-cheking
   2124         // once more wont kill
   2125         File f = new File(sdkPath + PLATFORM_TOOLS_FOLDER + File.separator);
   2126         if (!f.exists())
   2127         {
   2128             StudioLogger
   2129                     .error("Run: Could not find tools folder on " + sdkPath + PLATFORM_TOOLS_FOLDER //$NON-NLS-1$
   2130                             + File.separator);
   2131         }
   2132         else
   2133         {
   2134             if (!f.isDirectory())
   2135             {
   2136                 StudioLogger.error("Run: Invalid tools folder " + sdkPath + PLATFORM_TOOLS_FOLDER //$NON-NLS-1$
   2137                         + File.separator);
   2138             }
   2139         }
   2140 
   2141         String cmd[] =
   2142                 {
   2143                         sdkPath + PLATFORM_TOOLS_FOLDER + File.separator + ADB_COMMAND,
   2144                         ADB_INSTANCE_PARAMETER, serialNumber, SHELL_CMD,
   2145                         "rm /" + folder + "/" + file //$NON-NLS-1$ //$NON-NLS-2$
   2146                 };
   2147 
   2148         return cmd;
   2149     }
   2150 
   2151     /**
   2152      * Uses the ADB shell command to remove a file from the device
   2153      *
   2154      * @param serialNumber
   2155      * @param fileName
   2156      * @param sdCardFolder
   2157      * @return
   2158      * @throws IOException
   2159      */
   2160     private static boolean deleteFileFromDevice(String serialNumber, String fileName, String folder)
   2161             throws IOException
   2162     {
   2163 
   2164         String command[] = createDeleteFileFromDeviceCommand(serialNumber, fileName, folder);
   2165         IStatus status = executeRemoteDevicesCommand(command, null, 1000, "", new IStopCondition() //$NON-NLS-1$
   2166                 {
   2167 
   2168                     public boolean canStop()
   2169                     {
   2170                         return true;
   2171                     }
   2172                 }, null);
   2173 
   2174         return status.isOK();
   2175     }
   2176 
   2177     /**
   2178      * Check if a device identified by the serial number has a mounted SDCard
   2179      * @param serialNumber the serial number
   2180      * @return true if the device has a SDCard
   2181      * @throws IOException
   2182      */
   2183     public static boolean hasSDCard(String serialNumber) throws IOException
   2184     {
   2185         boolean hasSdCard = false;
   2186         File tempSdCardFile = File.createTempFile("SDcheck", ".tmp"); //$NON-NLS-1$ //$NON-NLS-2$
   2187         boolean tempCopiedOnSdCardFile =
   2188                 pushFileToDevice(serialNumber, SDCARD_FOLDER, tempSdCardFile);
   2189 
   2190         if (tempCopiedOnSdCardFile)
   2191         {
   2192             //trying to write on /sdcard folder (it works for phones previous from Platform 2.2)
   2193             if (!deleteFileFromDevice(serialNumber, tempSdCardFile.getName(), SDCARD_FOLDER))
   2194             {
   2195                 StudioLogger
   2196                         .error("DDMSFacade: Could not delete tempfile from /sdcard when checking if card is enabled"); //$NON-NLS-1$
   2197             }
   2198             hasSdCard = true;
   2199             tempSdCardFile.delete();
   2200         }
   2201         else
   2202         {
   2203 
   2204             File tempMntFile = File.createTempFile("SDcheck", ".tmp"); //$NON-NLS-1$ //$NON-NLS-2$
   2205             boolean tempCopiedOnMntFile =
   2206                     pushFileToDevice(serialNumber, MNT_SDCARD_FOLDER, tempSdCardFile);
   2207 
   2208             if (tempCopiedOnMntFile)
   2209             {
   2210                 //trying to write on /mnt/sdcard folder (it works for phones since Platform 2.2)
   2211                 if (!deleteFileFromDevice(serialNumber, tempMntFile.getName(), MNT_SDCARD_FOLDER))
   2212                 {
   2213                     StudioLogger
   2214                             .error("DDMSFacade: Could not delete tempfile from /mnt/sdcard when checking if card is enabled"); //$NON-NLS-1$
   2215                 }
   2216                 hasSdCard = true;
   2217                 tempMntFile.delete();
   2218             }
   2219 
   2220         }
   2221 
   2222         return hasSdCard;
   2223     }
   2224 
   2225     /**
   2226      *
   2227      * @param serialNumber
   2228      * @param sdCardFolder
   2229      * @param tempFile
   2230      * @return true if manages to push file into the folder specified on device
   2231      */
   2232     private static boolean pushFileToDevice(String serialNumber, String folder, File file)
   2233     {
   2234         Collection<String> files = new ArrayList<String>();
   2235         files.add(file.getName());
   2236         Path path = new Path(file.getAbsolutePath());
   2237 
   2238         IStatus status =
   2239                 pushFiles(serialNumber, path.removeLastSegments(1).toString(), files, folder, 2000,
   2240                         new NullProgressMonitor(), null);
   2241 
   2242         return status.isOK();
   2243     }
   2244 
   2245     /**
   2246      * Creates a string with the command that should
   2247      * be called in order to disconnect from an IP/Port
   2248      *
   2249      * @param host device host (IP)
   2250      * @param port device port
   2251      * @return the command to be used to disconnect from an IP/Port
   2252      */
   2253     private static String[] createDisconnectTcpIpCommand(String host, String port)
   2254     {
   2255 
   2256         String hostPort = host + ":" + port; //$NON-NLS-1$
   2257 
   2258         String sdkPath = SdkUtils.getSdkPath();
   2259         String cmd[] =
   2260                 {
   2261                         sdkPath + PLATFORM_TOOLS_FOLDER + File.separator + ADB_COMMAND,
   2262                         DISCONNECT_TCPIP_CMD, hostPort
   2263                 };
   2264 
   2265         return cmd;
   2266     }
   2267 
   2268     public static void deleteFile(String serialNumber, String path) throws IOException
   2269     {
   2270         DDMSFacade.execRemoteApp(serialNumber, "rm " + path, //$NON-NLS-1$
   2271                 new NullProgressMonitor());
   2272     }
   2273 }
   2274