您的位置:首页 > 移动开发 > Android开发

【Android测试】【第三节】ADB——源码浅谈

2015-12-14 15:59 791 查看
前言

  由于本人精力平有限,所以这里简单的说说ADB源码。

  首先根据前面的理解,我们已经知道了ADB是“连接手机和PC的一个桥梁”,我们经常在PC端开发的时候,会用到eclipse这个工具,这里面有一个工具叫DDMS,如下图:



 

  是不是发现通过DDMS在PC端可以看到手机的一些信息,其实呢 它就是通过 “ddmlib.jar” 来建立起ADB的。因此我们今天就通过反编译 “ddmlib.jar” 来分析一下ADB源码。

反编译

  首先不得不吐槽一下百度经验的审核人员,我看到里面“反编译jar”的经验没有,于是呢我就写了一个提交了上去,结果提交了很多次,都给我打回了,真不知道这帮审核的人员是怎么想的,这种方便别人参考的内容难道不应该被通过吗?切

  好了,说正事吧。

  ddmlib.jar 放在 <SDk path>\tools\libs 的文件夹下。

  整个反编译的过程如下:

    1、下载jd-gui-0.3.3.windows.zip (我的微云链接:http://url.cn/Zz8sOj )

    2、解压之后打开,将要编译的jar导入:



    3、展开坐标的树形结构,就是源码啦



上源码





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


AndroidDebugBridge

实现

  既然ddmlib包含了ADB,因为我们就引入它,来进行一些ADB操作。

  1、建立一个普通的Java工程;

  2、将ddmlib.jar,包含进来(这里需要主要,还需要引入guava-15.0.jar,否则会提示少 com/geogle/common/*** 的错误,guava和ddmlib存放在同一个目录下)



  3、调用AndroidDebugBridge类中的方法,完成要实现的方法(例如下面)

import com.android.ddmlib.AndroidDebugBridge;
import com.android.ddmlib.IDevice;

public class test
{
public static void main(String[] args)
{
System.out.println(" begin ");
AndroidDebugBridge.init(false);
//AndroidDebugBridge adb = AndroidDebugBridge.createBridge("E:\\adt-bundle-windows-x86_64-20140702\\sdk\\platform-tools\\adb.exe", true);
AndroidDebugBridge adb = AndroidDebugBridge.createBridge();

WaitDevices(adb);

for (IDevice device : adb.getDevices())
{
System.out.println("Device Name: "  +  device.getName());
System.out.println("Device isOnline: " + device.isOnline() );
System.out.println("Device SerialNumber: : " + device.getSerialNumber());
}
System.out.println(" end ");
}

public static void WaitDevices(AndroidDebugBridge adb)
{
int count = 0;
while (adb.hasInitialDeviceList() == false)
{
try
{
Thread.sleep(500);
System.err.println("wait for devices");
count++;
} catch (InterruptedException e)
{
}
if (count > 50)
{
System.err.println("time out\n");
break;
}
}
}
}


  运行上面的代码输出结果为:

begin
wait for devices
Device Name: samsung-gt_i9500-4d0019214ab6608f
Device isOnline: true
Device SerialNumber: : 4d0019214ab6608f
end


  

  注意区分,上面代码里的createBridge() 的方法,无参得到代表使用系统当前的ADB,如果指定了参数,且第二个参数为ture,则启动指定的ADB,这些通过源代码都可以看到。另外createBridge() 之前必须要调用 init 的方法。接下来拿到Idevice 对象就可以实现各种各样的功能了,这里只是说一下怎么用这个lib,具体你想通过这个东西来拿到什么信息,还需自己动手去写写。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: