前言
由于本人水平有限,所以这里简单的说说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
时间: 2024-10-12 03:55:27