1 # Copyright 2014 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
5 """Provides a variety of device interactions based on adb.
7 Eventually, this will be based on adb_wrapper.
9 # pylint: disable=unused-argument
15 import multiprocessing
25 import pylib
.android_commands
26 from pylib
import cmd_helper
27 from pylib
import constants
28 from pylib
import device_signal
29 from pylib
.device
import adb_wrapper
30 from pylib
.device
import decorators
31 from pylib
.device
import device_blacklist
32 from pylib
.device
import device_errors
33 from pylib
.device
import intent
34 from pylib
.device
import logcat_monitor
35 from pylib
.device
.commands
import install_commands
36 from pylib
.sdk
import split_select
37 from pylib
.utils
import apk_helper
38 from pylib
.utils
import base_error
39 from pylib
.utils
import device_temp_file
40 from pylib
.utils
import host_utils
41 from pylib
.utils
import md5sum
42 from pylib
.utils
import parallelizer
43 from pylib
.utils
import timeout_retry
44 from pylib
.utils
import zip_utils
49 # A sentinel object for default values
50 # TODO(jbudorick,perezju): revisit how default values are handled by
51 # the timeout_retry decorators.
54 _CONTROL_CHARGING_COMMANDS
= [
57 'witness_file': '/sys/module/pm8921_charger/parameters/disabled',
58 'enable_command': 'echo 0 > /sys/module/pm8921_charger/parameters/disabled',
60 'echo 1 > /sys/module/pm8921_charger/parameters/disabled',
64 # Setting the HIZ bit of the bq24192 causes the charger to actually ignore
65 # energy coming from USB. Setting the power_supply offline just updates the
66 # Android system to reflect that.
67 'witness_file': '/sys/kernel/debug/bq24192/INPUT_SRC_CONT',
69 'echo 0x4A > /sys/kernel/debug/bq24192/INPUT_SRC_CONT && '
70 'echo 1 > /sys/class/power_supply/usb/online'),
72 'echo 0xCA > /sys/kernel/debug/bq24192/INPUT_SRC_CONT && '
73 'chmod 644 /sys/class/power_supply/usb/online && '
74 'echo 0 > /sys/class/power_supply/usb/online'),
79 @decorators.WithExplicitTimeoutAndRetries(
80 _DEFAULT_TIMEOUT
, _DEFAULT_RETRIES
)
82 """Returns a list of Android Virtual Devices.
85 A list containing the configured AVDs.
87 lines
= cmd_helper
.GetCmdOutput([
88 os
.path
.join(constants
.ANDROID_SDK_ROOT
, 'tools', 'android'),
89 'list', 'avd']).splitlines()
92 if 'Name:' not in line
:
94 key
, value
= (s
.strip() for s
in line
.split(':', 1))
100 @decorators.WithExplicitTimeoutAndRetries(
101 _DEFAULT_TIMEOUT
, _DEFAULT_RETRIES
)
103 """Restarts the adb server.
106 CommandFailedError if we fail to kill or restart the server.
109 return not adb_wrapper
.AdbWrapper
.IsServerOnline()
112 return adb_wrapper
.AdbWrapper
.IsServerOnline()
114 adb_wrapper
.AdbWrapper
.KillServer()
115 if not timeout_retry
.WaitFor(adb_killed
, wait_period
=1, max_tries
=5):
116 # TODO(perezju): raise an exception after fixng http://crbug.com/442319
117 logging
.warning('Failed to kill adb server')
118 adb_wrapper
.AdbWrapper
.StartServer()
119 if not timeout_retry
.WaitFor(adb_started
, wait_period
=1, max_tries
=5):
120 raise device_errors
.CommandFailedError('Failed to start adb server')
124 """Return a basic ISO 8601 time stamp with the current local time."""
125 return time
.strftime('%Y%m%dT%H%M%S', time
.localtime())
128 def _JoinLines(lines
):
129 # makes sure that the last line is also terminated, and is more memory
130 # efficient than first appending an end-line to each line and then joining
131 # all of them together.
132 return ''.join(s
for line
in lines
for s
in (line
, '\n'))
135 class DeviceUtils(object):
137 _MAX_ADB_COMMAND_LENGTH
= 512
138 _MAX_ADB_OUTPUT_LENGTH
= 32768
139 _VALID_SHELL_VARIABLE
= re
.compile('^[a-zA-Z_][a-zA-Z0-9_]*$')
141 # Property in /data/local.prop that controls Java assertions.
142 JAVA_ASSERT_PROPERTY
= 'dalvik.vm.enableassertions'
144 def __init__(self
, device
, default_timeout
=_DEFAULT_TIMEOUT
,
145 default_retries
=_DEFAULT_RETRIES
):
146 """DeviceUtils constructor.
149 device: Either a device serial, an existing AdbWrapper instance, or an
150 an existing AndroidCommands instance.
151 default_timeout: An integer containing the default number of seconds to
152 wait for an operation to complete if no explicit value
154 default_retries: An integer containing the default number or times an
155 operation should be retried on failure if no explicit
159 self
.old_interface
= None
160 if isinstance(device
, basestring
):
161 self
.adb
= adb_wrapper
.AdbWrapper(device
)
162 self
.old_interface
= pylib
.android_commands
.AndroidCommands(device
)
163 elif isinstance(device
, adb_wrapper
.AdbWrapper
):
165 self
.old_interface
= pylib
.android_commands
.AndroidCommands(str(device
))
166 elif isinstance(device
, pylib
.android_commands
.AndroidCommands
):
167 self
.adb
= adb_wrapper
.AdbWrapper(device
.GetDevice())
168 self
.old_interface
= device
170 raise ValueError('Unsupported device value: %r' % device
)
171 self
._commands
_installed
= None
172 self
._default
_timeout
= default_timeout
173 self
._default
_retries
= default_retries
175 self
._client
_caches
= {}
176 assert hasattr(self
, decorators
.DEFAULT_TIMEOUT_ATTR
)
177 assert hasattr(self
, decorators
.DEFAULT_RETRIES_ATTR
)
179 def __eq__(self
, other
):
180 """Checks whether |other| refers to the same device as |self|.
183 other: The object to compare to. This can be a basestring, an instance
184 of adb_wrapper.AdbWrapper, or an instance of DeviceUtils.
186 Whether |other| refers to the same device as |self|.
188 return self
.adb
.GetDeviceSerial() == str(other
)
190 def __lt__(self
, other
):
191 """Compares two instances of DeviceUtils.
193 This merely compares their serial numbers.
196 other: The instance of DeviceUtils to compare to.
198 Whether |self| is less than |other|.
200 return self
.adb
.GetDeviceSerial() < other
.adb
.GetDeviceSerial()
203 """Returns the device serial."""
204 return self
.adb
.GetDeviceSerial()
206 @decorators.WithTimeoutAndRetriesFromInstance()
207 def IsOnline(self
, timeout
=None, retries
=None):
208 """Checks whether the device is online.
211 timeout: timeout in seconds
212 retries: number of retries
215 True if the device is online, False otherwise.
218 CommandTimeoutError on timeout.
221 return self
.adb
.GetState() == 'device'
222 except base_error
.BaseError
as exc
:
223 logging
.info('Failed to get state: %s', exc
)
226 @decorators.WithTimeoutAndRetriesFromInstance()
227 def HasRoot(self
, timeout
=None, retries
=None):
228 """Checks whether or not adbd has root privileges.
231 timeout: timeout in seconds
232 retries: number of retries
235 True if adbd has root privileges, False otherwise.
238 CommandTimeoutError on timeout.
239 DeviceUnreachableError on missing device.
242 self
.RunShellCommand('ls /root', check_return
=True)
244 except device_errors
.AdbCommandFailedError
:
247 def NeedsSU(self
, timeout
=DEFAULT
, retries
=DEFAULT
):
248 """Checks whether 'su' is needed to access protected resources.
251 timeout: timeout in seconds
252 retries: number of retries
255 True if 'su' is available on the device and is needed to to access
256 protected resources; False otherwise if either 'su' is not available
257 (e.g. because the device has a user build), or not needed (because adbd
258 already has root privileges).
261 CommandTimeoutError on timeout.
262 DeviceUnreachableError on missing device.
264 if 'needs_su' not in self
._cache
:
266 self
.RunShellCommand(
267 'su -c ls /root && ! ls /root', check_return
=True,
268 timeout
=self
._default
_timeout
if timeout
is DEFAULT
else timeout
,
269 retries
=self
._default
_retries
if retries
is DEFAULT
else retries
)
270 self
._cache
['needs_su'] = True
271 except device_errors
.AdbCommandFailedError
:
272 self
._cache
['needs_su'] = False
273 return self
._cache
['needs_su']
276 @decorators.WithTimeoutAndRetriesFromInstance()
277 def EnableRoot(self
, timeout
=None, retries
=None):
278 """Restarts adbd with root privileges.
281 timeout: timeout in seconds
282 retries: number of retries
285 CommandFailedError if root could not be enabled.
286 CommandTimeoutError on timeout.
288 if self
.IsUserBuild():
289 raise device_errors
.CommandFailedError(
290 'Cannot enable root in user builds.', str(self
))
291 if 'needs_su' in self
._cache
:
292 del self
._cache
['needs_su']
294 self
.WaitUntilFullyBooted()
296 @decorators.WithTimeoutAndRetriesFromInstance()
297 def IsUserBuild(self
, timeout
=None, retries
=None):
298 """Checks whether or not the device is running a user build.
301 timeout: timeout in seconds
302 retries: number of retries
305 True if the device is running a user build, False otherwise (i.e. if
306 it's running a userdebug build).
309 CommandTimeoutError on timeout.
310 DeviceUnreachableError on missing device.
312 return self
.build_type
== 'user'
314 @decorators.WithTimeoutAndRetriesFromInstance()
315 def GetExternalStoragePath(self
, timeout
=None, retries
=None):
316 """Get the device's path to its SD card.
319 timeout: timeout in seconds
320 retries: number of retries
323 The device's path to its SD card.
326 CommandFailedError if the external storage path could not be determined.
327 CommandTimeoutError on timeout.
328 DeviceUnreachableError on missing device.
330 if 'external_storage' in self
._cache
:
331 return self
._cache
['external_storage']
333 value
= self
.RunShellCommand('echo $EXTERNAL_STORAGE',
337 raise device_errors
.CommandFailedError('$EXTERNAL_STORAGE is not set',
339 self
._cache
['external_storage'] = value
342 @decorators.WithTimeoutAndRetriesFromInstance()
343 def GetApplicationPaths(self
, package
, timeout
=None, retries
=None):
344 """Get the paths of the installed apks on the device for the given package.
347 package: Name of the package.
350 List of paths to the apks on the device for the given package.
352 # 'pm path' is liable to incorrectly exit with a nonzero number starting
354 # TODO(jbudorick): Check if this is fixed as new Android versions are
355 # released to put an upper bound on this.
356 should_check_return
= (self
.build_version_sdk
<
357 constants
.ANDROID_SDK_VERSION_CODES
.LOLLIPOP
)
358 output
= self
.RunShellCommand(
359 ['pm', 'path', package
], check_return
=should_check_return
)
362 if not line
.startswith('package:'):
363 raise device_errors
.CommandFailedError(
364 'pm path returned: %r' % '\n'.join(output
), str(self
))
365 apks
.append(line
[len('package:'):])
368 @decorators.WithTimeoutAndRetriesFromInstance()
369 def GetApplicationDataDirectory(self
, package
, timeout
=None, retries
=None):
370 """Get the data directory on the device for the given package.
373 package: Name of the package.
376 The package's data directory, or None if the package doesn't exist on the
380 output
= self
._RunPipedShellCommand
(
381 'pm dump %s | grep dataDir=' % cmd_helper
.SingleQuote(package
))
383 _
, _
, dataDir
= line
.partition('dataDir=')
386 except device_errors
.CommandFailedError
:
387 logging
.exception('Could not find data directory for %s', package
)
390 @decorators.WithTimeoutAndRetriesFromInstance()
391 def WaitUntilFullyBooted(self
, wifi
=False, timeout
=None, retries
=None):
392 """Wait for the device to fully boot.
394 This means waiting for the device to boot, the package manager to be
395 available, and the SD card to be ready. It can optionally mean waiting
396 for wifi to come up, too.
399 wifi: A boolean indicating if we should wait for wifi to come up or not.
400 timeout: timeout in seconds
401 retries: number of retries
404 CommandFailedError on failure.
405 CommandTimeoutError if one of the component waits times out.
406 DeviceUnreachableError if the device becomes unresponsive.
410 self
.RunShellCommand(['test', '-d', self
.GetExternalStoragePath()],
413 except device_errors
.AdbCommandFailedError
:
418 return self
.GetApplicationPaths('android')
419 except device_errors
.CommandFailedError
:
422 def boot_completed():
423 return self
.GetProp('sys.boot_completed') == '1'
426 return 'Wi-Fi is enabled' in self
.RunShellCommand(['dumpsys', 'wifi'],
429 self
.adb
.WaitForDevice()
430 timeout_retry
.WaitFor(sd_card_ready
)
431 timeout_retry
.WaitFor(pm_ready
)
432 timeout_retry
.WaitFor(boot_completed
)
434 timeout_retry
.WaitFor(wifi_enabled
)
436 REBOOT_DEFAULT_TIMEOUT
= 10 * _DEFAULT_TIMEOUT
437 REBOOT_DEFAULT_RETRIES
= _DEFAULT_RETRIES
439 @decorators.WithTimeoutAndRetriesDefaults(
440 REBOOT_DEFAULT_TIMEOUT
,
441 REBOOT_DEFAULT_RETRIES
)
442 def Reboot(self
, block
=True, wifi
=False, timeout
=None, retries
=None):
443 """Reboot the device.
446 block: A boolean indicating if we should wait for the reboot to complete.
447 wifi: A boolean indicating if we should wait for wifi to be enabled after
448 the reboot. The option has no effect unless |block| is also True.
449 timeout: timeout in seconds
450 retries: number of retries
453 CommandTimeoutError on timeout.
454 DeviceUnreachableError on missing device.
456 def device_offline():
457 return not self
.IsOnline()
461 timeout_retry
.WaitFor(device_offline
, wait_period
=1)
463 self
.WaitUntilFullyBooted(wifi
=wifi
)
465 INSTALL_DEFAULT_TIMEOUT
= 4 * _DEFAULT_TIMEOUT
466 INSTALL_DEFAULT_RETRIES
= _DEFAULT_RETRIES
468 @decorators.WithTimeoutAndRetriesDefaults(
469 INSTALL_DEFAULT_TIMEOUT
,
470 INSTALL_DEFAULT_RETRIES
)
471 def Install(self
, apk_path
, reinstall
=False, timeout
=None, retries
=None):
474 Noop if an identical APK is already installed.
477 apk_path: A string containing the path to the APK to install.
478 reinstall: A boolean indicating if we should keep any existing app data.
479 timeout: timeout in seconds
480 retries: number of retries
483 CommandFailedError if the installation fails.
484 CommandTimeoutError if the installation times out.
485 DeviceUnreachableError on missing device.
487 package_name
= apk_helper
.GetPackageName(apk_path
)
488 device_paths
= self
.GetApplicationPaths(package_name
)
490 if len(device_paths
) > 1:
492 'Installing single APK (%s) when split APKs (%s) are currently '
493 'installed.', apk_path
, ' '.join(device_paths
))
494 (files_to_push
, _
) = self
._GetChangedAndStaleFiles
(
495 apk_path
, device_paths
[0])
496 should_install
= bool(files_to_push
)
497 if should_install
and not reinstall
:
498 self
.adb
.Uninstall(package_name
)
500 should_install
= True
502 self
.adb
.Install(apk_path
, reinstall
=reinstall
)
504 @decorators.WithTimeoutAndRetriesDefaults(
505 INSTALL_DEFAULT_TIMEOUT
,
506 INSTALL_DEFAULT_RETRIES
)
507 def InstallSplitApk(self
, base_apk
, split_apks
, reinstall
=False,
508 timeout
=None, retries
=None):
509 """Install a split APK.
511 Noop if all of the APK splits are already installed.
514 base_apk: A string of the path to the base APK.
515 split_apks: A list of strings of paths of all of the APK splits.
516 reinstall: A boolean indicating if we should keep any existing app data.
517 timeout: timeout in seconds
518 retries: number of retries
521 CommandFailedError if the installation fails.
522 CommandTimeoutError if the installation times out.
523 DeviceUnreachableError on missing device.
524 DeviceVersionError if device SDK is less than Android L.
526 self
._CheckSdkLevel
(constants
.ANDROID_SDK_VERSION_CODES
.LOLLIPOP
)
528 all_apks
= [base_apk
] + split_select
.SelectSplits(
529 self
, base_apk
, split_apks
)
530 package_name
= apk_helper
.GetPackageName(base_apk
)
531 device_apk_paths
= self
.GetApplicationPaths(package_name
)
534 partial_install_package
= package_name
535 device_checksums
= md5sum
.CalculateDeviceMd5Sums(device_apk_paths
, self
)
536 host_checksums
= md5sum
.CalculateHostMd5Sums(all_apks
)
537 apks_to_install
= [k
for (k
, v
) in host_checksums
.iteritems()
538 if v
not in device_checksums
.values()]
539 if apks_to_install
and not reinstall
:
540 self
.adb
.Uninstall(package_name
)
541 partial_install_package
= None
542 apks_to_install
= all_apks
544 partial_install_package
= None
545 apks_to_install
= all_apks
547 self
.adb
.InstallMultiple(
548 apks_to_install
, partial
=partial_install_package
, reinstall
=reinstall
)
550 def _CheckSdkLevel(self
, required_sdk_level
):
551 """Raises an exception if the device does not have the required SDK level.
553 if self
.build_version_sdk
< required_sdk_level
:
554 raise device_errors
.DeviceVersionError(
555 ('Requires SDK level %s, device is SDK level %s' %
556 (required_sdk_level
, self
.build_version_sdk
)),
557 device_serial
=self
.adb
.GetDeviceSerial())
560 @decorators.WithTimeoutAndRetriesFromInstance()
561 def RunShellCommand(self
, cmd
, check_return
=False, cwd
=None, env
=None,
562 as_root
=False, single_line
=False, large_output
=False,
563 timeout
=None, retries
=None):
564 """Run an ADB shell command.
566 The command to run |cmd| should be a sequence of program arguments or else
569 When |cmd| is a sequence, it is assumed to contain the name of the command
570 to run followed by its arguments. In this case, arguments are passed to the
571 command exactly as given, without any further processing by the shell. This
572 allows to easily pass arguments containing spaces or special characters
573 without having to worry about getting quoting right. Whenever possible, it
574 is recomended to pass |cmd| as a sequence.
576 When |cmd| is given as a string, it will be interpreted and run by the
579 This behaviour is consistent with that of command runners in cmd_helper as
580 well as Python's own subprocess.Popen.
582 TODO(perezju) Change the default of |check_return| to True when callers
583 have switched to the new behaviour.
586 cmd: A string with the full command to run on the device, or a sequence
587 containing the command and its arguments.
588 check_return: A boolean indicating whether or not the return code should
590 cwd: The device directory in which the command should be run.
591 env: The environment variables with which the command should be run.
592 as_root: A boolean indicating whether the shell command should be run
593 with root privileges.
594 single_line: A boolean indicating if only a single line of output is
596 large_output: Uses a work-around for large shell command output. Without
597 this large output will be truncated.
598 timeout: timeout in seconds
599 retries: number of retries
602 If single_line is False, the output of the command as a list of lines,
603 otherwise, a string with the unique line of output emmited by the command
604 (with the optional newline at the end stripped).
607 AdbCommandFailedError if check_return is True and the exit code of
608 the command run on the device is non-zero.
609 CommandFailedError if single_line is True but the output contains two or
611 CommandTimeoutError on timeout.
612 DeviceUnreachableError on missing device.
614 def env_quote(key
, value
):
615 if not DeviceUtils
._VALID
_SHELL
_VARIABLE
.match(key
):
616 raise KeyError('Invalid shell variable name %r' % key
)
617 # using double quotes here to allow interpolation of shell variables
618 return '%s=%s' % (key
, cmd_helper
.DoubleQuote(value
))
621 return self
.adb
.Shell(cmd
)
623 def handle_check_return(cmd
):
626 except device_errors
.AdbCommandFailedError
as exc
:
632 def handle_large_command(cmd
):
633 if len(cmd
) < self
._MAX
_ADB
_COMMAND
_LENGTH
:
634 return handle_check_return(cmd
)
636 with device_temp_file
.DeviceTempFile(self
.adb
, suffix
='.sh') as script
:
637 self
._WriteFileWithPush
(script
.name
, cmd
)
638 logging
.info('Large shell command will be run from file: %s ...',
640 return handle_check_return('sh %s' % script
.name_quoted
)
642 def handle_large_output(cmd
, large_output_mode
):
643 if large_output_mode
:
644 with device_temp_file
.DeviceTempFile(self
.adb
) as large_output_file
:
645 cmd
= '%s > %s' % (cmd
, large_output_file
.name
)
646 logging
.debug('Large output mode enabled. Will write output to '
647 'device and read results from file.')
648 handle_large_command(cmd
)
649 return self
.ReadFile(large_output_file
.name
, force_pull
=True)
652 return handle_large_command(cmd
)
653 except device_errors
.AdbCommandFailedError
as exc
:
654 if exc
.status
is None:
655 logging
.exception('No output found for %s', cmd
)
656 logging
.warning('Attempting to run in large_output mode.')
657 logging
.warning('Use RunShellCommand(..., large_output=True) for '
658 'shell commands that expect a lot of output.')
659 return handle_large_output(cmd
, True)
663 if not isinstance(cmd
, basestring
):
664 cmd
= ' '.join(cmd_helper
.SingleQuote(s
) for s
in cmd
)
666 env
= ' '.join(env_quote(k
, v
) for k
, v
in env
.iteritems())
667 cmd
= '%s %s' % (env
, cmd
)
669 cmd
= 'cd %s && %s' % (cmd_helper
.SingleQuote(cwd
), cmd
)
670 if as_root
and self
.NeedsSU():
671 # "su -c sh -c" allows using shell features in |cmd|
672 cmd
= 'su -c sh -c %s' % cmd_helper
.SingleQuote(cmd
)
674 output
= handle_large_output(cmd
, large_output
).splitlines()
679 elif len(output
) == 1:
682 msg
= 'one line of output was expected, but got: %s'
683 raise device_errors
.CommandFailedError(msg
% output
, str(self
))
687 def _RunPipedShellCommand(self
, script
, **kwargs
):
688 PIPESTATUS_LEADER
= 'PIPESTATUS: '
690 script
+= '; echo "%s${PIPESTATUS[@]}"' % PIPESTATUS_LEADER
691 kwargs
['check_return'] = True
692 output
= self
.RunShellCommand(script
, **kwargs
)
693 pipestatus_line
= output
[-1]
695 if not pipestatus_line
.startswith(PIPESTATUS_LEADER
):
696 logging
.error('Pipe exit statuses of shell script missing.')
697 raise device_errors
.AdbShellCommandFailedError(
698 script
, output
, status
=None,
699 device_serial
=self
.adb
.GetDeviceSerial())
703 int(s
) for s
in pipestatus_line
[len(PIPESTATUS_LEADER
):].split()]
705 raise device_errors
.AdbShellCommandFailedError(
706 script
, output
, status
=statuses
,
707 device_serial
=self
.adb
.GetDeviceSerial())
710 @decorators.WithTimeoutAndRetriesFromInstance()
711 def KillAll(self
, process_name
, signum
=device_signal
.SIGKILL
, as_root
=False,
712 blocking
=False, quiet
=False, timeout
=None, retries
=None):
713 """Kill all processes with the given name on the device.
716 process_name: A string containing the name of the process to kill.
717 signum: An integer containing the signal number to send to kill. Defaults
719 as_root: A boolean indicating whether the kill should be executed with
721 blocking: A boolean indicating whether we should wait until all processes
722 with the given |process_name| are dead.
723 quiet: A boolean indicating whether to ignore the fact that no processes
725 timeout: timeout in seconds
726 retries: number of retries
729 The number of processes attempted to kill.
732 CommandFailedError if no process was killed and |quiet| is False.
733 CommandTimeoutError on timeout.
734 DeviceUnreachableError on missing device.
736 pids
= self
.GetPids(process_name
)
741 raise device_errors
.CommandFailedError(
742 'No process "%s"' % process_name
, str(self
))
744 cmd
= ['kill', '-%d' % signum
] + pids
.values()
745 self
.RunShellCommand(cmd
, as_root
=as_root
, check_return
=True)
748 # TODO(perezu): use timeout_retry.WaitFor
750 while self
.GetPids(process_name
):
751 time
.sleep(wait_period
)
755 @decorators.WithTimeoutAndRetriesFromInstance()
756 def StartActivity(self
, intent_obj
, blocking
=False, trace_file_name
=None,
757 force_stop
=False, timeout
=None, retries
=None):
758 """Start package's activity on the device.
761 intent_obj: An Intent object to send.
762 blocking: A boolean indicating whether we should wait for the activity to
764 trace_file_name: If present, a string that both indicates that we want to
765 profile the activity and contains the path to which the
766 trace should be saved.
767 force_stop: A boolean indicating whether we should stop the activity
769 timeout: timeout in seconds
770 retries: number of retries
773 CommandFailedError if the activity could not be started.
774 CommandTimeoutError on timeout.
775 DeviceUnreachableError on missing device.
777 cmd
= ['am', 'start']
781 cmd
.extend(['--start-profiler', trace_file_name
])
784 cmd
.extend(intent_obj
.am_args
)
785 for line
in self
.RunShellCommand(cmd
, check_return
=True):
786 if line
.startswith('Error:'):
787 raise device_errors
.CommandFailedError(line
, str(self
))
789 @decorators.WithTimeoutAndRetriesFromInstance()
790 def StartInstrumentation(self
, component
, finish
=True, raw
=False,
791 extras
=None, timeout
=None, retries
=None):
795 cmd
= ['am', 'instrument']
800 for k
, v
in extras
.iteritems():
801 cmd
.extend(['-e', str(k
), str(v
)])
802 cmd
.append(component
)
803 return self
.RunShellCommand(cmd
, check_return
=True, large_output
=True)
805 @decorators.WithTimeoutAndRetriesFromInstance()
806 def BroadcastIntent(self
, intent_obj
, timeout
=None, retries
=None):
807 """Send a broadcast intent.
810 intent: An Intent to broadcast.
811 timeout: timeout in seconds
812 retries: number of retries
815 CommandTimeoutError on timeout.
816 DeviceUnreachableError on missing device.
818 cmd
= ['am', 'broadcast'] + intent_obj
.am_args
819 self
.RunShellCommand(cmd
, check_return
=True)
821 @decorators.WithTimeoutAndRetriesFromInstance()
822 def GoHome(self
, timeout
=None, retries
=None):
823 """Return to the home screen.
826 timeout: timeout in seconds
827 retries: number of retries
830 CommandTimeoutError on timeout.
831 DeviceUnreachableError on missing device.
834 intent
.Intent(action
='android.intent.action.MAIN',
835 category
='android.intent.category.HOME'),
838 @decorators.WithTimeoutAndRetriesFromInstance()
839 def ForceStop(self
, package
, timeout
=None, retries
=None):
840 """Close the application.
843 package: A string containing the name of the package to stop.
844 timeout: timeout in seconds
845 retries: number of retries
848 CommandTimeoutError on timeout.
849 DeviceUnreachableError on missing device.
851 self
.RunShellCommand(['am', 'force-stop', package
], check_return
=True)
853 @decorators.WithTimeoutAndRetriesFromInstance()
854 def ClearApplicationState(self
, package
, timeout
=None, retries
=None):
855 """Clear all state for the given package.
858 package: A string containing the name of the package to stop.
859 timeout: timeout in seconds
860 retries: number of retries
863 CommandTimeoutError on timeout.
864 DeviceUnreachableError on missing device.
866 # Check that the package exists before clearing it for android builds below
867 # JB MR2. Necessary because calling pm clear on a package that doesn't exist
869 if ((self
.build_version_sdk
>=
870 constants
.ANDROID_SDK_VERSION_CODES
.JELLY_BEAN_MR2
)
871 or self
.GetApplicationPaths(package
)):
872 self
.RunShellCommand(['pm', 'clear', package
], check_return
=True)
874 @decorators.WithTimeoutAndRetriesFromInstance()
875 def SendKeyEvent(self
, keycode
, timeout
=None, retries
=None):
876 """Sends a keycode to the device.
878 See the pylib.constants.keyevent module for suitable keycode values.
881 keycode: A integer keycode to send to the device.
882 timeout: timeout in seconds
883 retries: number of retries
886 CommandTimeoutError on timeout.
887 DeviceUnreachableError on missing device.
889 self
.RunShellCommand(['input', 'keyevent', format(keycode
, 'd')],
892 PUSH_CHANGED_FILES_DEFAULT_TIMEOUT
= 10 * _DEFAULT_TIMEOUT
893 PUSH_CHANGED_FILES_DEFAULT_RETRIES
= _DEFAULT_RETRIES
895 @decorators.WithTimeoutAndRetriesDefaults(
896 PUSH_CHANGED_FILES_DEFAULT_TIMEOUT
,
897 PUSH_CHANGED_FILES_DEFAULT_RETRIES
)
898 def PushChangedFiles(self
, host_device_tuples
, timeout
=None,
899 retries
=None, delete_device_stale
=False):
900 """Push files to the device, skipping files that don't need updating.
902 When a directory is pushed, it is traversed recursively on the host and
903 all files in it are pushed to the device as needed.
904 Additionally, if delete_device_stale option is True,
905 files that exist on the device but don't exist on the host are deleted.
908 host_device_tuples: A list of (host_path, device_path) tuples, where
909 |host_path| is an absolute path of a file or directory on the host
910 that should be minimially pushed to the device, and |device_path| is
911 an absolute path of the destination on the device.
912 timeout: timeout in seconds
913 retries: number of retries
914 delete_device_stale: option to delete stale files on device
917 CommandFailedError on failure.
918 CommandTimeoutError on timeout.
919 DeviceUnreachableError on missing device.
922 all_changed_files
= []
924 for h
, d
in host_device_tuples
:
926 self
.RunShellCommand(['mkdir', '-p', d
], check_return
=True)
927 (changed_files
, stale_files
) = self
._GetChangedAndStaleFiles
(h
, d
)
928 all_changed_files
+= changed_files
929 all_stale_files
+= stale_files
931 if delete_device_stale
:
932 self
.RunShellCommand(['rm', '-f'] + all_stale_files
,
935 if not all_changed_files
:
938 self
._PushFilesImpl
(host_device_tuples
, all_changed_files
)
940 def _GetChangedAndStaleFiles(self
, host_path
, device_path
):
941 """Get files to push and delete
944 host_path: an absolute path of a file or directory on the host
945 device_path: an absolute path of a file or directory on the device
949 1st element: a list of (host_files_path, device_files_path) tuples to push
950 2nd element: a list of stale files under device_path
952 real_host_path
= os
.path
.realpath(host_path
)
954 real_device_path
= self
.RunShellCommand(
955 ['realpath', device_path
], single_line
=True, check_return
=True)
956 except device_errors
.CommandFailedError
:
957 real_device_path
= None
958 if not real_device_path
:
959 return ([(host_path
, device_path
)], [])
962 host_checksums
= md5sum
.CalculateHostMd5Sums([real_host_path
])
963 device_checksums
= md5sum
.CalculateDeviceMd5Sums(
964 [real_device_path
], self
)
965 except EnvironmentError as e
:
966 logging
.warning('Error calculating md5: %s', e
)
967 return ([(host_path
, device_path
)], [])
969 if os
.path
.isfile(host_path
):
970 host_checksum
= host_checksums
.get(real_host_path
)
971 device_checksum
= device_checksums
.get(real_device_path
)
972 if host_checksum
!= device_checksum
:
973 return ([(host_path
, device_path
)], [])
978 for host_abs_path
, host_checksum
in host_checksums
.iteritems():
979 device_abs_path
= '%s/%s' % (
980 real_device_path
, os
.path
.relpath(host_abs_path
, real_host_path
))
981 device_checksum
= device_checksums
.pop(device_abs_path
, None)
982 if device_checksum
!= host_checksum
:
983 to_push
.append((host_abs_path
, device_abs_path
))
984 to_delete
= device_checksums
.keys()
985 return (to_push
, to_delete
)
987 def _PushFilesImpl(self
, host_device_tuples
, files
):
988 size
= sum(host_utils
.GetRecursiveDiskUsage(h
) for h
, _
in files
)
989 file_count
= len(files
)
990 dir_size
= sum(host_utils
.GetRecursiveDiskUsage(h
)
991 for h
, _
in host_device_tuples
)
993 for h
, _
in host_device_tuples
:
995 dir_file_count
+= sum(len(f
) for _r
, _d
, f
in os
.walk(h
))
999 push_duration
= self
._ApproximateDuration
(
1000 file_count
, file_count
, size
, False)
1001 dir_push_duration
= self
._ApproximateDuration
(
1002 len(host_device_tuples
), dir_file_count
, dir_size
, False)
1003 zip_duration
= self
._ApproximateDuration
(1, 1, size
, True)
1005 self
._InstallCommands
()
1007 if dir_push_duration
< push_duration
and (
1008 dir_push_duration
< zip_duration
or not self
._commands
_installed
):
1009 self
._PushChangedFilesIndividually
(host_device_tuples
)
1010 elif push_duration
< zip_duration
or not self
._commands
_installed
:
1011 self
._PushChangedFilesIndividually
(files
)
1013 self
._PushChangedFilesZipped
(files
)
1014 self
.RunShellCommand(
1015 ['chmod', '-R', '777'] + [d
for _
, d
in host_device_tuples
],
1016 as_root
=True, check_return
=True)
1018 def _InstallCommands(self
):
1019 if self
._commands
_installed
is None:
1021 if not install_commands
.Installed(self
):
1022 install_commands
.InstallCommands(self
)
1023 self
._commands
_installed
= True
1024 except Exception as e
:
1025 logging
.warning('unzip not available: %s' % str(e
))
1026 self
._commands
_installed
= False
1029 def _ApproximateDuration(adb_calls
, file_count
, byte_count
, is_zipping
):
1030 # We approximate the time to push a set of files to a device as:
1031 # t = c1 * a + c2 * f + c3 + b / c4 + b / (c5 * c6), where
1032 # t: total time (sec)
1033 # c1: adb call time delay (sec)
1034 # a: number of times adb is called (unitless)
1035 # c2: push time delay (sec)
1036 # f: number of files pushed via adb (unitless)
1037 # c3: zip time delay (sec)
1038 # c4: zip rate (bytes/sec)
1039 # b: total number of bytes (bytes)
1040 # c5: transfer rate (bytes/sec)
1041 # c6: compression ratio (unitless)
1043 # All of these are approximations.
1044 ADB_CALL_PENALTY
= 0.1 # seconds
1045 ADB_PUSH_PENALTY
= 0.01 # seconds
1046 ZIP_PENALTY
= 2.0 # seconds
1047 ZIP_RATE
= 10000000.0 # bytes / second
1048 TRANSFER_RATE
= 2000000.0 # bytes / second
1049 COMPRESSION_RATIO
= 2.0 # unitless
1051 adb_call_time
= ADB_CALL_PENALTY
* adb_calls
1052 adb_push_setup_time
= ADB_PUSH_PENALTY
* file_count
1054 zip_time
= ZIP_PENALTY
+ byte_count
/ ZIP_RATE
1055 transfer_time
= byte_count
/ (TRANSFER_RATE
* COMPRESSION_RATIO
)
1058 transfer_time
= byte_count
/ TRANSFER_RATE
1059 return adb_call_time
+ adb_push_setup_time
+ zip_time
+ transfer_time
1061 def _PushChangedFilesIndividually(self
, files
):
1065 def _PushChangedFilesZipped(self
, files
):
1069 with tempfile
.NamedTemporaryFile(suffix
='.zip') as zip_file
:
1070 zip_proc
= multiprocessing
.Process(
1071 target
=DeviceUtils
._CreateDeviceZip
,
1072 args
=(zip_file
.name
, files
))
1076 zip_on_device
= '%s/tmp.zip' % self
.GetExternalStoragePath()
1078 self
.adb
.Push(zip_file
.name
, zip_on_device
)
1079 self
.RunShellCommand(
1080 ['unzip', zip_on_device
],
1082 env
={'PATH': '%s:$PATH' % install_commands
.BIN_DIR
},
1085 if zip_proc
.is_alive():
1086 zip_proc
.terminate()
1088 self
.RunShellCommand(['rm', zip_on_device
], check_return
=True)
1091 def _CreateDeviceZip(zip_path
, host_device_tuples
):
1092 with zipfile
.ZipFile(zip_path
, 'w') as zip_file
:
1093 for host_path
, device_path
in host_device_tuples
:
1094 zip_utils
.WriteToZipFile(zip_file
, host_path
, device_path
)
1096 @decorators.WithTimeoutAndRetriesFromInstance()
1097 def FileExists(self
, device_path
, timeout
=None, retries
=None):
1098 """Checks whether the given file exists on the device.
1101 device_path: A string containing the absolute path to the file on the
1103 timeout: timeout in seconds
1104 retries: number of retries
1107 True if the file exists on the device, False otherwise.
1110 CommandTimeoutError on timeout.
1111 DeviceUnreachableError on missing device.
1114 self
.RunShellCommand(['test', '-e', device_path
], check_return
=True)
1116 except device_errors
.AdbCommandFailedError
:
1119 @decorators.WithTimeoutAndRetriesFromInstance()
1120 def PullFile(self
, device_path
, host_path
, timeout
=None, retries
=None):
1121 """Pull a file from the device.
1124 device_path: A string containing the absolute path of the file to pull
1126 host_path: A string containing the absolute path of the destination on
1128 timeout: timeout in seconds
1129 retries: number of retries
1132 CommandFailedError on failure.
1133 CommandTimeoutError on timeout.
1135 # Create the base dir if it doesn't exist already
1136 dirname
= os
.path
.dirname(host_path
)
1137 if dirname
and not os
.path
.exists(dirname
):
1138 os
.makedirs(dirname
)
1139 self
.adb
.Pull(device_path
, host_path
)
1141 def _ReadFileWithPull(self
, device_path
):
1143 d
= tempfile
.mkdtemp()
1144 host_temp_path
= os
.path
.join(d
, 'tmp_ReadFileWithPull')
1145 self
.adb
.Pull(device_path
, host_temp_path
)
1146 with
open(host_temp_path
, 'r') as host_temp
:
1147 return host_temp
.read()
1149 if os
.path
.exists(d
):
1152 _LS_RE
= re
.compile(
1153 r
'(?P<perms>\S+) +(?P<owner>\S+) +(?P<group>\S+) +(?:(?P<size>\d+) +)?'
1154 + r
'(?P<date>\S+) +(?P<time>\S+) +(?P<name>.+)$')
1156 @decorators.WithTimeoutAndRetriesFromInstance()
1157 def ReadFile(self
, device_path
, as_root
=False, force_pull
=False,
1158 timeout
=None, retries
=None):
1159 """Reads the contents of a file from the device.
1162 device_path: A string containing the absolute path of the file to read
1164 as_root: A boolean indicating whether the read should be executed with
1166 force_pull: A boolean indicating whether to force the operation to be
1167 performed by pulling a file from the device. The default is, when the
1168 contents are short, to retrieve the contents using cat instead.
1169 timeout: timeout in seconds
1170 retries: number of retries
1173 The contents of |device_path| as a string. Contents are intepreted using
1174 universal newlines, so the caller will see them encoded as '\n'. Also,
1175 all lines will be terminated.
1178 AdbCommandFailedError if the file can't be read.
1179 CommandTimeoutError on timeout.
1180 DeviceUnreachableError on missing device.
1183 # TODO(jbudorick): Implement a generic version of Stat() that handles
1184 # as_root=True, then switch this implementation to use that.
1185 ls_out
= self
.RunShellCommand(['ls', '-l', device_path
], as_root
=as_root
,
1188 m
= self
._LS
_RE
.match(line
)
1189 if m
and m
.group('name') == posixpath
.basename(device_path
):
1190 return int(m
.group('size'))
1191 logging
.warning('Could not determine size of %s.', device_path
)
1195 and 0 < get_size(device_path
) <= self
._MAX
_ADB
_OUTPUT
_LENGTH
):
1196 return _JoinLines(self
.RunShellCommand(
1197 ['cat', device_path
], as_root
=as_root
, check_return
=True))
1198 elif as_root
and self
.NeedsSU():
1199 with device_temp_file
.DeviceTempFile(self
.adb
) as device_temp
:
1200 self
.RunShellCommand(['cp', device_path
, device_temp
.name
],
1201 as_root
=True, check_return
=True)
1202 return self
._ReadFileWithPull
(device_temp
.name
)
1204 return self
._ReadFileWithPull
(device_path
)
1206 def _WriteFileWithPush(self
, device_path
, contents
):
1207 with tempfile
.NamedTemporaryFile() as host_temp
:
1208 host_temp
.write(contents
)
1210 self
.adb
.Push(host_temp
.name
, device_path
)
1212 @decorators.WithTimeoutAndRetriesFromInstance()
1213 def WriteFile(self
, device_path
, contents
, as_root
=False, force_push
=False,
1214 timeout
=None, retries
=None):
1215 """Writes |contents| to a file on the device.
1218 device_path: A string containing the absolute path to the file to write
1220 contents: A string containing the data to write to the device.
1221 as_root: A boolean indicating whether the write should be executed with
1222 root privileges (if available).
1223 force_push: A boolean indicating whether to force the operation to be
1224 performed by pushing a file to the device. The default is, when the
1225 contents are short, to pass the contents using a shell script instead.
1226 timeout: timeout in seconds
1227 retries: number of retries
1230 CommandFailedError if the file could not be written on the device.
1231 CommandTimeoutError on timeout.
1232 DeviceUnreachableError on missing device.
1234 if not force_push
and len(contents
) < self
._MAX
_ADB
_COMMAND
_LENGTH
:
1235 # If the contents are small, for efficieny we write the contents with
1236 # a shell command rather than pushing a file.
1237 cmd
= 'echo -n %s > %s' % (cmd_helper
.SingleQuote(contents
),
1238 cmd_helper
.SingleQuote(device_path
))
1239 self
.RunShellCommand(cmd
, as_root
=as_root
, check_return
=True)
1240 elif as_root
and self
.NeedsSU():
1241 # Adb does not allow to "push with su", so we first push to a temp file
1242 # on a safe location, and then copy it to the desired location with su.
1243 with device_temp_file
.DeviceTempFile(self
.adb
) as device_temp
:
1244 self
._WriteFileWithPush
(device_temp
.name
, contents
)
1245 # Here we need 'cp' rather than 'mv' because the temp and
1246 # destination files might be on different file systems (e.g.
1247 # on internal storage and an external sd card).
1248 self
.RunShellCommand(['cp', device_temp
.name
, device_path
],
1249 as_root
=True, check_return
=True)
1251 # If root is not needed, we can push directly to the desired location.
1252 self
._WriteFileWithPush
(device_path
, contents
)
1254 @decorators.WithTimeoutAndRetriesFromInstance()
1255 def Ls(self
, device_path
, timeout
=None, retries
=None):
1256 """Lists the contents of a directory on the device.
1259 device_path: A string containing the path of the directory on the device
1261 timeout: timeout in seconds
1262 retries: number of retries
1265 A list of pairs (filename, stat) for each file found in the directory,
1266 where the stat object has the properties: st_mode, st_size, and st_time.
1269 AdbCommandFailedError if |device_path| does not specify a valid and
1270 accessible directory in the device.
1271 CommandTimeoutError on timeout.
1272 DeviceUnreachableError on missing device.
1274 return self
.adb
.Ls(device_path
)
1276 @decorators.WithTimeoutAndRetriesFromInstance()
1277 def Stat(self
, device_path
, timeout
=None, retries
=None):
1278 """Get the stat attributes of a file or directory on the device.
1281 device_path: A string containing the path of from which to get attributes
1283 timeout: timeout in seconds
1284 retries: number of retries
1287 A stat object with the properties: st_mode, st_size, and st_time
1290 CommandFailedError if device_path cannot be found on the device.
1291 CommandTimeoutError on timeout.
1292 DeviceUnreachableError on missing device.
1294 dirname
, target
= device_path
.rsplit('/', 1)
1295 for filename
, stat
in self
.adb
.Ls(dirname
):
1296 if filename
== target
:
1298 raise device_errors
.CommandFailedError(
1299 'Cannot find file or directory: %r' % device_path
, str(self
))
1301 @decorators.WithTimeoutAndRetriesFromInstance()
1302 def SetJavaAsserts(self
, enabled
, timeout
=None, retries
=None):
1303 """Enables or disables Java asserts.
1306 enabled: A boolean indicating whether Java asserts should be enabled
1308 timeout: timeout in seconds
1309 retries: number of retries
1312 True if the device-side property changed and a restart is required as a
1313 result, False otherwise.
1316 CommandTimeoutError on timeout.
1318 def find_property(lines
, property_name
):
1319 for index
, line
in enumerate(lines
):
1320 if line
.strip() == '':
1322 key
, value
= (s
.strip() for s
in line
.split('=', 1))
1323 if key
== property_name
:
1327 new_value
= 'all' if enabled
else ''
1329 # First ensure the desired property is persisted.
1331 properties
= self
.ReadFile(
1332 constants
.DEVICE_LOCAL_PROPERTIES_PATH
).splitlines()
1333 except device_errors
.CommandFailedError
:
1335 index
, value
= find_property(properties
, self
.JAVA_ASSERT_PROPERTY
)
1336 if new_value
!= value
:
1338 new_line
= '%s=%s' % (self
.JAVA_ASSERT_PROPERTY
, new_value
)
1340 properties
.append(new_line
)
1342 properties
[index
] = new_line
1344 assert index
is not None # since new_value == '' and new_value != value
1345 properties
.pop(index
)
1346 self
.WriteFile(constants
.DEVICE_LOCAL_PROPERTIES_PATH
,
1347 _JoinLines(properties
))
1349 # Next, check the current runtime value is what we need, and
1350 # if not, set it and report that a reboot is required.
1351 value
= self
.GetProp(self
.JAVA_ASSERT_PROPERTY
)
1352 if new_value
!= value
:
1353 self
.SetProp(self
.JAVA_ASSERT_PROPERTY
, new_value
)
1360 """Returns the language setting on the device."""
1361 return self
.GetProp('persist.sys.language', cache
=False)
1365 """Returns the country setting on the device."""
1366 return self
.GetProp('persist.sys.country', cache
=False)
1369 def screen_density(self
):
1370 """Returns the screen density of the device."""
1378 dpi
= int(self
.GetProp('ro.sf.lcd_density', cache
=True))
1379 return DPI_TO_DENSITY
.get(dpi
, 'tvdpi')
1382 def build_description(self
):
1383 """Returns the build description of the system.
1386 nakasi-user 4.4.4 KTU84P 1227136 release-keys
1388 return self
.GetProp('ro.build.description', cache
=True)
1391 def build_fingerprint(self
):
1392 """Returns the build fingerprint of the system.
1395 google/nakasi/grouper:4.4.4/KTU84P/1227136:user/release-keys
1397 return self
.GetProp('ro.build.fingerprint', cache
=True)
1401 """Returns the build ID of the system (e.g. 'KTU84P')."""
1402 return self
.GetProp('ro.build.id', cache
=True)
1405 def build_product(self
):
1406 """Returns the build product of the system (e.g. 'grouper')."""
1407 return self
.GetProp('ro.build.product', cache
=True)
1410 def build_type(self
):
1411 """Returns the build type of the system (e.g. 'user')."""
1412 return self
.GetProp('ro.build.type', cache
=True)
1415 def build_version_sdk(self
):
1416 """Returns the build version sdk of the system as a number (e.g. 19).
1418 For version code numbers see:
1419 http://developer.android.com/reference/android/os/Build.VERSION_CODES.html
1421 For named constants see:
1422 pylib.constants.ANDROID_SDK_VERSION_CODES
1425 CommandFailedError if the build version sdk is not a number.
1427 value
= self
.GetProp('ro.build.version.sdk', cache
=True)
1431 raise device_errors
.CommandFailedError(
1432 'Invalid build version sdk: %r' % value
)
1435 def product_cpu_abi(self
):
1436 """Returns the product cpu abi of the device (e.g. 'armeabi-v7a')."""
1437 return self
.GetProp('ro.product.cpu.abi', cache
=True)
1440 def product_model(self
):
1441 """Returns the name of the product model (e.g. 'Nexus 7')."""
1442 return self
.GetProp('ro.product.model', cache
=True)
1445 def product_name(self
):
1446 """Returns the product name of the device (e.g. 'nakasi')."""
1447 return self
.GetProp('ro.product.name', cache
=True)
1449 def GetProp(self
, property_name
, cache
=False, timeout
=DEFAULT
,
1451 """Gets a property from the device.
1454 property_name: A string containing the name of the property to get from
1456 cache: A boolean indicating whether to cache the value of this property.
1457 timeout: timeout in seconds
1458 retries: number of retries
1461 The value of the device's |property_name| property.
1464 CommandTimeoutError on timeout.
1466 assert isinstance(property_name
, basestring
), (
1467 "property_name is not a string: %r" % property_name
)
1469 cache_key
= '_prop:' + property_name
1470 if cache
and cache_key
in self
._cache
:
1471 return self
._cache
[cache_key
]
1473 # timeout and retries are handled down at run shell, because we don't
1474 # want to apply them in the other branch when reading from the cache
1475 value
= self
.RunShellCommand(
1476 ['getprop', property_name
], single_line
=True, check_return
=True,
1477 timeout
=self
._default
_timeout
if timeout
is DEFAULT
else timeout
,
1478 retries
=self
._default
_retries
if retries
is DEFAULT
else retries
)
1479 if cache
or cache_key
in self
._cache
:
1480 self
._cache
[cache_key
] = value
1483 @decorators.WithTimeoutAndRetriesFromInstance()
1484 def SetProp(self
, property_name
, value
, check
=False, timeout
=None,
1486 """Sets a property on the device.
1489 property_name: A string containing the name of the property to set on
1491 value: A string containing the value to set to the property on the
1493 check: A boolean indicating whether to check that the property was
1494 successfully set on the device.
1495 timeout: timeout in seconds
1496 retries: number of retries
1499 CommandFailedError if check is true and the property was not correctly
1500 set on the device (e.g. because it is not rooted).
1501 CommandTimeoutError on timeout.
1503 assert isinstance(property_name
, basestring
), (
1504 "property_name is not a string: %r" % property_name
)
1505 assert isinstance(value
, basestring
), "value is not a string: %r" % value
1507 self
.RunShellCommand(['setprop', property_name
, value
], check_return
=True)
1508 if property_name
in self
._cache
:
1509 del self
._cache
[property_name
]
1510 # TODO(perezju) remove the option and make the check mandatory, but using a
1511 # single shell script to both set- and getprop.
1512 if check
and value
!= self
.GetProp(property_name
):
1513 raise device_errors
.CommandFailedError(
1514 'Unable to set property %r on the device to %r'
1515 % (property_name
, value
), str(self
))
1517 @decorators.WithTimeoutAndRetriesFromInstance()
1518 def GetABI(self
, timeout
=None, retries
=None):
1519 """Gets the device main ABI.
1522 timeout: timeout in seconds
1523 retries: number of retries
1526 The device's main ABI name.
1529 CommandTimeoutError on timeout.
1531 return self
.GetProp('ro.product.cpu.abi')
1533 @decorators.WithTimeoutAndRetriesFromInstance()
1534 def GetPids(self
, process_name
, timeout
=None, retries
=None):
1535 """Returns the PIDs of processes with the given name.
1537 Note that the |process_name| is often the package name.
1540 process_name: A string containing the process name to get the PIDs for.
1541 timeout: timeout in seconds
1542 retries: number of retries
1545 A dict mapping process name to PID for each process that contained the
1546 provided |process_name|.
1549 CommandTimeoutError on timeout.
1550 DeviceUnreachableError on missing device.
1554 ps_output
= self
._RunPipedShellCommand
(
1555 'ps | grep -F %s' % cmd_helper
.SingleQuote(process_name
))
1556 except device_errors
.AdbShellCommandFailedError
as e
:
1557 if e
.status
and isinstance(e
.status
, list) and not e
.status
[0]:
1558 # If ps succeeded but grep failed, there were no processes with the
1564 for line
in ps_output
:
1566 ps_data
= line
.split()
1567 if process_name
in ps_data
[-1]:
1568 procs_pids
[ps_data
[-1]] = ps_data
[1]
1573 @decorators.WithTimeoutAndRetriesFromInstance()
1574 def TakeScreenshot(self
, host_path
=None, timeout
=None, retries
=None):
1575 """Takes a screenshot of the device.
1578 host_path: A string containing the path on the host to save the
1579 screenshot to. If None, a file name in the current
1580 directory will be generated.
1581 timeout: timeout in seconds
1582 retries: number of retries
1585 The name of the file on the host to which the screenshot was saved.
1588 CommandFailedError on failure.
1589 CommandTimeoutError on timeout.
1590 DeviceUnreachableError on missing device.
1593 host_path
= os
.path
.abspath('screenshot-%s.png' % _GetTimeStamp())
1594 with device_temp_file
.DeviceTempFile(self
.adb
, suffix
='.png') as device_tmp
:
1595 self
.RunShellCommand(['/system/bin/screencap', '-p', device_tmp
.name
],
1597 self
.PullFile(device_tmp
.name
, host_path
)
1600 @decorators.WithTimeoutAndRetriesFromInstance()
1601 def GetMemoryUsageForPid(self
, pid
, timeout
=None, retries
=None):
1602 """Gets the memory usage for the given PID.
1605 pid: PID of the process.
1606 timeout: timeout in seconds
1607 retries: number of retries
1610 A dict containing memory usage statistics for the PID. May include:
1611 Size, Rss, Pss, Shared_Clean, Shared_Dirty, Private_Clean,
1612 Private_Dirty, VmHWM
1615 CommandTimeoutError on timeout.
1617 result
= collections
.defaultdict(int)
1620 result
.update(self
._GetMemoryUsageForPidFromSmaps
(pid
))
1621 except device_errors
.CommandFailedError
:
1622 logging
.exception('Error getting memory usage from smaps')
1625 result
.update(self
._GetMemoryUsageForPidFromStatus
(pid
))
1626 except device_errors
.CommandFailedError
:
1627 logging
.exception('Error getting memory usage from status')
1631 def _GetMemoryUsageForPidFromSmaps(self
, pid
):
1633 'Size', 'Rss', 'Pss', 'Shared_Clean', 'Shared_Dirty', 'Private_Clean',
1636 showmap_out
= self
._RunPipedShellCommand
(
1637 'showmap %d | grep TOTAL' % int(pid
), as_root
=True)
1639 split_totals
= showmap_out
[-1].split()
1640 if (not split_totals
1641 or len(split_totals
) != 9
1642 or split_totals
[-1] != 'TOTAL'):
1643 raise device_errors
.CommandFailedError(
1644 'Invalid output from showmap: %s' % '\n'.join(showmap_out
))
1646 return dict(itertools
.izip(SMAPS_COLUMNS
, (int(n
) for n
in split_totals
)))
1648 def _GetMemoryUsageForPidFromStatus(self
, pid
):
1649 for line
in self
.ReadFile(
1650 '/proc/%s/status' % str(pid
), as_root
=True).splitlines():
1651 if line
.startswith('VmHWM:'):
1652 return {'VmHWM': int(line
.split()[1])}
1654 raise device_errors
.CommandFailedError(
1655 'Could not find memory peak value for pid %s', str(pid
))
1657 @decorators.WithTimeoutAndRetriesFromInstance()
1658 def GetLogcatMonitor(self
, timeout
=None, retries
=None, *args
, **kwargs
):
1659 """Returns a new LogcatMonitor associated with this device.
1661 Parameters passed to this function are passed directly to
1662 |logcat_monitor.LogcatMonitor| and are documented there.
1665 timeout: timeout in seconds
1666 retries: number of retries
1668 return logcat_monitor
.LogcatMonitor(self
.adb
, *args
, **kwargs
)
1670 def GetClientCache(self
, client_name
):
1671 """Returns client cache."""
1672 if client_name
not in self
._client
_caches
:
1673 self
._client
_caches
[client_name
] = {}
1674 return self
._client
_caches
[client_name
]
1676 def _ClearCache(self
):
1677 """Clears all caches."""
1678 for client
in self
._client
_caches
:
1679 self
._client
_caches
[client
].clear()
1683 def parallel(cls
, devices
=None, async=False):
1684 """Creates a Parallelizer to operate over the provided list of devices.
1686 If |devices| is either |None| or an empty list, the Parallelizer will
1687 operate over all attached devices that have not been blacklisted.
1690 devices: A list of either DeviceUtils instances or objects from
1691 from which DeviceUtils instances can be constructed. If None,
1692 all attached devices will be used.
1693 async: If true, returns a Parallelizer that runs operations
1697 A Parallelizer operating over |devices|.
1700 devices
= cls
.HealthyDevices()
1702 raise device_errors
.NoDevicesError()
1704 devices
= [d
if isinstance(d
, cls
) else cls(d
) for d
in devices
]
1706 return parallelizer
.Parallelizer(devices
)
1708 return parallelizer
.SyncParallelizer(devices
)
1711 def HealthyDevices(cls
):
1712 blacklist
= device_blacklist
.ReadBlacklist()
1713 def blacklisted(adb
):
1714 if adb
.GetDeviceSerial() in blacklist
:
1715 logging
.warning('Device %s is blacklisted.', adb
.GetDeviceSerial())
1719 return [cls(adb
) for adb
in adb_wrapper
.AdbWrapper
.Devices()
1720 if not blacklisted(adb
)]