1/* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.ddmlib; 18 19import com.android.ddmlib.log.LogReceiver; 20 21import java.io.File; 22import java.io.IOException; 23import java.nio.channels.SocketChannel; 24import java.util.ArrayList; 25import java.util.Collections; 26import java.util.HashMap; 27import java.util.List; 28import java.util.Map; 29import java.util.regex.Matcher; 30import java.util.regex.Pattern; 31 32 33/** 34 * A Device. It can be a physical device or an emulator. 35 */ 36final class Device implements IDevice { 37 private static final String DEVICE_MODEL_PROPERTY = "ro.product.model"; //$NON-NLS-1$ 38 private static final String DEVICE_MANUFACTURER_PROPERTY = "ro.product.manufacturer"; //$NON-NLS-1$ 39 40 private final static int INSTALL_TIMEOUT = 2*60*1000; //2min 41 private static final int BATTERY_TIMEOUT = 2*1000; //2 seconds 42 private static final int GETPROP_TIMEOUT = 2*1000; //2 seconds 43 44 /** Emulator Serial Number regexp. */ 45 final static String RE_EMULATOR_SN = "emulator-(\\d+)"; //$NON-NLS-1$ 46 47 /** Serial number of the device */ 48 private String mSerialNumber = null; 49 50 /** Name of the AVD */ 51 private String mAvdName = null; 52 53 /** State of the device. */ 54 private DeviceState mState = null; 55 56 /** Device properties. */ 57 private final Map<String, String> mProperties = new HashMap<String, String>(); 58 private final Map<String, String> mMountPoints = new HashMap<String, String>(); 59 60 private final ArrayList<Client> mClients = new ArrayList<Client>(); 61 private DeviceMonitor mMonitor; 62 63 private static final String LOG_TAG = "Device"; 64 private static final char SEPARATOR = '-'; 65 66 /** 67 * Socket for the connection monitoring client connection/disconnection. 68 */ 69 private SocketChannel mSocketChannel; 70 71 private boolean mArePropertiesSet = false; 72 73 private Integer mLastBatteryLevel = null; 74 private long mLastBatteryCheckTime = 0; 75 76 private String mName; 77 78 /** 79 * Output receiver for "pm install package.apk" command line. 80 */ 81 private static final class InstallReceiver extends MultiLineReceiver { 82 83 private static final String SUCCESS_OUTPUT = "Success"; //$NON-NLS-1$ 84 private static final Pattern FAILURE_PATTERN = Pattern.compile("Failure\\s+\\[(.*)\\]"); //$NON-NLS-1$ 85 86 private String mErrorMessage = null; 87 88 public InstallReceiver() { 89 } 90 91 @Override 92 public void processNewLines(String[] lines) { 93 for (String line : lines) { 94 if (line.length() > 0) { 95 if (line.startsWith(SUCCESS_OUTPUT)) { 96 mErrorMessage = null; 97 } else { 98 Matcher m = FAILURE_PATTERN.matcher(line); 99 if (m.matches()) { 100 mErrorMessage = m.group(1); 101 } 102 } 103 } 104 } 105 } 106 107 @Override 108 public boolean isCancelled() { 109 return false; 110 } 111 112 public String getErrorMessage() { 113 return mErrorMessage; 114 } 115 } 116 117 /** 118 * Output receiver for "dumpsys battery" command line. 119 */ 120 private static final class BatteryReceiver extends MultiLineReceiver { 121 private static final Pattern BATTERY_LEVEL = Pattern.compile("\\s*level: (\\d+)"); 122 private static final Pattern SCALE = Pattern.compile("\\s*scale: (\\d+)"); 123 124 private Integer mBatteryLevel = null; 125 private Integer mBatteryScale = null; 126 127 /** 128 * Get the parsed percent battery level. 129 * @return 130 */ 131 public Integer getBatteryLevel() { 132 if (mBatteryLevel != null && mBatteryScale != null) { 133 return (mBatteryLevel * 100) / mBatteryScale; 134 } 135 return null; 136 } 137 138 @Override 139 public void processNewLines(String[] lines) { 140 for (String line : lines) { 141 Matcher batteryMatch = BATTERY_LEVEL.matcher(line); 142 if (batteryMatch.matches()) { 143 try { 144 mBatteryLevel = Integer.parseInt(batteryMatch.group(1)); 145 } catch (NumberFormatException e) { 146 Log.w(LOG_TAG, String.format("Failed to parse %s as an integer", 147 batteryMatch.group(1))); 148 } 149 } 150 Matcher scaleMatch = SCALE.matcher(line); 151 if (scaleMatch.matches()) { 152 try { 153 mBatteryScale = Integer.parseInt(scaleMatch.group(1)); 154 } catch (NumberFormatException e) { 155 Log.w(LOG_TAG, String.format("Failed to parse %s as an integer", 156 batteryMatch.group(1))); 157 } 158 } 159 } 160 } 161 162 @Override 163 public boolean isCancelled() { 164 return false; 165 } 166 } 167 168 /* 169 * (non-Javadoc) 170 * @see com.android.ddmlib.IDevice#getSerialNumber() 171 */ 172 @Override 173 public String getSerialNumber() { 174 return mSerialNumber; 175 } 176 177 /** {@inheritDoc} */ 178 @Override 179 public String getAvdName() { 180 return mAvdName; 181 } 182 183 /** 184 * Sets the name of the AVD 185 */ 186 void setAvdName(String avdName) { 187 if (isEmulator() == false) { 188 throw new IllegalArgumentException( 189 "Cannot set the AVD name of the device is not an emulator"); 190 } 191 192 mAvdName = avdName; 193 } 194 195 @Override 196 public String getName() { 197 if (mName == null) { 198 mName = constructName(); 199 } 200 201 return mName; 202 } 203 204 private String constructName() { 205 if (isEmulator()) { 206 String avdName = getAvdName(); 207 if (avdName != null) { 208 return String.format("%s [%s]", avdName, getSerialNumber()); 209 } else { 210 return getSerialNumber(); 211 } 212 } else { 213 String manufacturer = cleanupStringForDisplay( 214 getProperty(DEVICE_MANUFACTURER_PROPERTY)); 215 String model = cleanupStringForDisplay( 216 getProperty(DEVICE_MODEL_PROPERTY)); 217 218 StringBuilder sb = new StringBuilder(20); 219 220 if (manufacturer != null) { 221 sb.append(manufacturer); 222 sb.append(SEPARATOR); 223 } 224 225 if (model != null) { 226 sb.append(model); 227 sb.append(SEPARATOR); 228 } 229 230 sb.append(getSerialNumber()); 231 return sb.toString(); 232 } 233 } 234 235 private String cleanupStringForDisplay(String s) { 236 if (s == null) { 237 return null; 238 } 239 240 StringBuilder sb = new StringBuilder(s.length()); 241 for (int i = 0; i < s.length(); i++) { 242 char c = s.charAt(i); 243 244 if (Character.isLetterOrDigit(c)) { 245 sb.append(Character.toLowerCase(c)); 246 } else { 247 sb.append('_'); 248 } 249 } 250 251 return sb.toString(); 252 } 253 254 /* 255 * (non-Javadoc) 256 * @see com.android.ddmlib.IDevice#getState() 257 */ 258 @Override 259 public DeviceState getState() { 260 return mState; 261 } 262 263 /** 264 * Changes the state of the device. 265 */ 266 void setState(DeviceState state) { 267 mState = state; 268 } 269 270 271 /* 272 * (non-Javadoc) 273 * @see com.android.ddmlib.IDevice#getProperties() 274 */ 275 @Override 276 public Map<String, String> getProperties() { 277 return Collections.unmodifiableMap(mProperties); 278 } 279 280 /* 281 * (non-Javadoc) 282 * @see com.android.ddmlib.IDevice#getPropertyCount() 283 */ 284 @Override 285 public int getPropertyCount() { 286 return mProperties.size(); 287 } 288 289 /* 290 * (non-Javadoc) 291 * @see com.android.ddmlib.IDevice#getProperty(java.lang.String) 292 */ 293 @Override 294 public String getProperty(String name) { 295 return mProperties.get(name); 296 } 297 298 /** 299 * {@inheritDoc} 300 */ 301 @Override 302 public boolean arePropertiesSet() { 303 return mArePropertiesSet; 304 } 305 306 /** 307 * {@inheritDoc} 308 */ 309 @Override 310 public String getPropertyCacheOrSync(String name) throws TimeoutException, 311 AdbCommandRejectedException, ShellCommandUnresponsiveException, IOException { 312 if (mArePropertiesSet) { 313 return getProperty(name); 314 } else { 315 return getPropertySync(name); 316 } 317 } 318 319 /** 320 * {@inheritDoc} 321 */ 322 @Override 323 public String getPropertySync(String name) throws TimeoutException, 324 AdbCommandRejectedException, ShellCommandUnresponsiveException, IOException { 325 CollectingOutputReceiver receiver = new CollectingOutputReceiver(); 326 executeShellCommand(String.format("getprop '%s'", name), receiver, GETPROP_TIMEOUT); 327 String value = receiver.getOutput().trim(); 328 if (value.isEmpty()) { 329 return null; 330 } 331 return value; 332 } 333 334 @Override 335 public String getMountPoint(String name) { 336 return mMountPoints.get(name); 337 } 338 339 340 @Override 341 public String toString() { 342 return mSerialNumber; 343 } 344 345 /* 346 * (non-Javadoc) 347 * @see com.android.ddmlib.IDevice#isOnline() 348 */ 349 @Override 350 public boolean isOnline() { 351 return mState == DeviceState.ONLINE; 352 } 353 354 /* 355 * (non-Javadoc) 356 * @see com.android.ddmlib.IDevice#isEmulator() 357 */ 358 @Override 359 public boolean isEmulator() { 360 return mSerialNumber.matches(RE_EMULATOR_SN); 361 } 362 363 /* 364 * (non-Javadoc) 365 * @see com.android.ddmlib.IDevice#isOffline() 366 */ 367 @Override 368 public boolean isOffline() { 369 return mState == DeviceState.OFFLINE; 370 } 371 372 /* 373 * (non-Javadoc) 374 * @see com.android.ddmlib.IDevice#isBootLoader() 375 */ 376 @Override 377 public boolean isBootLoader() { 378 return mState == DeviceState.BOOTLOADER; 379 } 380 381 /* 382 * (non-Javadoc) 383 * @see com.android.ddmlib.IDevice#hasClients() 384 */ 385 @Override 386 public boolean hasClients() { 387 return mClients.size() > 0; 388 } 389 390 /* 391 * (non-Javadoc) 392 * @see com.android.ddmlib.IDevice#getClients() 393 */ 394 @Override 395 public Client[] getClients() { 396 synchronized (mClients) { 397 return mClients.toArray(new Client[mClients.size()]); 398 } 399 } 400 401 /* 402 * (non-Javadoc) 403 * @see com.android.ddmlib.IDevice#getClient(java.lang.String) 404 */ 405 @Override 406 public Client getClient(String applicationName) { 407 synchronized (mClients) { 408 for (Client c : mClients) { 409 if (applicationName.equals(c.getClientData().getClientDescription())) { 410 return c; 411 } 412 } 413 414 } 415 416 return null; 417 } 418 419 /* 420 * (non-Javadoc) 421 * @see com.android.ddmlib.IDevice#getSyncService() 422 */ 423 @Override 424 public SyncService getSyncService() 425 throws TimeoutException, AdbCommandRejectedException, IOException { 426 SyncService syncService = new SyncService(AndroidDebugBridge.getSocketAddress(), this); 427 if (syncService.openSync()) { 428 return syncService; 429 } 430 431 return null; 432 } 433 434 /* 435 * (non-Javadoc) 436 * @see com.android.ddmlib.IDevice#getFileListingService() 437 */ 438 @Override 439 public FileListingService getFileListingService() { 440 return new FileListingService(this); 441 } 442 443 @Override 444 public RawImage getScreenshot() 445 throws TimeoutException, AdbCommandRejectedException, IOException { 446 return AdbHelper.getFrameBuffer(AndroidDebugBridge.getSocketAddress(), this); 447 } 448 449 @Override 450 public void executeShellCommand(String command, IShellOutputReceiver receiver) 451 throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException, 452 IOException { 453 AdbHelper.executeRemoteCommand(AndroidDebugBridge.getSocketAddress(), command, this, 454 receiver, DdmPreferences.getTimeOut()); 455 } 456 457 @Override 458 public void executeShellCommand(String command, IShellOutputReceiver receiver, 459 int maxTimeToOutputResponse) 460 throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException, 461 IOException { 462 AdbHelper.executeRemoteCommand(AndroidDebugBridge.getSocketAddress(), command, this, 463 receiver, maxTimeToOutputResponse); 464 } 465 466 @Override 467 public void runEventLogService(LogReceiver receiver) 468 throws TimeoutException, AdbCommandRejectedException, IOException { 469 AdbHelper.runEventLogService(AndroidDebugBridge.getSocketAddress(), this, receiver); 470 } 471 472 @Override 473 public void runLogService(String logname, LogReceiver receiver) 474 throws TimeoutException, AdbCommandRejectedException, IOException { 475 AdbHelper.runLogService(AndroidDebugBridge.getSocketAddress(), this, logname, receiver); 476 } 477 478 @Override 479 public void createForward(int localPort, int remotePort) 480 throws TimeoutException, AdbCommandRejectedException, IOException { 481 AdbHelper.createForward(AndroidDebugBridge.getSocketAddress(), this, 482 String.format("tcp:%d", localPort), //$NON-NLS-1$ 483 String.format("tcp:%d", remotePort)); //$NON-NLS-1$ 484 } 485 486 @Override 487 public void createForward(int localPort, String remoteSocketName, 488 DeviceUnixSocketNamespace namespace) throws TimeoutException, 489 AdbCommandRejectedException, IOException { 490 AdbHelper.createForward(AndroidDebugBridge.getSocketAddress(), this, 491 String.format("tcp:%d", localPort), //$NON-NLS-1$ 492 String.format("%s:%s", namespace.getType(), remoteSocketName)); //$NON-NLS-1$ 493 } 494 495 @Override 496 public void removeForward(int localPort, int remotePort) 497 throws TimeoutException, AdbCommandRejectedException, IOException { 498 AdbHelper.removeForward(AndroidDebugBridge.getSocketAddress(), this, 499 String.format("tcp:%d", localPort), //$NON-NLS-1$ 500 String.format("tcp:%d", remotePort)); //$NON-NLS-1$ 501 } 502 503 @Override 504 public void removeForward(int localPort, String remoteSocketName, 505 DeviceUnixSocketNamespace namespace) throws TimeoutException, 506 AdbCommandRejectedException, IOException { 507 AdbHelper.removeForward(AndroidDebugBridge.getSocketAddress(), this, 508 String.format("tcp:%d", localPort), //$NON-NLS-1$ 509 String.format("%s:%s", namespace.getType(), remoteSocketName)); //$NON-NLS-1$ 510 } 511 512 /* 513 * (non-Javadoc) 514 * @see com.android.ddmlib.IDevice#getClientName(int) 515 */ 516 @Override 517 public String getClientName(int pid) { 518 synchronized (mClients) { 519 for (Client c : mClients) { 520 if (c.getClientData().getPid() == pid) { 521 return c.getClientData().getClientDescription(); 522 } 523 } 524 } 525 526 return null; 527 } 528 529 530 Device(DeviceMonitor monitor, String serialNumber, DeviceState deviceState) { 531 mMonitor = monitor; 532 mSerialNumber = serialNumber; 533 mState = deviceState; 534 } 535 536 DeviceMonitor getMonitor() { 537 return mMonitor; 538 } 539 540 void addClient(Client client) { 541 synchronized (mClients) { 542 mClients.add(client); 543 } 544 } 545 546 List<Client> getClientList() { 547 return mClients; 548 } 549 550 boolean hasClient(int pid) { 551 synchronized (mClients) { 552 for (Client client : mClients) { 553 if (client.getClientData().getPid() == pid) { 554 return true; 555 } 556 } 557 } 558 559 return false; 560 } 561 562 void clearClientList() { 563 synchronized (mClients) { 564 mClients.clear(); 565 } 566 } 567 568 /** 569 * Sets the client monitoring socket. 570 * @param socketChannel the sockets 571 */ 572 void setClientMonitoringSocket(SocketChannel socketChannel) { 573 mSocketChannel = socketChannel; 574 } 575 576 /** 577 * Returns the client monitoring socket. 578 */ 579 SocketChannel getClientMonitoringSocket() { 580 return mSocketChannel; 581 } 582 583 /** 584 * Removes a {@link Client} from the list. 585 * @param client the client to remove. 586 * @param notify Whether or not to notify the listeners of a change. 587 */ 588 void removeClient(Client client, boolean notify) { 589 mMonitor.addPortToAvailableList(client.getDebuggerListenPort()); 590 synchronized (mClients) { 591 mClients.remove(client); 592 } 593 if (notify) { 594 mMonitor.getServer().deviceChanged(this, CHANGE_CLIENT_LIST); 595 } 596 } 597 598 void update(int changeMask) { 599 if ((changeMask & CHANGE_BUILD_INFO) != 0) { 600 mArePropertiesSet = true; 601 } 602 mMonitor.getServer().deviceChanged(this, changeMask); 603 } 604 605 void update(Client client, int changeMask) { 606 mMonitor.getServer().clientChanged(client, changeMask); 607 } 608 609 void addProperty(String label, String value) { 610 mProperties.put(label, value); 611 } 612 613 void setMountingPoint(String name, String value) { 614 mMountPoints.put(name, value); 615 } 616 617 @Override 618 public void pushFile(String local, String remote) 619 throws IOException, AdbCommandRejectedException, TimeoutException, SyncException { 620 SyncService sync = null; 621 try { 622 String targetFileName = getFileName(local); 623 624 Log.d(targetFileName, String.format("Uploading %1$s onto device '%2$s'", 625 targetFileName, getSerialNumber())); 626 627 sync = getSyncService(); 628 if (sync != null) { 629 String message = String.format("Uploading file onto device '%1$s'", 630 getSerialNumber()); 631 Log.d(LOG_TAG, message); 632 sync.pushFile(local, remote, SyncService.getNullProgressMonitor()); 633 } else { 634 throw new IOException("Unable to open sync connection!"); 635 } 636 } catch (TimeoutException e) { 637 Log.e(LOG_TAG, "Error during Sync: timeout."); 638 throw e; 639 640 } catch (SyncException e) { 641 Log.e(LOG_TAG, String.format("Error during Sync: %1$s", e.getMessage())); 642 throw e; 643 644 } catch (IOException e) { 645 Log.e(LOG_TAG, String.format("Error during Sync: %1$s", e.getMessage())); 646 throw e; 647 648 } finally { 649 if (sync != null) { 650 sync.close(); 651 } 652 } 653 } 654 655 @Override 656 public void pullFile(String remote, String local) 657 throws IOException, AdbCommandRejectedException, TimeoutException, SyncException { 658 SyncService sync = null; 659 try { 660 String targetFileName = getFileName(remote); 661 662 Log.d(targetFileName, String.format("Downloading %1$s from device '%2$s'", 663 targetFileName, getSerialNumber())); 664 665 sync = getSyncService(); 666 if (sync != null) { 667 String message = String.format("Downloding file from device '%1$s'", 668 getSerialNumber()); 669 Log.d(LOG_TAG, message); 670 sync.pullFile(remote, local, SyncService.getNullProgressMonitor()); 671 } else { 672 throw new IOException("Unable to open sync connection!"); 673 } 674 } catch (TimeoutException e) { 675 Log.e(LOG_TAG, "Error during Sync: timeout."); 676 throw e; 677 678 } catch (SyncException e) { 679 Log.e(LOG_TAG, String.format("Error during Sync: %1$s", e.getMessage())); 680 throw e; 681 682 } catch (IOException e) { 683 Log.e(LOG_TAG, String.format("Error during Sync: %1$s", e.getMessage())); 684 throw e; 685 686 } finally { 687 if (sync != null) { 688 sync.close(); 689 } 690 } 691 } 692 693 @Override 694 public String installPackage(String packageFilePath, boolean reinstall, String... extraArgs) 695 throws InstallException { 696 try { 697 String remoteFilePath = syncPackageToDevice(packageFilePath); 698 String result = installRemotePackage(remoteFilePath, reinstall, extraArgs); 699 removeRemotePackage(remoteFilePath); 700 return result; 701 } catch (IOException e) { 702 throw new InstallException(e); 703 } catch (AdbCommandRejectedException e) { 704 throw new InstallException(e); 705 } catch (TimeoutException e) { 706 throw new InstallException(e); 707 } catch (SyncException e) { 708 throw new InstallException(e); 709 } 710 } 711 712 @Override 713 public String syncPackageToDevice(String localFilePath) 714 throws IOException, AdbCommandRejectedException, TimeoutException, SyncException { 715 SyncService sync = null; 716 try { 717 String packageFileName = getFileName(localFilePath); 718 String remoteFilePath = String.format("/data/local/tmp/%1$s", packageFileName); //$NON-NLS-1$ 719 720 Log.d(packageFileName, String.format("Uploading %1$s onto device '%2$s'", 721 packageFileName, getSerialNumber())); 722 723 sync = getSyncService(); 724 if (sync != null) { 725 String message = String.format("Uploading file onto device '%1$s'", 726 getSerialNumber()); 727 Log.d(LOG_TAG, message); 728 sync.pushFile(localFilePath, remoteFilePath, SyncService.getNullProgressMonitor()); 729 } else { 730 throw new IOException("Unable to open sync connection!"); 731 } 732 return remoteFilePath; 733 } catch (TimeoutException e) { 734 Log.e(LOG_TAG, "Error during Sync: timeout."); 735 throw e; 736 737 } catch (SyncException e) { 738 Log.e(LOG_TAG, String.format("Error during Sync: %1$s", e.getMessage())); 739 throw e; 740 741 } catch (IOException e) { 742 Log.e(LOG_TAG, String.format("Error during Sync: %1$s", e.getMessage())); 743 throw e; 744 745 } finally { 746 if (sync != null) { 747 sync.close(); 748 } 749 } 750 } 751 752 /** 753 * Helper method to retrieve the file name given a local file path 754 * @param filePath full directory path to file 755 * @return {@link String} file name 756 */ 757 private String getFileName(String filePath) { 758 return new File(filePath).getName(); 759 } 760 761 @Override 762 public String installRemotePackage(String remoteFilePath, boolean reinstall, 763 String... extraArgs) throws InstallException { 764 try { 765 InstallReceiver receiver = new InstallReceiver(); 766 StringBuilder optionString = new StringBuilder(); 767 if (reinstall) { 768 optionString.append("-r "); 769 } 770 for (String arg : extraArgs) { 771 optionString.append(arg); 772 optionString.append(' '); 773 } 774 String cmd = String.format("pm install %1$s \"%2$s\"", optionString.toString(), 775 remoteFilePath); 776 executeShellCommand(cmd, receiver, INSTALL_TIMEOUT); 777 return receiver.getErrorMessage(); 778 } catch (TimeoutException e) { 779 throw new InstallException(e); 780 } catch (AdbCommandRejectedException e) { 781 throw new InstallException(e); 782 } catch (ShellCommandUnresponsiveException e) { 783 throw new InstallException(e); 784 } catch (IOException e) { 785 throw new InstallException(e); 786 } 787 } 788 789 @Override 790 public void removeRemotePackage(String remoteFilePath) throws InstallException { 791 try { 792 executeShellCommand("rm " + remoteFilePath, new NullOutputReceiver(), INSTALL_TIMEOUT); 793 } catch (IOException e) { 794 throw new InstallException(e); 795 } catch (TimeoutException e) { 796 throw new InstallException(e); 797 } catch (AdbCommandRejectedException e) { 798 throw new InstallException(e); 799 } catch (ShellCommandUnresponsiveException e) { 800 throw new InstallException(e); 801 } 802 } 803 804 @Override 805 public String uninstallPackage(String packageName) throws InstallException { 806 try { 807 InstallReceiver receiver = new InstallReceiver(); 808 executeShellCommand("pm uninstall " + packageName, receiver, INSTALL_TIMEOUT); 809 return receiver.getErrorMessage(); 810 } catch (TimeoutException e) { 811 throw new InstallException(e); 812 } catch (AdbCommandRejectedException e) { 813 throw new InstallException(e); 814 } catch (ShellCommandUnresponsiveException e) { 815 throw new InstallException(e); 816 } catch (IOException e) { 817 throw new InstallException(e); 818 } 819 } 820 821 /* 822 * (non-Javadoc) 823 * @see com.android.ddmlib.IDevice#reboot() 824 */ 825 @Override 826 public void reboot(String into) 827 throws TimeoutException, AdbCommandRejectedException, IOException { 828 AdbHelper.reboot(into, AndroidDebugBridge.getSocketAddress(), this); 829 } 830 831 @Override 832 public Integer getBatteryLevel() throws TimeoutException, AdbCommandRejectedException, 833 IOException, ShellCommandUnresponsiveException { 834 // use default of 5 minutes 835 return getBatteryLevel(5 * 60 * 1000); 836 } 837 838 @Override 839 public Integer getBatteryLevel(long freshnessMs) throws TimeoutException, 840 AdbCommandRejectedException, IOException, ShellCommandUnresponsiveException { 841 if (mLastBatteryLevel != null 842 && mLastBatteryCheckTime > (System.currentTimeMillis() - freshnessMs)) { 843 return mLastBatteryLevel; 844 } 845 BatteryReceiver receiver = new BatteryReceiver(); 846 executeShellCommand("dumpsys battery", receiver, BATTERY_TIMEOUT); 847 mLastBatteryLevel = receiver.getBatteryLevel(); 848 mLastBatteryCheckTime = System.currentTimeMillis(); 849 return mLastBatteryLevel; 850 } 851} 852