OLD | NEW |
---|---|
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 """Provides an interface to communicate with the device via the adb command. | 5 """Provides an interface to communicate with the device via the adb command. |
6 | 6 |
7 Assumes adb binary is currently on system path. | 7 Assumes adb binary is currently on system path. |
8 """ | 8 """ |
9 | 9 |
10 import collections | 10 import collections |
(...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
279 """Reboots the device and waits for the package manager to return. | 279 """Reboots the device and waits for the package manager to return. |
280 | 280 |
281 Args: | 281 Args: |
282 full_reboot: Whether to fully reboot the device or just restart the shell. | 282 full_reboot: Whether to fully reboot the device or just restart the shell. |
283 """ | 283 """ |
284 # TODO(torne): hive can't reboot the device either way without breaking the | 284 # TODO(torne): hive can't reboot the device either way without breaking the |
285 # connection; work out if we can handle this better | 285 # connection; work out if we can handle this better |
286 if os.environ.get('USING_HIVE'): | 286 if os.environ.get('USING_HIVE'): |
287 logging.warning('Ignoring reboot request as we are on hive') | 287 logging.warning('Ignoring reboot request as we are on hive') |
288 return | 288 return |
289 if full_reboot: | 289 if full_reboot or not self.IsRootEnabled(): |
290 self._adb.SendCommand('reboot') | 290 self._adb.SendCommand('reboot') |
291 timeout = 300 | |
291 else: | 292 else: |
292 self.RestartShell() | 293 self.RestartShell() |
294 timeout = 120 | |
293 self.WaitForDevicePm() | 295 self.WaitForDevicePm() |
294 self.StartMonitoringLogcat(timeout=120) | 296 self.StartMonitoringLogcat(timeout=timeout) |
295 self.WaitForLogMatch(BOOT_COMPLETE_RE, None) | 297 self.WaitForLogMatch(BOOT_COMPLETE_RE, None) |
296 | 298 |
297 def Uninstall(self, package): | 299 def Uninstall(self, package): |
298 """Uninstalls the specified package from the device. | 300 """Uninstalls the specified package from the device. |
299 | 301 |
300 Args: | 302 Args: |
301 package: Name of the package to remove. | 303 package: Name of the package to remove. |
302 | 304 |
303 Returns: | 305 Returns: |
304 A status string returned by adb uninstall | 306 A status string returned by adb uninstall |
305 """ | 307 """ |
306 uninstall_command = 'uninstall %s' % package | 308 uninstall_command = 'uninstall %s' % package |
307 | 309 |
308 logging.info('>>> $' + uninstall_command) | 310 return self._adb.SendCommand(uninstall_command, timeout_time=60, |
309 return self._adb.SendCommand(uninstall_command, timeout_time=60) | 311 cmd_logger=logging) |
310 | 312 |
311 def Install(self, package_file_path): | 313 def Install(self, package_file_path, reinstall=False, retry_count=3): |
312 """Installs the specified package to the device. | 314 """Installs the specified package to the device. |
313 | 315 |
314 Args: | 316 Args: |
315 package_file_path: Path to .apk file to install. | 317 package_file_path: Path to .apk file to install. |
318 reinstall: Whether to reinstall over existing package | |
bulach
2012/08/09 12:36:52
nit: remove retry_count from 313, since it's undoc
| |
316 | 319 |
317 Returns: | 320 Returns: |
318 A status string returned by adb install | 321 A status string returned by adb install |
319 """ | 322 """ |
320 assert os.path.isfile(package_file_path) | 323 assert os.path.isfile(package_file_path) |
321 | 324 |
322 install_command = 'install %s' % package_file_path | 325 if reinstall: |
326 install_cmd = 'install -r %s' | |
327 else: | |
328 install_cmd = 'install %s' | |
323 | 329 |
324 logging.info('>>> $' + install_command) | 330 return self._adb.SendCommand(install_cmd % package_file_path, |
325 return self._adb.SendCommand(install_command, timeout_time=2*60) | 331 timeout_time=2*60, cmd_logger=logging, |
bulach
2012/08/09 12:36:52
nit: I think it needs space around *, timeout_time
Isaac (away)
2012/08/10 04:44:35
It's like this a couple other places in this file.
| |
332 retry_count=3) | |
333 | |
334 def ManagedInstall(self, apk_path, keep_data, package_name=None, | |
335 reboots_on_failure=2): | |
336 """Installs the specified package to the device. Reboots the device on | |
337 package manager timeouts. | |
338 | |
339 Args: | |
340 apk_path: Path to .apk file to install. | |
341 keep_data: Whether to keep data if package already exists | |
342 package_name: Package name (only needed if keep_data=False | |
bulach
2012/08/09 12:36:52
nit: )
| |
343 reboots_on_failure: number of time to reboot if package manager is frozen. | |
344 | |
345 Returns: | |
346 A status string returned by adb install | |
347 """ | |
348 reboots_left = reboots_on_failure | |
349 while True: | |
350 try: | |
351 if not keep_data: | |
352 self.Uninstall(package_name) | |
353 install_status = self.Install(apk_path, keep_data, retry_count=0) | |
354 if 'Success' in install_status: | |
355 return install_status | |
356 except errors.WaitForResponseTimedOutError: | |
357 if reboots_left < 0: | |
bulach
2012/08/09 12:36:52
nit: seems that this should be <= 0, that is, pass
| |
358 raise | |
359 # Force a hard reboot on last attempt | |
360 self.Reboot(full_reboot=(reboots_left==0)) | |
bulach
2012/08/09 12:36:52
nit: space around ==
| |
361 reboots_left -= 1 | |
326 | 362 |
327 def MakeSystemFolderWritable(self): | 363 def MakeSystemFolderWritable(self): |
328 """Remounts the /system folder rw. """ | 364 """Remounts the /system folder rw. """ |
329 out = self._adb.SendCommand('remount') | 365 out = self._adb.SendCommand('remount') |
330 if out.strip() != 'remount succeeded': | 366 if out.strip() != 'remount succeeded': |
331 raise errors.MsgException('Remount failed: %s' % out) | 367 raise errors.MsgException('Remount failed: %s' % out) |
332 | 368 |
333 def RestartAdbServer(self): | 369 def RestartAdbServer(self): |
334 """Restart the adb server.""" | 370 """Restart the adb server.""" |
335 self.KillAdbServer() | 371 self.KillAdbServer() |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
378 attempts += 1 | 414 attempts += 1 |
379 if not boot_completed: | 415 if not boot_completed: |
380 raise errors.WaitForResponseTimedOutError( | 416 raise errors.WaitForResponseTimedOutError( |
381 'sys.boot_completed flag was not set after %s seconds' % wait_time) | 417 'sys.boot_completed flag was not set after %s seconds' % wait_time) |
382 | 418 |
383 def WaitForSdCardReady(self, timeout_time): | 419 def WaitForSdCardReady(self, timeout_time): |
384 """Wait for the SD card ready before pushing data into it.""" | 420 """Wait for the SD card ready before pushing data into it.""" |
385 logging.info('Waiting for SD card ready...') | 421 logging.info('Waiting for SD card ready...') |
386 sdcard_ready = False | 422 sdcard_ready = False |
387 attempts = 0 | 423 attempts = 0 |
388 wait_period = 5 | |
389 while not sdcard_ready and attempts * wait_period < timeout_time: | 424 while not sdcard_ready and attempts * wait_period < timeout_time: |
390 output = self.RunShellCommand('ls /sdcard/') | 425 output = self.RunShellCommand('ls /sdcard/') |
391 if len(output) > 0: | 426 if len(output) > 0: |
392 sdcard_ready = True | 427 sdcard_ready = True |
393 else: | 428 else: |
394 time.sleep(wait_period) | 429 time.sleep(wait_period) |
395 attempts += 1 | 430 attempts += 1 |
396 if not sdcard_ready: | 431 if not sdcard_ready: |
397 raise errors.WaitForResponseTimedOutError( | 432 raise errors.WaitForResponseTimedOutError( |
398 'SD card not ready after %s seconds' % timeout_time) | 433 'SD card not ready after %s seconds' % timeout_time) |
399 | 434 |
400 # It is tempting to turn this function into a generator, however this is not | 435 # It is tempting to turn this function into a generator, however this is not |
401 # possible without using a private (local) adb_shell instance (to ensure no | 436 # possible without using a private (local) adb_shell instance (to ensure no |
402 # other command interleaves usage of it), which would defeat the main aim of | 437 # other command interleaves usage of it), which would defeat the main aim of |
403 # being able to reuse the adb shell instance across commands. | 438 # being able to reuse the adb shell instance across commands. |
404 def RunShellCommand(self, command, timeout_time=20, log_result=True): | 439 def RunShellCommand(self, command, timeout_time=20, log_result=True): |
405 """Send a command to the adb shell and return the result. | 440 """Send a command to the adb shell and return the result. |
406 | 441 |
407 Args: | 442 Args: |
408 command: String containing the shell command to send. Must not include | 443 command: String containing the shell command to send. Must not include |
409 the single quotes as we use them to escape the whole command. | 444 the single quotes as we use them to escape the whole command. |
410 timeout_time: Number of seconds to wait for command to respond before | 445 timeout_time: Number of seconds to wait for command to respond before |
411 retrying, used by AdbInterface.SendShellCommand. | 446 retrying, used by AdbInterface.SendShellCommand. |
412 log_result: Boolean to indicate whether we should log the result of the | 447 log_result: Boolean to indicate whether we should log the result of the |
413 shell command. | 448 shell command. |
414 | 449 |
415 Returns: | 450 Returns: |
416 list containing the lines of output received from running the command | 451 list containing the lines of output received from running the command |
417 """ | 452 """ |
418 logging.info('>>> $' + command) | |
419 if "'" in command: logging.warning(command + " contains ' quotes") | 453 if "'" in command: logging.warning(command + " contains ' quotes") |
420 result = self._adb.SendShellCommand("'%s'" % command, | 454 result = self._adb.SendShellCommand("'%s'" % command, timeout_time, |
421 timeout_time).splitlines() | 455 cmd_logger=logging).splitlines() |
422 if log_result: | 456 if log_result: |
423 logging.info('\n>>> '.join(result)) | 457 logging.info('\n>>> '.join(result)) |
424 return result | 458 return result |
425 | 459 |
426 def KillAll(self, process): | 460 def KillAll(self, process): |
427 """Android version of killall, connected via adb. | 461 """Android version of killall, connected via adb. |
428 | 462 |
429 Args: | 463 Args: |
430 process: name of the process to kill off | 464 process: name of the process to kill off |
431 | 465 |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
473 elif isinstance(value, int): | 507 elif isinstance(value, int): |
474 cmd += ' --ei' | 508 cmd += ' --ei' |
475 else: | 509 else: |
476 raise NotImplementedError( | 510 raise NotImplementedError( |
477 'Need to teach StartActivity how to pass %s extras' % type(value)) | 511 'Need to teach StartActivity how to pass %s extras' % type(value)) |
478 cmd += ' %s %s' % (key, value) | 512 cmd += ' %s %s' % (key, value) |
479 if trace_file_name: | 513 if trace_file_name: |
480 cmd += ' --start-profiler ' + trace_file_name | 514 cmd += ' --start-profiler ' + trace_file_name |
481 self.RunShellCommand(cmd) | 515 self.RunShellCommand(cmd) |
482 | 516 |
483 | |
484 def CloseApplication(self, package): | 517 def CloseApplication(self, package): |
485 """Attempt to close down the application, using increasing violence. | 518 """Attempt to close down the application, using increasing violence. |
486 | 519 |
487 Args: | 520 Args: |
488 package: Name of the process to kill off, e.g. | 521 package: Name of the process to kill off, e.g. |
489 com.google.android.apps.chrome | 522 com.google.android.apps.chrome |
490 """ | 523 """ |
491 self.RunShellCommand('am force-stop ' + package) | 524 self.RunShellCommand('am force-stop ' + package) |
492 | 525 |
493 def ClearApplicationState(self, package): | 526 def ClearApplicationState(self, package): |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
533 return | 566 return |
534 | 567 |
535 # They don't match, so remove everything first and then create it. | 568 # They don't match, so remove everything first and then create it. |
536 if os.path.isdir(local_path): | 569 if os.path.isdir(local_path): |
537 self.RunShellCommand('rm -r %s' % device_path, timeout_time=2*60) | 570 self.RunShellCommand('rm -r %s' % device_path, timeout_time=2*60) |
538 self.RunShellCommand('mkdir -p %s' % device_path) | 571 self.RunShellCommand('mkdir -p %s' % device_path) |
539 | 572 |
540 # NOTE: We can't use adb_interface.Push() because it hardcodes a timeout of | 573 # NOTE: We can't use adb_interface.Push() because it hardcodes a timeout of |
541 # 60 seconds which isn't sufficient for a lot of users of this method. | 574 # 60 seconds which isn't sufficient for a lot of users of this method. |
542 push_command = 'push %s %s' % (local_path, device_path) | 575 push_command = 'push %s %s' % (local_path, device_path) |
543 logging.info('>>> $' + push_command) | 576 output = self._adb.SendCommand(push_command, timeout_time=30*60, |
544 output = self._adb.SendCommand(push_command, timeout_time=30*60) | 577 cmd_logger=logging) |
545 assert output | 578 assert output |
546 # Success looks like this: "3035 KB/s (12512056 bytes in 4.025s)" | 579 # Success looks like this: "3035 KB/s (12512056 bytes in 4.025s)" |
547 # Errors look like this: "failed to copy ... " | 580 # Errors look like this: "failed to copy ... " |
548 if not re.search('^[0-9]', output.splitlines()[-1]): | 581 if not re.search('^[0-9]', output.splitlines()[-1]): |
549 logging.critical('PUSH FAILED: ' + output) | 582 logging.critical('PUSH FAILED: ' + output) |
550 | 583 |
551 def GetFileContents(self, filename, log_result=True): | 584 def GetFileContents(self, filename, log_result=True): |
552 """Gets contents from the file specified by |filename|.""" | 585 """Gets contents from the file specified by |filename|.""" |
553 return self.RunShellCommand('if [ -f "' + filename + '" ]; then cat "' + | 586 return self.RunShellCommand('if [ -f "' + filename + '" ]; then cat "' + |
554 filename + '"; fi', log_result=log_result) | 587 filename + '"; fi', log_result=log_result) |
(...skipping 390 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
945 if len(process_results) <= 8: | 978 if len(process_results) <= 8: |
946 continue | 979 continue |
947 # Column 0 is the executable name | 980 # Column 0 is the executable name |
948 # Column 1 is the pid | 981 # Column 1 is the pid |
949 # Column 8 is the Inode in use | 982 # Column 8 is the Inode in use |
950 if process_results[8] == socket_name: | 983 if process_results[8] == socket_name: |
951 pids.append( (int(process_results[1]), process_results[0]) ) | 984 pids.append( (int(process_results[1]), process_results[0]) ) |
952 break | 985 break |
953 logging.info('PidsUsingDevicePort: %s', pids) | 986 logging.info('PidsUsingDevicePort: %s', pids) |
954 return pids | 987 return pids |
OLD | NEW |