1/*
2 * Copyright (C) 2007 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
17package com.android.ddmlib;
18
19import com.android.ddmlib.Log.LogLevel;
20
21import java.io.BufferedReader;
22import java.io.File;
23import java.io.IOException;
24import java.io.InputStreamReader;
25import java.lang.Thread.State;
26import java.net.InetAddress;
27import java.net.InetSocketAddress;
28import java.net.UnknownHostException;
29import java.security.InvalidParameterException;
30import java.util.ArrayList;
31import java.util.Map;
32import java.util.regex.Matcher;
33import java.util.regex.Pattern;
34
35/**
36 * A connection to the host-side android debug bridge (adb)
37 * <p/>This is the central point to communicate with any devices, emulators, or the applications
38 * running on them.
39 * <p/><b>{@link #init(boolean)} must be called before anything is done.</b>
40 */
41public final class AndroidDebugBridge {
42
43    /*
44     * Minimum and maximum version of adb supported. This correspond to
45     * ADB_SERVER_VERSION found in //device/tools/adb/adb.h
46     */
47
48    private final static int ADB_VERSION_MICRO_MIN = 20;
49    private final static int ADB_VERSION_MICRO_MAX = -1;
50
51    private final static Pattern sAdbVersion = Pattern.compile(
52            "^.*(\\d+)\\.(\\d+)\\.(\\d+)$"); //$NON-NLS-1$
53
54    private final static String ADB = "adb"; //$NON-NLS-1$
55    private final static String DDMS = "ddms"; //$NON-NLS-1$
56    private final static String SERVER_PORT_ENV_VAR = "ANDROID_ADB_SERVER_PORT"; //$NON-NLS-1$
57
58    // Where to find the ADB bridge.
59    final static String ADB_HOST = "127.0.0.1"; //$NON-NLS-1$
60    final static int ADB_PORT = 5037;
61
62    private static InetAddress sHostAddr;
63    private static InetSocketAddress sSocketAddr;
64
65    private static AndroidDebugBridge sThis;
66    private static boolean sInitialized = false;
67    private static boolean sClientSupport;
68
69    /** Full path to adb. */
70    private String mAdbOsLocation = null;
71
72    private boolean mVersionCheck;
73
74    private boolean mStarted = false;
75
76    private DeviceMonitor mDeviceMonitor;
77
78    private final static ArrayList<IDebugBridgeChangeListener> sBridgeListeners =
79        new ArrayList<IDebugBridgeChangeListener>();
80    private final static ArrayList<IDeviceChangeListener> sDeviceListeners =
81        new ArrayList<IDeviceChangeListener>();
82    private final static ArrayList<IClientChangeListener> sClientListeners =
83        new ArrayList<IClientChangeListener>();
84
85    // lock object for synchronization
86    private static final Object sLock = sBridgeListeners;
87
88    /**
89     * Classes which implement this interface provide a method that deals
90     * with {@link AndroidDebugBridge} changes.
91     */
92    public interface IDebugBridgeChangeListener {
93        /**
94         * Sent when a new {@link AndroidDebugBridge} is connected.
95         * <p/>
96         * This is sent from a non UI thread.
97         * @param bridge the new {@link AndroidDebugBridge} object.
98         */
99        public void bridgeChanged(AndroidDebugBridge bridge);
100    }
101
102    /**
103     * Classes which implement this interface provide methods that deal
104     * with {@link IDevice} addition, deletion, and changes.
105     */
106    public interface IDeviceChangeListener {
107        /**
108         * Sent when the a device is connected to the {@link AndroidDebugBridge}.
109         * <p/>
110         * This is sent from a non UI thread.
111         * @param device the new device.
112         */
113        public void deviceConnected(IDevice device);
114
115        /**
116         * Sent when the a device is connected to the {@link AndroidDebugBridge}.
117         * <p/>
118         * This is sent from a non UI thread.
119         * @param device the new device.
120         */
121        public void deviceDisconnected(IDevice device);
122
123        /**
124         * Sent when a device data changed, or when clients are started/terminated on the device.
125         * <p/>
126         * This is sent from a non UI thread.
127         * @param device the device that was updated.
128         * @param changeMask the mask describing what changed. It can contain any of the following
129         * values: {@link IDevice#CHANGE_BUILD_INFO}, {@link IDevice#CHANGE_STATE},
130         * {@link IDevice#CHANGE_CLIENT_LIST}
131         */
132        public void deviceChanged(IDevice device, int changeMask);
133    }
134
135    /**
136     * Classes which implement this interface provide methods that deal
137     * with {@link Client}  changes.
138     */
139    public interface IClientChangeListener {
140        /**
141         * Sent when an existing client information changed.
142         * <p/>
143         * This is sent from a non UI thread.
144         * @param client the updated client.
145         * @param changeMask the bit mask describing the changed properties. It can contain
146         * any of the following values: {@link Client#CHANGE_INFO},
147         * {@link Client#CHANGE_DEBUGGER_STATUS}, {@link Client#CHANGE_THREAD_MODE},
148         * {@link Client#CHANGE_THREAD_DATA}, {@link Client#CHANGE_HEAP_MODE},
149         * {@link Client#CHANGE_HEAP_DATA}, {@link Client#CHANGE_NATIVE_HEAP_DATA}
150         */
151        public void clientChanged(Client client, int changeMask);
152    }
153
154    /**
155     * Initializes the <code>ddm</code> library.
156     * <p/>This must be called once <b>before</b> any call to
157     * {@link #createBridge(String, boolean)}.
158     * <p>The library can be initialized in 2 ways:
159     * <ul>
160     * <li>Mode 1: <var>clientSupport</var> == <code>true</code>.<br>The library monitors the
161     * devices and the applications running on them. It will connect to each application, as a
162     * debugger of sort, to be able to interact with them through JDWP packets.</li>
163     * <li>Mode 2: <var>clientSupport</var> == <code>false</code>.<br>The library only monitors
164     * devices. The applications are left untouched, letting other tools built on
165     * <code>ddmlib</code> to connect a debugger to them.</li>
166     * </ul>
167     * <p/><b>Only one tool can run in mode 1 at the same time.</b>
168     * <p/>Note that mode 1 does not prevent debugging of applications running on devices. Mode 1
169     * lets debuggers connect to <code>ddmlib</code> which acts as a proxy between the debuggers and
170     * the applications to debug. See {@link Client#getDebuggerListenPort()}.
171     * <p/>The preferences of <code>ddmlib</code> should also be initialized with whatever default
172     * values were changed from the default values.
173     * <p/>When the application quits, {@link #terminate()} should be called.
174     * @param clientSupport Indicates whether the library should enable the monitoring and
175     * interaction with applications running on the devices.
176     * @see AndroidDebugBridge#createBridge(String, boolean)
177     * @see DdmPreferences
178     */
179    public static synchronized void init(boolean clientSupport) {
180        if (sInitialized) {
181            throw new IllegalStateException("AndroidDebugBridge.init() has already been called.");
182        }
183        sInitialized = true;
184        sClientSupport = clientSupport;
185
186        // Determine port and instantiate socket address.
187        initAdbSocketAddr();
188
189        MonitorThread monitorThread = MonitorThread.createInstance();
190        monitorThread.start();
191
192        HandleHello.register(monitorThread);
193        HandleAppName.register(monitorThread);
194        HandleTest.register(monitorThread);
195        HandleThread.register(monitorThread);
196        HandleHeap.register(monitorThread);
197        HandleWait.register(monitorThread);
198        HandleProfiling.register(monitorThread);
199        HandleNativeHeap.register(monitorThread);
200    }
201
202    /**
203     * Terminates the ddm library. This must be called upon application termination.
204     */
205    public static synchronized void terminate() {
206        // kill the monitoring services
207        if (sThis != null && sThis.mDeviceMonitor != null) {
208            sThis.mDeviceMonitor.stop();
209            sThis.mDeviceMonitor = null;
210        }
211
212        MonitorThread monitorThread = MonitorThread.getInstance();
213        if (monitorThread != null) {
214            monitorThread.quit();
215        }
216
217        sInitialized = false;
218    }
219
220    /**
221     * Returns whether the ddmlib is setup to support monitoring and interacting with
222     * {@link Client}s running on the {@link IDevice}s.
223     */
224    static boolean getClientSupport() {
225        return sClientSupport;
226    }
227
228    /**
229     * Returns the socket address of the ADB server on the host.
230     */
231    public static InetSocketAddress getSocketAddress() {
232        return sSocketAddr;
233    }
234
235    /**
236     * Creates a {@link AndroidDebugBridge} that is not linked to any particular executable.
237     * <p/>This bridge will expect adb to be running. It will not be able to start/stop/restart
238     * adb.
239     * <p/>If a bridge has already been started, it is directly returned with no changes (similar
240     * to calling {@link #getBridge()}).
241     * @return a connected bridge.
242     */
243    public static AndroidDebugBridge createBridge() {
244        synchronized (sLock) {
245            if (sThis != null) {
246                return sThis;
247            }
248
249            try {
250                sThis = new AndroidDebugBridge();
251                sThis.start();
252            } catch (InvalidParameterException e) {
253                sThis = null;
254            }
255
256            // because the listeners could remove themselves from the list while processing
257            // their event callback, we make a copy of the list and iterate on it instead of
258            // the main list.
259            // This mostly happens when the application quits.
260            IDebugBridgeChangeListener[] listenersCopy = sBridgeListeners.toArray(
261                    new IDebugBridgeChangeListener[sBridgeListeners.size()]);
262
263            // notify the listeners of the change
264            for (IDebugBridgeChangeListener listener : listenersCopy) {
265                // we attempt to catch any exception so that a bad listener doesn't kill our
266                // thread
267                try {
268                    listener.bridgeChanged(sThis);
269                } catch (Exception e) {
270                    Log.e(DDMS, e);
271                }
272            }
273
274            return sThis;
275        }
276    }
277
278
279    /**
280     * Creates a new debug bridge from the location of the command line tool.
281     * <p/>
282     * Any existing server will be disconnected, unless the location is the same and
283     * <code>forceNewBridge</code> is set to false.
284     * @param osLocation the location of the command line tool 'adb'
285     * @param forceNewBridge force creation of a new bridge even if one with the same location
286     * already exists.
287     * @return a connected bridge.
288     */
289    public static AndroidDebugBridge createBridge(String osLocation, boolean forceNewBridge) {
290        synchronized (sLock) {
291            if (sThis != null) {
292                if (sThis.mAdbOsLocation != null && sThis.mAdbOsLocation.equals(osLocation) &&
293                        forceNewBridge == false) {
294                    return sThis;
295                } else {
296                    // stop the current server
297                    sThis.stop();
298                }
299            }
300
301            try {
302                sThis = new AndroidDebugBridge(osLocation);
303                sThis.start();
304            } catch (InvalidParameterException e) {
305                sThis = null;
306            }
307
308            // because the listeners could remove themselves from the list while processing
309            // their event callback, we make a copy of the list and iterate on it instead of
310            // the main list.
311            // This mostly happens when the application quits.
312            IDebugBridgeChangeListener[] listenersCopy = sBridgeListeners.toArray(
313                    new IDebugBridgeChangeListener[sBridgeListeners.size()]);
314
315            // notify the listeners of the change
316            for (IDebugBridgeChangeListener listener : listenersCopy) {
317                // we attempt to catch any exception so that a bad listener doesn't kill our
318                // thread
319                try {
320                    listener.bridgeChanged(sThis);
321                } catch (Exception e) {
322                    Log.e(DDMS, e);
323                }
324            }
325
326            return sThis;
327        }
328    }
329
330    /**
331     * Returns the current debug bridge. Can be <code>null</code> if none were created.
332     */
333    public static AndroidDebugBridge getBridge() {
334        return sThis;
335    }
336
337    /**
338     * Disconnects the current debug bridge, and destroy the object.
339     * <p/>This also stops the current adb host server.
340     * <p/>
341     * A new object will have to be created with {@link #createBridge(String, boolean)}.
342     */
343    public static void disconnectBridge() {
344        synchronized (sLock) {
345            if (sThis != null) {
346                sThis.stop();
347                sThis = null;
348
349                // because the listeners could remove themselves from the list while processing
350                // their event callback, we make a copy of the list and iterate on it instead of
351                // the main list.
352                // This mostly happens when the application quits.
353                IDebugBridgeChangeListener[] listenersCopy = sBridgeListeners.toArray(
354                        new IDebugBridgeChangeListener[sBridgeListeners.size()]);
355
356                // notify the listeners.
357                for (IDebugBridgeChangeListener listener : listenersCopy) {
358                    // we attempt to catch any exception so that a bad listener doesn't kill our
359                    // thread
360                    try {
361                        listener.bridgeChanged(sThis);
362                    } catch (Exception e) {
363                        Log.e(DDMS, e);
364                    }
365                }
366            }
367        }
368    }
369
370    /**
371     * Adds the listener to the collection of listeners who will be notified when a new
372     * {@link AndroidDebugBridge} is connected, by sending it one of the messages defined
373     * in the {@link IDebugBridgeChangeListener} interface.
374     * @param listener The listener which should be notified.
375     */
376    public static void addDebugBridgeChangeListener(IDebugBridgeChangeListener listener) {
377        synchronized (sLock) {
378            if (sBridgeListeners.contains(listener) == false) {
379                sBridgeListeners.add(listener);
380                if (sThis != null) {
381                    // we attempt to catch any exception so that a bad listener doesn't kill our
382                    // thread
383                    try {
384                        listener.bridgeChanged(sThis);
385                    } catch (Exception e) {
386                        Log.e(DDMS, e);
387                    }
388                }
389            }
390        }
391    }
392
393    /**
394     * Removes the listener from the collection of listeners who will be notified when a new
395     * {@link AndroidDebugBridge} is started.
396     * @param listener The listener which should no longer be notified.
397     */
398    public static void removeDebugBridgeChangeListener(IDebugBridgeChangeListener listener) {
399        synchronized (sLock) {
400            sBridgeListeners.remove(listener);
401        }
402    }
403
404    /**
405     * Adds the listener to the collection of listeners who will be notified when a {@link IDevice}
406     * is connected, disconnected, or when its properties or its {@link Client} list changed,
407     * by sending it one of the messages defined in the {@link IDeviceChangeListener} interface.
408     * @param listener The listener which should be notified.
409     */
410    public static void addDeviceChangeListener(IDeviceChangeListener listener) {
411        synchronized (sLock) {
412            if (sDeviceListeners.contains(listener) == false) {
413                sDeviceListeners.add(listener);
414            }
415        }
416    }
417
418    /**
419     * Removes the listener from the collection of listeners who will be notified when a
420     * {@link IDevice} is connected, disconnected, or when its properties or its {@link Client}
421     * list changed.
422     * @param listener The listener which should no longer be notified.
423     */
424    public static void removeDeviceChangeListener(IDeviceChangeListener listener) {
425        synchronized (sLock) {
426            sDeviceListeners.remove(listener);
427        }
428    }
429
430    /**
431     * Adds the listener to the collection of listeners who will be notified when a {@link Client}
432     * property changed, by sending it one of the messages defined in the
433     * {@link IClientChangeListener} interface.
434     * @param listener The listener which should be notified.
435     */
436    public static void addClientChangeListener(IClientChangeListener listener) {
437        synchronized (sLock) {
438            if (sClientListeners.contains(listener) == false) {
439                sClientListeners.add(listener);
440            }
441        }
442    }
443
444    /**
445     * Removes the listener from the collection of listeners who will be notified when a
446     * {@link Client} property changed.
447     * @param listener The listener which should no longer be notified.
448     */
449    public static void removeClientChangeListener(IClientChangeListener listener) {
450        synchronized (sLock) {
451            sClientListeners.remove(listener);
452        }
453    }
454
455
456    /**
457     * Returns the devices.
458     * @see #hasInitialDeviceList()
459     */
460    public IDevice[] getDevices() {
461        synchronized (sLock) {
462            if (mDeviceMonitor != null) {
463                return mDeviceMonitor.getDevices();
464            }
465        }
466
467        return new IDevice[0];
468    }
469
470    /**
471     * Returns whether the bridge has acquired the initial list from adb after being created.
472     * <p/>Calling {@link #getDevices()} right after {@link #createBridge(String, boolean)} will
473     * generally result in an empty list. This is due to the internal asynchronous communication
474     * mechanism with <code>adb</code> that does not guarantee that the {@link IDevice} list has been
475     * built before the call to {@link #getDevices()}.
476     * <p/>The recommended way to get the list of {@link IDevice} objects is to create a
477     * {@link IDeviceChangeListener} object.
478     */
479    public boolean hasInitialDeviceList() {
480        if (mDeviceMonitor != null) {
481            return mDeviceMonitor.hasInitialDeviceList();
482        }
483
484        return false;
485    }
486
487    /**
488     * Sets the client to accept debugger connection on the custom "Selected debug port".
489     * @param selectedClient the client. Can be null.
490     */
491    public void setSelectedClient(Client selectedClient) {
492        MonitorThread monitorThread = MonitorThread.getInstance();
493        if (monitorThread != null) {
494            monitorThread.setSelectedClient(selectedClient);
495        }
496    }
497
498    /**
499     * Returns whether the {@link AndroidDebugBridge} object is still connected to the adb daemon.
500     */
501    public boolean isConnected() {
502        MonitorThread monitorThread = MonitorThread.getInstance();
503        if (mDeviceMonitor != null && monitorThread != null) {
504            return mDeviceMonitor.isMonitoring() && monitorThread.getState() != State.TERMINATED;
505        }
506        return false;
507    }
508
509    /**
510     * Returns the number of times the {@link AndroidDebugBridge} object attempted to connect
511     * to the adb daemon.
512     */
513    public int getConnectionAttemptCount() {
514        if (mDeviceMonitor != null) {
515            return mDeviceMonitor.getConnectionAttemptCount();
516        }
517        return -1;
518    }
519
520    /**
521     * Returns the number of times the {@link AndroidDebugBridge} object attempted to restart
522     * the adb daemon.
523     */
524    public int getRestartAttemptCount() {
525        if (mDeviceMonitor != null) {
526            return mDeviceMonitor.getRestartAttemptCount();
527        }
528        return -1;
529    }
530
531    /**
532     * Creates a new bridge.
533     * @param osLocation the location of the command line tool
534     * @throws InvalidParameterException
535     */
536    private AndroidDebugBridge(String osLocation) throws InvalidParameterException {
537        if (osLocation == null || osLocation.length() == 0) {
538            throw new InvalidParameterException();
539        }
540        mAdbOsLocation = osLocation;
541
542        checkAdbVersion();
543    }
544
545    /**
546     * Creates a new bridge not linked to any particular adb executable.
547     */
548    private AndroidDebugBridge() {
549    }
550
551    /**
552     * Queries adb for its version number and checks it against {@link #MIN_VERSION_NUMBER} and
553     * {@link #MAX_VERSION_NUMBER}
554     */
555    private void checkAdbVersion() {
556        // default is bad check
557        mVersionCheck = false;
558
559        if (mAdbOsLocation == null) {
560            return;
561        }
562
563        String[] command = new String[2];
564        command[0] = mAdbOsLocation;
565        command[1] = "version"; //$NON-NLS-1$
566        Log.d(DDMS, String.format("Checking '%1$s version'", mAdbOsLocation));
567        Process process = null;
568        try {
569            process = Runtime.getRuntime().exec(command);
570        } catch (IOException e) {
571            boolean exists = new File(mAdbOsLocation).exists();
572            String msg;
573            if (exists) {
574                msg = String.format(
575                        "Unexpected exception '%1$s' while attempting to get adb version from '%2$s'",
576                        e.getMessage(), mAdbOsLocation);
577            } else {
578                msg = "Unable to locate adb.\n" +
579                      "Please use SDK Manager and check if Android SDK platform-tools are installed.";
580            }
581            Log.logAndDisplay(LogLevel.ERROR, ADB, msg);
582            return;
583        }
584
585        ArrayList<String> errorOutput = new ArrayList<String>();
586        ArrayList<String> stdOutput = new ArrayList<String>();
587        int status;
588        try {
589            status = grabProcessOutput(process, errorOutput, stdOutput,
590                    true /* waitForReaders */);
591        } catch (InterruptedException e) {
592            return;
593        }
594
595        if (status != 0) {
596            StringBuilder builder = new StringBuilder("'adb version' failed!"); //$NON-NLS-1$
597            for (String error : errorOutput) {
598                builder.append('\n');
599                builder.append(error);
600            }
601            Log.logAndDisplay(LogLevel.ERROR, ADB, builder.toString());
602        }
603
604        // check both stdout and stderr
605        boolean versionFound = false;
606        for (String line : stdOutput) {
607            versionFound = scanVersionLine(line);
608            if (versionFound) {
609                break;
610            }
611        }
612        if (!versionFound) {
613            for (String line : errorOutput) {
614                versionFound = scanVersionLine(line);
615                if (versionFound) {
616                    break;
617                }
618            }
619        }
620
621        if (!versionFound) {
622            // if we get here, we failed to parse the output.
623            StringBuilder builder = new StringBuilder(
624                    "Failed to parse the output of 'adb version':\n"); //$NON-NLS-1$
625            builder.append("Standard Output was:\n"); //$NON-NLS-1$
626            for (String line : stdOutput) {
627                builder.append(line);
628                builder.append('\n');
629            }
630            builder.append("\nError Output was:\n"); //$NON-NLS-1$
631            for (String line : errorOutput) {
632                builder.append(line);
633                builder.append('\n');
634            }
635            Log.logAndDisplay(LogLevel.ERROR, ADB, builder.toString());
636        }
637    }
638
639    /**
640     * Scans a line resulting from 'adb version' for a potential version number.
641     * <p/>
642     * If a version number is found, it checks the version number against what is expected
643     * by this version of ddms.
644     * <p/>
645     * Returns true when a version number has been found so that we can stop scanning,
646     * whether the version number is in the acceptable range or not.
647     *
648     * @param line The line to scan.
649     * @return True if a version number was found (whether it is acceptable or not).
650     */
651    @SuppressWarnings("all") // With Eclipse 3.6, replace by @SuppressWarnings("unused")
652    private boolean scanVersionLine(String line) {
653        if (line != null) {
654            Matcher matcher = sAdbVersion.matcher(line);
655            if (matcher.matches()) {
656                int majorVersion = Integer.parseInt(matcher.group(1));
657                int minorVersion = Integer.parseInt(matcher.group(2));
658                int microVersion = Integer.parseInt(matcher.group(3));
659
660                // check only the micro version for now.
661                if (microVersion < ADB_VERSION_MICRO_MIN) {
662                    String message = String.format(
663                            "Required minimum version of adb: %1$d.%2$d.%3$d." //$NON-NLS-1$
664                            + "Current version is %1$d.%2$d.%4$d", //$NON-NLS-1$
665                            majorVersion, minorVersion, ADB_VERSION_MICRO_MIN,
666                            microVersion);
667                    Log.logAndDisplay(LogLevel.ERROR, ADB, message);
668                } else if (ADB_VERSION_MICRO_MAX != -1 &&
669                        microVersion > ADB_VERSION_MICRO_MAX) {
670                    String message = String.format(
671                            "Required maximum version of adb: %1$d.%2$d.%3$d." //$NON-NLS-1$
672                            + "Current version is %1$d.%2$d.%4$d", //$NON-NLS-1$
673                            majorVersion, minorVersion, ADB_VERSION_MICRO_MAX,
674                            microVersion);
675                    Log.logAndDisplay(LogLevel.ERROR, ADB, message);
676                } else {
677                    mVersionCheck = true;
678                }
679
680                return true;
681            }
682        }
683        return false;
684    }
685
686    /**
687     * Starts the debug bridge.
688     * @return true if success.
689     */
690    boolean start() {
691        if (mAdbOsLocation != null && (mVersionCheck == false || startAdb() == false)) {
692            return false;
693        }
694
695        mStarted = true;
696
697        // now that the bridge is connected, we start the underlying services.
698        mDeviceMonitor = new DeviceMonitor(this);
699        mDeviceMonitor.start();
700
701        return true;
702    }
703
704   /**
705     * Kills the debug bridge, and the adb host server.
706     * @return true if success
707     */
708    boolean stop() {
709        // if we haven't started we return false;
710        if (mStarted == false) {
711            return false;
712        }
713
714        // kill the monitoring services
715        mDeviceMonitor.stop();
716        mDeviceMonitor = null;
717
718        if (stopAdb() == false) {
719            return false;
720        }
721
722        mStarted = false;
723        return true;
724    }
725
726    /**
727     * Restarts adb, but not the services around it.
728     * @return true if success.
729     */
730    public boolean restart() {
731        if (mAdbOsLocation == null) {
732            Log.e(ADB,
733                    "Cannot restart adb when AndroidDebugBridge is created without the location of adb."); //$NON-NLS-1$
734            return false;
735        }
736
737        if (mVersionCheck == false) {
738            Log.logAndDisplay(LogLevel.ERROR, ADB,
739                    "Attempting to restart adb, but version check failed!"); //$NON-NLS-1$
740            return false;
741        }
742        synchronized (this) {
743            stopAdb();
744
745            boolean restart = startAdb();
746
747            if (restart && mDeviceMonitor == null) {
748                mDeviceMonitor = new DeviceMonitor(this);
749                mDeviceMonitor.start();
750            }
751
752            return restart;
753        }
754    }
755
756    /**
757     * Notify the listener of a new {@link IDevice}.
758     * <p/>
759     * The notification of the listeners is done in a synchronized block. It is important to
760     * expect the listeners to potentially access various methods of {@link IDevice} as well as
761     * {@link #getDevices()} which use internal locks.
762     * <p/>
763     * For this reason, any call to this method from a method of {@link DeviceMonitor},
764     * {@link IDevice} which is also inside a synchronized block, should first synchronize on
765     * the {@link AndroidDebugBridge} lock. Access to this lock is done through {@link #getLock()}.
766     * @param device the new <code>IDevice</code>.
767     * @see #getLock()
768     */
769    void deviceConnected(IDevice device) {
770        // because the listeners could remove themselves from the list while processing
771        // their event callback, we make a copy of the list and iterate on it instead of
772        // the main list.
773        // This mostly happens when the application quits.
774        IDeviceChangeListener[] listenersCopy = null;
775        synchronized (sLock) {
776            listenersCopy = sDeviceListeners.toArray(
777                    new IDeviceChangeListener[sDeviceListeners.size()]);
778        }
779
780        // Notify the listeners
781        for (IDeviceChangeListener listener : listenersCopy) {
782            // we attempt to catch any exception so that a bad listener doesn't kill our
783            // thread
784            try {
785                listener.deviceConnected(device);
786            } catch (Exception e) {
787                Log.e(DDMS, e);
788            }
789        }
790    }
791
792    /**
793     * Notify the listener of a disconnected {@link IDevice}.
794     * <p/>
795     * The notification of the listeners is done in a synchronized block. It is important to
796     * expect the listeners to potentially access various methods of {@link IDevice} as well as
797     * {@link #getDevices()} which use internal locks.
798     * <p/>
799     * For this reason, any call to this method from a method of {@link DeviceMonitor},
800     * {@link IDevice} which is also inside a synchronized block, should first synchronize on
801     * the {@link AndroidDebugBridge} lock. Access to this lock is done through {@link #getLock()}.
802     * @param device the disconnected <code>IDevice</code>.
803     * @see #getLock()
804     */
805    void deviceDisconnected(IDevice device) {
806        // because the listeners could remove themselves from the list while processing
807        // their event callback, we make a copy of the list and iterate on it instead of
808        // the main list.
809        // This mostly happens when the application quits.
810        IDeviceChangeListener[] listenersCopy = null;
811        synchronized (sLock) {
812            listenersCopy = sDeviceListeners.toArray(
813                    new IDeviceChangeListener[sDeviceListeners.size()]);
814        }
815
816        // Notify the listeners
817        for (IDeviceChangeListener listener : listenersCopy) {
818            // we attempt to catch any exception so that a bad listener doesn't kill our
819            // thread
820            try {
821                listener.deviceDisconnected(device);
822            } catch (Exception e) {
823                Log.e(DDMS, e);
824            }
825        }
826    }
827
828    /**
829     * Notify the listener of a modified {@link IDevice}.
830     * <p/>
831     * The notification of the listeners is done in a synchronized block. It is important to
832     * expect the listeners to potentially access various methods of {@link IDevice} as well as
833     * {@link #getDevices()} which use internal locks.
834     * <p/>
835     * For this reason, any call to this method from a method of {@link DeviceMonitor},
836     * {@link IDevice} which is also inside a synchronized block, should first synchronize on
837     * the {@link AndroidDebugBridge} lock. Access to this lock is done through {@link #getLock()}.
838     * @param device the modified <code>IDevice</code>.
839     * @see #getLock()
840     */
841    void deviceChanged(IDevice device, int changeMask) {
842        // because the listeners could remove themselves from the list while processing
843        // their event callback, we make a copy of the list and iterate on it instead of
844        // the main list.
845        // This mostly happens when the application quits.
846        IDeviceChangeListener[] listenersCopy = null;
847        synchronized (sLock) {
848            listenersCopy = sDeviceListeners.toArray(
849                    new IDeviceChangeListener[sDeviceListeners.size()]);
850        }
851
852        // Notify the listeners
853        for (IDeviceChangeListener listener : listenersCopy) {
854            // we attempt to catch any exception so that a bad listener doesn't kill our
855            // thread
856            try {
857                listener.deviceChanged(device, changeMask);
858            } catch (Exception e) {
859                Log.e(DDMS, e);
860            }
861        }
862    }
863
864    /**
865     * Notify the listener of a modified {@link Client}.
866     * <p/>
867     * The notification of the listeners is done in a synchronized block. It is important to
868     * expect the listeners to potentially access various methods of {@link IDevice} as well as
869     * {@link #getDevices()} which use internal locks.
870     * <p/>
871     * For this reason, any call to this method from a method of {@link DeviceMonitor},
872     * {@link IDevice} which is also inside a synchronized block, should first synchronize on
873     * the {@link AndroidDebugBridge} lock. Access to this lock is done through {@link #getLock()}.
874     * @param device the modified <code>Client</code>.
875     * @param changeMask the mask indicating what changed in the <code>Client</code>
876     * @see #getLock()
877     */
878    void clientChanged(Client client, int changeMask) {
879        // because the listeners could remove themselves from the list while processing
880        // their event callback, we make a copy of the list and iterate on it instead of
881        // the main list.
882        // This mostly happens when the application quits.
883        IClientChangeListener[] listenersCopy = null;
884        synchronized (sLock) {
885            listenersCopy = sClientListeners.toArray(
886                    new IClientChangeListener[sClientListeners.size()]);
887
888        }
889
890        // Notify the listeners
891        for (IClientChangeListener listener : listenersCopy) {
892            // we attempt to catch any exception so that a bad listener doesn't kill our
893            // thread
894            try {
895                listener.clientChanged(client, changeMask);
896            } catch (Exception e) {
897                Log.e(DDMS, e);
898            }
899        }
900    }
901
902    /**
903     * Returns the {@link DeviceMonitor} object.
904     */
905    DeviceMonitor getDeviceMonitor() {
906        return mDeviceMonitor;
907    }
908
909    /**
910     * Starts the adb host side server.
911     * @return true if success
912     */
913    synchronized boolean startAdb() {
914        if (mAdbOsLocation == null) {
915            Log.e(ADB,
916                "Cannot start adb when AndroidDebugBridge is created without the location of adb."); //$NON-NLS-1$
917            return false;
918        }
919
920        Process proc;
921        int status = -1;
922
923        try {
924            String[] command = new String[2];
925            command[0] = mAdbOsLocation;
926            command[1] = "start-server"; //$NON-NLS-1$
927            Log.d(DDMS,
928                    String.format("Launching '%1$s %2$s' to ensure ADB is running.", //$NON-NLS-1$
929                    mAdbOsLocation, command[1]));
930            ProcessBuilder processBuilder = new ProcessBuilder(command);
931            if (DdmPreferences.getUseAdbHost()) {
932                String adbHostValue = DdmPreferences.getAdbHostValue();
933                if (adbHostValue != null && adbHostValue.length() > 0) {
934                    //TODO : check that the String is a valid IP address
935                    Map<String, String> env = processBuilder.environment();
936                    env.put("ADBHOST", adbHostValue);
937                }
938            }
939            proc = processBuilder.start();
940
941            ArrayList<String> errorOutput = new ArrayList<String>();
942            ArrayList<String> stdOutput = new ArrayList<String>();
943            status = grabProcessOutput(proc, errorOutput, stdOutput,
944                    false /* waitForReaders */);
945
946        } catch (IOException ioe) {
947            Log.d(DDMS, "Unable to run 'adb': " + ioe.getMessage()); //$NON-NLS-1$
948            // we'll return false;
949        } catch (InterruptedException ie) {
950            Log.d(DDMS, "Unable to run 'adb': " + ie.getMessage()); //$NON-NLS-1$
951            // we'll return false;
952        }
953
954        if (status != 0) {
955            Log.w(DDMS,
956                    "'adb start-server' failed -- run manually if necessary"); //$NON-NLS-1$
957            return false;
958        }
959
960        Log.d(DDMS, "'adb start-server' succeeded"); //$NON-NLS-1$
961
962        return true;
963    }
964
965    /**
966     * Stops the adb host side server.
967     * @return true if success
968     */
969    private synchronized boolean stopAdb() {
970        if (mAdbOsLocation == null) {
971            Log.e(ADB,
972                "Cannot stop adb when AndroidDebugBridge is created without the location of adb."); //$NON-NLS-1$
973            return false;
974        }
975
976        Process proc;
977        int status = -1;
978
979        try {
980            String[] command = new String[2];
981            command[0] = mAdbOsLocation;
982            command[1] = "kill-server"; //$NON-NLS-1$
983            proc = Runtime.getRuntime().exec(command);
984            status = proc.waitFor();
985        }
986        catch (IOException ioe) {
987            // we'll return false;
988        }
989        catch (InterruptedException ie) {
990            // we'll return false;
991        }
992
993        if (status != 0) {
994            Log.w(DDMS,
995                    "'adb kill-server' failed -- run manually if necessary"); //$NON-NLS-1$
996            return false;
997        }
998
999        Log.d(DDMS, "'adb kill-server' succeeded"); //$NON-NLS-1$
1000        return true;
1001    }
1002
1003    /**
1004     * Get the stderr/stdout outputs of a process and return when the process is done.
1005     * Both <b>must</b> be read or the process will block on windows.
1006     * @param process The process to get the ouput from
1007     * @param errorOutput The array to store the stderr output. cannot be null.
1008     * @param stdOutput The array to store the stdout output. cannot be null.
1009     * @param displayStdOut If true this will display stdout as well
1010     * @param waitforReaders if true, this will wait for the reader threads.
1011     * @return the process return code.
1012     * @throws InterruptedException
1013     */
1014    private int grabProcessOutput(final Process process, final ArrayList<String> errorOutput,
1015            final ArrayList<String> stdOutput, boolean waitforReaders)
1016            throws InterruptedException {
1017        assert errorOutput != null;
1018        assert stdOutput != null;
1019        // read the lines as they come. if null is returned, it's
1020        // because the process finished
1021        Thread t1 = new Thread("") { //$NON-NLS-1$
1022            @Override
1023            public void run() {
1024                // create a buffer to read the stderr output
1025                InputStreamReader is = new InputStreamReader(process.getErrorStream());
1026                BufferedReader errReader = new BufferedReader(is);
1027
1028                try {
1029                    while (true) {
1030                        String line = errReader.readLine();
1031                        if (line != null) {
1032                            Log.e(ADB, line);
1033                            errorOutput.add(line);
1034                        } else {
1035                            break;
1036                        }
1037                    }
1038                } catch (IOException e) {
1039                    // do nothing.
1040                }
1041            }
1042        };
1043
1044        Thread t2 = new Thread("") { //$NON-NLS-1$
1045            @Override
1046            public void run() {
1047                InputStreamReader is = new InputStreamReader(process.getInputStream());
1048                BufferedReader outReader = new BufferedReader(is);
1049
1050                try {
1051                    while (true) {
1052                        String line = outReader.readLine();
1053                        if (line != null) {
1054                            Log.d(ADB, line);
1055                            stdOutput.add(line);
1056                        } else {
1057                            break;
1058                        }
1059                    }
1060                } catch (IOException e) {
1061                    // do nothing.
1062                }
1063            }
1064        };
1065
1066        t1.start();
1067        t2.start();
1068
1069        // it looks like on windows process#waitFor() can return
1070        // before the thread have filled the arrays, so we wait for both threads and the
1071        // process itself.
1072        if (waitforReaders) {
1073            try {
1074                t1.join();
1075            } catch (InterruptedException e) {
1076            }
1077            try {
1078                t2.join();
1079            } catch (InterruptedException e) {
1080            }
1081        }
1082
1083        // get the return code from the process
1084        return process.waitFor();
1085    }
1086
1087    /**
1088     * Returns the singleton lock used by this class to protect any access to the listener.
1089     * <p/>
1090     * This includes adding/removing listeners, but also notifying listeners of new bridges,
1091     * devices, and clients.
1092     */
1093    static Object getLock() {
1094        return sLock;
1095    }
1096
1097    /**
1098     * Instantiates sSocketAddr with the address of the host's adb process.
1099     */
1100    private static void initAdbSocketAddr() {
1101        try {
1102            int adb_port = determineAndValidateAdbPort();
1103            sHostAddr = InetAddress.getByName(ADB_HOST);
1104            sSocketAddr = new InetSocketAddress(sHostAddr, adb_port);
1105        } catch (UnknownHostException e) {
1106            // localhost should always be known.
1107        }
1108    }
1109
1110    /**
1111     * Determines port where ADB is expected by looking at an env variable.
1112     * <p/>
1113     * The value for the environment variable ANDROID_ADB_SERVER_PORT is validated,
1114     * IllegalArgumentException is thrown on illegal values.
1115     * <p/>
1116     * @return The port number where the host's adb should be expected or started.
1117     * @throws IllegalArgumentException if ANDROID_ADB_SERVER_PORT has a non-numeric value.
1118     */
1119    private static int determineAndValidateAdbPort() {
1120        String adb_env_var;
1121        int result = ADB_PORT;
1122        try {
1123            adb_env_var = System.getenv(SERVER_PORT_ENV_VAR);
1124
1125            if (adb_env_var != null) {
1126                adb_env_var = adb_env_var.trim();
1127            }
1128
1129            if (adb_env_var != null && adb_env_var.length() > 0) {
1130                // C tools (adb, emulator) accept hex and octal port numbers, so need to accept
1131                // them too.
1132                result = Integer.decode(adb_env_var);
1133
1134                if (result <= 0) {
1135                    String errMsg = "env var " + SERVER_PORT_ENV_VAR //$NON-NLS-1$
1136                            + ": must be >=0, got " //$NON-NLS-1$
1137                            + System.getenv(SERVER_PORT_ENV_VAR);
1138                    throw new IllegalArgumentException(errMsg);
1139                }
1140            }
1141        } catch (NumberFormatException nfEx) {
1142            String errMsg = "env var " + SERVER_PORT_ENV_VAR //$NON-NLS-1$
1143                    + ": illegal value '" //$NON-NLS-1$
1144                    + System.getenv(SERVER_PORT_ENV_VAR) + "'"; //$NON-NLS-1$
1145            throw new IllegalArgumentException(errMsg);
1146        } catch (SecurityException secEx) {
1147            // A security manager has been installed that doesn't allow access to env vars.
1148            // So an environment variable might have been set, but we can't tell.
1149            // Let's log a warning and continue with ADB's default port.
1150            // The issue is that adb would be started (by the forked process having access
1151            // to the env vars) on the desired port, but within this process, we can't figure out
1152            // what that port is. However, a security manager not granting access to env vars
1153            // but allowing to fork is a rare and interesting configuration, so the right
1154            // thing seems to be to continue using the default port, as forking is likely to
1155            // fail later on in the scenario of the security manager.
1156            Log.w(DDMS,
1157                    "No access to env variables allowed by current security manager. " //$NON-NLS-1$
1158                    + "If you've set ANDROID_ADB_SERVER_PORT: it's being ignored."); //$NON-NLS-1$
1159        }
1160        return result;
1161    }
1162
1163}
1164