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