FileDocCategorySizeDatePackage
AndroidDebugBridge.javaAPI DocAndroid 1.5 API39307Wed May 06 22:41:08 BST 2009com.android.ddmlib

AndroidDebugBridge

public final class AndroidDebugBridge extends Object
A connection to the host-side android debug bridge (adb)

This is the central point to communicate with any devices, emulators, or the applications running on them.

{@link #init(boolean)} must be called before anything is done.

Fields Summary
private static final int
ADB_VERSION_MICRO_MIN
private static final int
ADB_VERSION_MICRO_MAX
private static final Pattern
sAdbVersion
private static final String
ADB
private static final String
DDMS
static final String
ADB_HOST
static final int
ADB_PORT
static InetAddress
sHostAddr
static InetSocketAddress
sSocketAddr
private static AndroidDebugBridge
sThis
private static boolean
sClientSupport
private String
mAdbOsLocation
Full path to adb.
private boolean
mVersionCheck
private boolean
mStarted
private DeviceMonitor
mDeviceMonitor
private static final ArrayList
sBridgeListeners
private static final ArrayList
sDeviceListeners
private static final ArrayList
sClientListeners
private static final Object
sLock
Constructors Summary
private AndroidDebugBridge(String osLocation)
Creates a new bridge.

param
osLocation the location of the command line tool
throws
InvalidParameterException

        if (osLocation == null || osLocation.length() == 0) {
            throw new InvalidParameterException();
        }
        mAdbOsLocation = osLocation;

        checkAdbVersion();
    
private AndroidDebugBridge()
Creates a new bridge not linked to any particular adb executable.

    
Methods Summary
public static voidaddClientChangeListener(com.android.ddmlib.AndroidDebugBridge$IClientChangeListener listener)
Adds the listener to the collection of listeners who will be notified when a {@link Client} property changed, by sending it one of the messages defined in the {@link IClientChangeListener} interface.

param
listener The listener which should be notified.

        synchronized (sLock) {
            if (sClientListeners.contains(listener) == false) {
                sClientListeners.add(listener);
            }
        }
    
public static voidaddDebugBridgeChangeListener(com.android.ddmlib.AndroidDebugBridge$IDebugBridgeChangeListener listener)
Adds the listener to the collection of listeners who will be notified when a new {@link AndroidDebugBridge} is connected, by sending it one of the messages defined in the {@link IDebugBridgeChangeListener} interface.

param
listener The listener which should be notified.

        synchronized (sLock) {
            if (sBridgeListeners.contains(listener) == false) {
                sBridgeListeners.add(listener);
                if (sThis != null) {
                    // we attempt to catch any exception so that a bad listener doesn't kill our
                    // thread
                    try {
                        listener.bridgeChanged(sThis);
                    } catch (Exception e) {
                        Log.e(DDMS, e);
                    }
                }
            }
        }
    
public static voidaddDeviceChangeListener(com.android.ddmlib.AndroidDebugBridge$IDeviceChangeListener listener)
Adds the listener to the collection of listeners who will be notified when a {@link Device} is connected, disconnected, or when its properties or its {@link Client} list changed, by sending it one of the messages defined in the {@link IDeviceChangeListener} interface.

param
listener The listener which should be notified.

        synchronized (sLock) {
            if (sDeviceListeners.contains(listener) == false) {
                sDeviceListeners.add(listener);
            }
        }
    
private voidcheckAdbVersion()
Queries adb for its version number and checks it against {@link #MIN_VERSION_NUMBER} and {@link #MAX_VERSION_NUMBER}

        // default is bad check
        mVersionCheck = false;

        if (mAdbOsLocation == null) {
            return;
        }

        try {
            String[] command = new String[2];
            command[0] = mAdbOsLocation;
            command[1] = "version"; //$NON-NLS-1$
            Log.d(DDMS, String.format("Checking '%1$s version'", mAdbOsLocation)); //$NON-NLS-1$
            Process process = Runtime.getRuntime().exec(command);

            ArrayList<String> errorOutput = new ArrayList<String>();
            ArrayList<String> stdOutput = new ArrayList<String>();
            int status = grabProcessOutput(process, errorOutput, stdOutput,
                    true /* waitForReaders */);

            if (status != 0) {
                StringBuilder builder = new StringBuilder("'adb version' failed!"); //$NON-NLS-1$
                for (String error : errorOutput) {
                    builder.append('\n");
                    builder.append(error);
                }
                Log.logAndDisplay(LogLevel.ERROR, "adb", builder.toString());
            }

            // check both stdout and stderr
            boolean versionFound = false;
            for (String line : stdOutput) {
                versionFound = scanVersionLine(line);
                if (versionFound) {
                    break;
                }
            }
            if (!versionFound) {
                for (String line : errorOutput) {
                    versionFound = scanVersionLine(line);
                    if (versionFound) {
                        break;
                    }
                }
            }

            if (!versionFound) {
                // if we get here, we failed to parse the output.
                Log.logAndDisplay(LogLevel.ERROR, ADB,
                        "Failed to parse the output of 'adb version'"); //$NON-NLS-1$
            }
            
        } catch (IOException e) {
            Log.logAndDisplay(LogLevel.ERROR, ADB,
                    "Failed to get the adb version: " + e.getMessage()); //$NON-NLS-1$
        } catch (InterruptedException e) {
        } finally {

        }
    
voidclientChanged(Client client, int changeMask)
Notify the listener of a modified {@link Client}.

The notification of the listeners is done in a synchronized block. It is important to expect the listeners to potentially access various methods of {@link Device} as well as {@link #getDevices()} which use internal locks.

For this reason, any call to this method from a method of {@link DeviceMonitor}, {@link Device} which is also inside a synchronized block, should first synchronize on the {@link AndroidDebugBridge} lock. Access to this lock is done through {@link #getLock()}.

param
device the modified Client.
param
changeMask the mask indicating what changed in the Client
see
#getLock()

        // because the listeners could remove themselves from the list while processing
        // their event callback, we make a copy of the list and iterate on it instead of
        // the main list.
        // This mostly happens when the application quits.
        IClientChangeListener[] listenersCopy = null;
        synchronized (sLock) {
            listenersCopy = sClientListeners.toArray(
                    new IClientChangeListener[sClientListeners.size()]);
            
        }

        // Notify the listeners
        for (IClientChangeListener listener : listenersCopy) {
            // we attempt to catch any exception so that a bad listener doesn't kill our
            // thread
            try {
                listener.clientChanged(client, changeMask);
            } catch (Exception e) {
                Log.e(DDMS, e);
            }
        }
    
public static com.android.ddmlib.AndroidDebugBridgecreateBridge()
Creates a {@link AndroidDebugBridge} that is not linked to any particular executable.

This bridge will expect adb to be running. It will not be able to start/stop/restart adb.

If a bridge has already been started, it is directly returned with no changes (similar to calling {@link #getBridge()}).

return
a connected bridge.

        synchronized (sLock) {
            if (sThis != null) {
                return sThis;
            }

            try {
                sThis = new AndroidDebugBridge();
                sThis.start();
            } catch (InvalidParameterException e) {
                sThis = null;
            }

            // because the listeners could remove themselves from the list while processing
            // their event callback, we make a copy of the list and iterate on it instead of
            // the main list.
            // This mostly happens when the application quits.
            IDebugBridgeChangeListener[] listenersCopy = sBridgeListeners.toArray(
                    new IDebugBridgeChangeListener[sBridgeListeners.size()]);

            // notify the listeners of the change
            for (IDebugBridgeChangeListener listener : listenersCopy) {
                // we attempt to catch any exception so that a bad listener doesn't kill our
                // thread
                try {
                    listener.bridgeChanged(sThis);
                } catch (Exception e) {
                    Log.e(DDMS, e);
                }
            }

            return sThis;
        }
    
public static com.android.ddmlib.AndroidDebugBridgecreateBridge(java.lang.String osLocation, boolean forceNewBridge)
Creates a new debug bridge from the location of the command line tool.

Any existing server will be disconnected, unless the location is the same and forceNewBridge is set to false.

param
osLocation the location of the command line tool 'adb'
param
forceNewBridge force creation of a new bridge even if one with the same location already exists.
return
a connected bridge.

        synchronized (sLock) {
            if (sThis != null) {
                if (sThis.mAdbOsLocation != null && sThis.mAdbOsLocation.equals(osLocation) &&
                        forceNewBridge == false) {
                    return sThis;
                } else {
                    // stop the current server
                    sThis.stop();
                }
            }

            try {
                sThis = new AndroidDebugBridge(osLocation);
                sThis.start();
            } catch (InvalidParameterException e) {
                sThis = null;
            }

            // because the listeners could remove themselves from the list while processing
            // their event callback, we make a copy of the list and iterate on it instead of
            // the main list.
            // This mostly happens when the application quits.
            IDebugBridgeChangeListener[] listenersCopy = sBridgeListeners.toArray(
                    new IDebugBridgeChangeListener[sBridgeListeners.size()]);

            // notify the listeners of the change
            for (IDebugBridgeChangeListener listener : listenersCopy) {
                // we attempt to catch any exception so that a bad listener doesn't kill our
                // thread
                try {
                    listener.bridgeChanged(sThis);
                } catch (Exception e) {
                    Log.e(DDMS, e);
                }
            }

            return sThis;
        }
    
voiddeviceChanged(Device device, int changeMask)
Notify the listener of a modified {@link Device}.

The notification of the listeners is done in a synchronized block. It is important to expect the listeners to potentially access various methods of {@link Device} as well as {@link #getDevices()} which use internal locks.

For this reason, any call to this method from a method of {@link DeviceMonitor}, {@link Device} which is also inside a synchronized block, should first synchronize on the {@link AndroidDebugBridge} lock. Access to this lock is done through {@link #getLock()}.

param
device the modified Device.
see
#getLock()

        // because the listeners could remove themselves from the list while processing
        // their event callback, we make a copy of the list and iterate on it instead of
        // the main list.
        // This mostly happens when the application quits.
        IDeviceChangeListener[] listenersCopy = null;
        synchronized (sLock) {
            listenersCopy = sDeviceListeners.toArray(
                    new IDeviceChangeListener[sDeviceListeners.size()]);
        }
        
        // Notify the listeners
        for (IDeviceChangeListener listener : listenersCopy) {
            // we attempt to catch any exception so that a bad listener doesn't kill our
            // thread
            try {
                listener.deviceChanged(device, changeMask);
            } catch (Exception e) {
                Log.e(DDMS, e);
            }
        }
    
voiddeviceConnected(Device device)
Notify the listener of a new {@link Device}.

The notification of the listeners is done in a synchronized block. It is important to expect the listeners to potentially access various methods of {@link Device} as well as {@link #getDevices()} which use internal locks.

For this reason, any call to this method from a method of {@link DeviceMonitor}, {@link Device} which is also inside a synchronized block, should first synchronize on the {@link AndroidDebugBridge} lock. Access to this lock is done through {@link #getLock()}.

param
device the new Device.
see
#getLock()

        // because the listeners could remove themselves from the list while processing
        // their event callback, we make a copy of the list and iterate on it instead of
        // the main list.
        // This mostly happens when the application quits.
        IDeviceChangeListener[] listenersCopy = null;
        synchronized (sLock) {
            listenersCopy = sDeviceListeners.toArray(
                    new IDeviceChangeListener[sDeviceListeners.size()]);
        }
        
        // Notify the listeners
        for (IDeviceChangeListener listener : listenersCopy) {
            // we attempt to catch any exception so that a bad listener doesn't kill our
            // thread
            try {
                listener.deviceConnected(device);
            } catch (Exception e) {
                Log.e(DDMS, e);
            }
        }
    
voiddeviceDisconnected(Device device)
Notify the listener of a disconnected {@link Device}.

The notification of the listeners is done in a synchronized block. It is important to expect the listeners to potentially access various methods of {@link Device} as well as {@link #getDevices()} which use internal locks.

For this reason, any call to this method from a method of {@link DeviceMonitor}, {@link Device} which is also inside a synchronized block, should first synchronize on the {@link AndroidDebugBridge} lock. Access to this lock is done through {@link #getLock()}.

param
device the disconnected Device.
see
#getLock()

        // because the listeners could remove themselves from the list while processing
        // their event callback, we make a copy of the list and iterate on it instead of
        // the main list.
        // This mostly happens when the application quits.
        IDeviceChangeListener[] listenersCopy = null;
        synchronized (sLock) {
            listenersCopy = sDeviceListeners.toArray(
                    new IDeviceChangeListener[sDeviceListeners.size()]);
        }
        
        // Notify the listeners
        for (IDeviceChangeListener listener : listenersCopy) {
            // we attempt to catch any exception so that a bad listener doesn't kill our
            // thread
            try {
                listener.deviceDisconnected(device);
            } catch (Exception e) {
                Log.e(DDMS, e);
            }
        }
    
public static voiddisconnectBridge()
Disconnects the current debug bridge, and destroy the object.

A new object will have to be created with {@link #createBridge(String, boolean)}.

        synchronized (sLock) {
            if (sThis != null) {
                sThis.stop();
                sThis = null;

                // because the listeners could remove themselves from the list while processing
                // their event callback, we make a copy of the list and iterate on it instead of
                // the main list.
                // This mostly happens when the application quits.
                IDebugBridgeChangeListener[] listenersCopy = sBridgeListeners.toArray(
                        new IDebugBridgeChangeListener[sBridgeListeners.size()]);

                // notify the listeners.
                for (IDebugBridgeChangeListener listener : listenersCopy) {
                    // we attempt to catch any exception so that a bad listener doesn't kill our
                    // thread
                    try {
                        listener.bridgeChanged(sThis);
                    } catch (Exception e) {
                        Log.e(DDMS, e);
                    }
                }
            }
        }
    
public static com.android.ddmlib.AndroidDebugBridgegetBridge()
Returns the current debug bridge. Can be null if none were created.

        return sThis;
    
static booleangetClientSupport()
Returns whether the ddmlib is setup to support monitoring and interacting with {@link Client}s running on the {@link Device}s.

        return sClientSupport;
    
public intgetConnectionAttemptCount()
Returns the number of times the {@link AndroidDebugBridge} object attempted to connect to the adb daemon.

        if (mDeviceMonitor != null) {
            return mDeviceMonitor.getConnectionAttemptCount();
        }
        return -1;
    
DeviceMonitorgetDeviceMonitor()
Returns the {@link DeviceMonitor} object.

        return mDeviceMonitor;
    
public Device[]getDevices()
Returns the devices.

see
#hasInitialDeviceList()

        synchronized (sLock) {
            if (mDeviceMonitor != null) {
                return mDeviceMonitor.getDevices();
            }
        }

        return new Device[0];
    
static java.lang.ObjectgetLock()
Returns the singleton lock used by this class to protect any access to the listener.

This includes adding/removing listeners, but also notifying listeners of new bridges, devices, and clients.

        return sLock;
    
public intgetRestartAttemptCount()
Returns the number of times the {@link AndroidDebugBridge} object attempted to restart the adb daemon.

        if (mDeviceMonitor != null) {
            return mDeviceMonitor.getRestartAttemptCount();
        }
        return -1;
    
private intgrabProcessOutput(java.lang.Process process, java.util.ArrayList errorOutput, java.util.ArrayList stdOutput, boolean waitforReaders)
Get the stderr/stdout outputs of a process and return when the process is done. Both must be read or the process will block on windows.

param
process The process to get the ouput from
param
errorOutput The array to store the stderr output. cannot be null.
param
stdOutput The array to store the stdout output. cannot be null.
param
displayStdOut If true this will display stdout as well
param
waitforReaders if true, this will wait for the reader threads.
return
the process return code.
throws
InterruptedException

        assert errorOutput != null;
        assert stdOutput != null;
        // read the lines as they come. if null is returned, it's
        // because the process finished
        Thread t1 = new Thread("") { //$NON-NLS-1$
            @Override
            public void run() {
                // create a buffer to read the stderr output
                InputStreamReader is = new InputStreamReader(process.getErrorStream());
                BufferedReader errReader = new BufferedReader(is);

                try {
                    while (true) {
                        String line = errReader.readLine();
                        if (line != null) {
                            Log.e(ADB, line);
                            errorOutput.add(line);
                        } else {
                            break;
                        }
                    }
                } catch (IOException e) {
                    // do nothing.
                }
            }
        };

        Thread t2 = new Thread("") { //$NON-NLS-1$
            @Override
            public void run() {
                InputStreamReader is = new InputStreamReader(process.getInputStream());
                BufferedReader outReader = new BufferedReader(is);

                try {
                    while (true) {
                        String line = outReader.readLine();
                        if (line != null) {
                            Log.d(ADB, line);
                            stdOutput.add(line);
                        } else {
                            break;
                        }
                    }
                } catch (IOException e) {
                    // do nothing.
                }
            }
        };

        t1.start();
        t2.start();

        // it looks like on windows process#waitFor() can return
        // before the thread have filled the arrays, so we wait for both threads and the
        // process itself.
        if (waitforReaders) {
            try {
                t1.join();
            } catch (InterruptedException e) {
            }
            try {
                t2.join();
            } catch (InterruptedException e) {
            }
        }

        // get the return code from the process
        return process.waitFor();
    
public booleanhasInitialDeviceList()
Returns whether the bridge has acquired the initial list from adb after being created.

Calling {@link #getDevices()} right after {@link #createBridge(String, boolean)} will generally result in an empty list. This is due to the internal asynchronous communication mechanism with adb that does not guarantee that the {@link Device} list has been built before the call to {@link #getDevices()}.

The recommended way to get the list of {@link Device} objects is to create a {@link IDeviceChangeListener} object.

        if (mDeviceMonitor != null) {
            return mDeviceMonitor.hasInitialDeviceList();
        }
        
        return false;
    
public static voidinit(boolean clientSupport)
Initializes the ddm library.

This must be called once before any call to {@link #createBridge(String, boolean)}.

The library can be initialized in 2 ways:

  • Mode 1: clientSupport == true.
    The library monitors the devices and the applications running on them. It will connect to each application, as a debugger of sort, to be able to interact with them through JDWP packets.
  • Mode 2: clientSupport == false.
    The library only monitors devices. The applications are left untouched, letting other tools built on ddmlib to connect a debugger to them.

Only one tool can run in mode 1 at the same time.

Note that mode 1 does not prevent debugging of applications running on devices. Mode 1 lets debuggers connect to ddmlib which acts as a proxy between the debuggers and the applications to debug. See {@link Client#getDebuggerListenPort()}.

The preferences of ddmlib should also be initialized with whatever default values were changed from the default values.

When the application quits, {@link #terminate()} should be called.

param
clientSupport Indicates whether the library should enable the monitoring and interaction with applications running on the devices.
see
AndroidDebugBridge#createBridge(String, boolean)
see
DdmPreferences


                       
       
                                         
           
    

                         
       
                                          
           

                                          
           

                                                                    
             
    

                       
       
                                                                     
             
    

                                                                                                                                                                                                   
         
        sClientSupport = clientSupport;

        MonitorThread monitorThread = MonitorThread.createInstance();
        monitorThread.start();

        HandleHello.register(monitorThread);
        HandleAppName.register(monitorThread);
        HandleTest.register(monitorThread);
        HandleThread.register(monitorThread);
        HandleHeap.register(monitorThread);
        HandleWait.register(monitorThread);
    
public booleanisConnected()
Returns whether the {@link AndroidDebugBridge} object is still connected to the adb daemon.

        MonitorThread monitorThread = MonitorThread.getInstance();
        if (mDeviceMonitor != null && monitorThread != null) {
            return mDeviceMonitor.isMonitoring() && monitorThread.getState() != State.TERMINATED;
        }
        return false;
    
public static voidremoveClientChangeListener(com.android.ddmlib.AndroidDebugBridge$IClientChangeListener listener)
Removes the listener from the collection of listeners who will be notified when a {@link Client} property changed.

param
listener The listener which should no longer be notified.

        synchronized (sLock) {
            sClientListeners.remove(listener);
        }
    
public static voidremoveDebugBridgeChangeListener(com.android.ddmlib.AndroidDebugBridge$IDebugBridgeChangeListener listener)
Removes the listener from the collection of listeners who will be notified when a new {@link AndroidDebugBridge} is started.

param
listener The listener which should no longer be notified.

        synchronized (sLock) {
            sBridgeListeners.remove(listener);
        }
    
public static voidremoveDeviceChangeListener(com.android.ddmlib.AndroidDebugBridge$IDeviceChangeListener listener)
Removes the listener from the collection of listeners who will be notified when a {@link Device} is connected, disconnected, or when its properties or its {@link Client} list changed.

param
listener The listener which should no longer be notified.

        synchronized (sLock) {
            sDeviceListeners.remove(listener);
        }
    
public booleanrestart()
Restarts adb, but not the services around it.

return
true if success.

        if (mAdbOsLocation == null) {
            Log.e(ADB,
                    "Cannot restart adb when AndroidDebugBridge is created without the location of adb."); //$NON-NLS-1$
            return false;
        }

        if (mVersionCheck == false) {
            Log.logAndDisplay(LogLevel.ERROR, ADB,
                    "Attempting to restart adb, but version check failed!"); //$NON-NLS-1$
            return false;
        }
        synchronized (this) {
            stopAdb();

            boolean restart = startAdb();

            if (restart && mDeviceMonitor == null) {
                mDeviceMonitor = new DeviceMonitor(this);
                mDeviceMonitor.start();
            }

            return restart;
        }
    
private booleanscanVersionLine(java.lang.String line)
Scans a line resulting from 'adb version' for a potential version number.

If a version number is found, it checks the version number against what is expected by this version of ddms.

Returns true when a version number has been found so that we can stop scanning, whether the version number is in the acceptable range or not.

param
line The line to scan.
return
True if a version number was found (whether it is acceptable or not).

        if (line != null) {
            Matcher matcher = sAdbVersion.matcher(line);
            if (matcher.matches()) {
                int majorVersion = Integer.parseInt(matcher.group(1));
                int minorVersion = Integer.parseInt(matcher.group(2));
                int microVersion = Integer.parseInt(matcher.group(3));

                // check only the micro version for now.
                if (microVersion < ADB_VERSION_MICRO_MIN) {
                    String message = String.format(
                            "Required minimum version of adb: %1$d.%2$d.%3$d." //$NON-NLS-1$
                            + "Current version is %1$d.%2$d.%4$d", //$NON-NLS-1$
                            majorVersion, minorVersion, ADB_VERSION_MICRO_MIN,
                            microVersion);
                    Log.logAndDisplay(LogLevel.ERROR, ADB, message);
                } else if (ADB_VERSION_MICRO_MAX != -1 &&
                        microVersion > ADB_VERSION_MICRO_MAX) {
                    String message = String.format(
                            "Required maximum version of adb: %1$d.%2$d.%3$d." //$NON-NLS-1$
                            + "Current version is %1$d.%2$d.%4$d", //$NON-NLS-1$
                            majorVersion, minorVersion, ADB_VERSION_MICRO_MAX,
                            microVersion);
                    Log.logAndDisplay(LogLevel.ERROR, ADB, message);
                } else {
                    mVersionCheck = true;
                }

                return true;
            }
        }
        return false;
    
public voidsetSelectedClient(Client selectedClient)
Sets the client to accept debugger connection on the custom "Selected debug port".

param
selectedClient the client. Can be null.

        MonitorThread monitorThread = MonitorThread.getInstance();
        if (monitorThread != null) {
            monitorThread.setSelectedClient(selectedClient);
        }
    
booleanstart()
Starts the debug bridge.

return
true if success.

        if (mAdbOsLocation != null && (mVersionCheck == false || startAdb() == false)) {
            return false;
        }

        mStarted = true;

        // now that the bridge is connected, we start the underlying services.
        mDeviceMonitor = new DeviceMonitor(this);
        mDeviceMonitor.start();

        return true;
    
synchronized booleanstartAdb()
Starts the adb host side server.

return
true if success

        if (mAdbOsLocation == null) {
            Log.e(ADB,
                "Cannot start adb when AndroidDebugBridge is created without the location of adb."); //$NON-NLS-1$
            return false;
        }

        Process proc;
        int status = -1;

        try {
            String[] command = new String[2];
            command[0] = mAdbOsLocation;
            command[1] = "start-server"; //$NON-NLS-1$
            Log.d(DDMS,
                    String.format("Launching '%1$s %2$s' to ensure ADB is running.", //$NON-NLS-1$
                    mAdbOsLocation, command[1]));
            proc = Runtime.getRuntime().exec(command);

            ArrayList<String> errorOutput = new ArrayList<String>();
            ArrayList<String> stdOutput = new ArrayList<String>();
            status = grabProcessOutput(proc, errorOutput, stdOutput,
                    false /* waitForReaders */);

        } catch (IOException ioe) {
            Log.d(DDMS, "Unable to run 'adb': " + ioe.getMessage()); //$NON-NLS-1$
            // we'll return false;
        } catch (InterruptedException ie) {
            Log.d(DDMS, "Unable to run 'adb': " + ie.getMessage()); //$NON-NLS-1$
            // we'll return false;
        }

        if (status != 0) {
            Log.w(DDMS,
                    "'adb start-server' failed -- run manually if necessary"); //$NON-NLS-1$
            return false;
        }

        Log.d(DDMS, "'adb start-server' succeeded"); //$NON-NLS-1$

        return true;
    
booleanstop()
Kills the debug bridge.

return
true if success

        // if we haven't started we return false;
        if (mStarted == false) {
            return false;
        }

        // kill the monitoring services
        mDeviceMonitor.stop();
        mDeviceMonitor = null;

        if (stopAdb() == false) {
            return false;
        }

        mStarted = false;
        return true;
    
private synchronized booleanstopAdb()
Stops the adb host side server.

return
true if success

        if (mAdbOsLocation == null) {
            Log.e(ADB,
                "Cannot stop adb when AndroidDebugBridge is created without the location of adb."); //$NON-NLS-1$
            return false;
        }

        Process proc;
        int status = -1;

        try {
            String[] command = new String[2];
            command[0] = mAdbOsLocation;
            command[1] = "kill-server"; //$NON-NLS-1$
            proc = Runtime.getRuntime().exec(command);
            status = proc.waitFor();
        }
        catch (IOException ioe) {
            // we'll return false;
        }
        catch (InterruptedException ie) {
            // we'll return false;
        }

        if (status != 0) {
            Log.w(DDMS,
                    "'adb kill-server' failed -- run manually if necessary"); //$NON-NLS-1$
            return false;
        }

        Log.d(DDMS, "'adb kill-server' succeeded"); //$NON-NLS-1$
        return true;
    
public static voidterminate()
Terminates the ddm library. This must be called upon application termination.

        // kill the monitoring services
        if (sThis != null && sThis.mDeviceMonitor != null) {
            sThis.mDeviceMonitor.stop();
            sThis.mDeviceMonitor = null;
        }

        MonitorThread monitorThread = MonitorThread.getInstance();
        if (monitorThread != null) {
            monitorThread.quit();
        }