Bug 1145680 - [mozdevice] Add reboot, move, copy, and info methods to adb.py. r=bc

This commit is contained in:
Dave Hunt 2015-10-27 02:30:00 +01:00
parent 4cd1bc150b
commit cf61aea229
6 changed files with 391 additions and 143 deletions

View File

@ -170,30 +170,38 @@ Device Shell methods
Informational methods
+++++++++++++++++++++
.. automethod:: ADBDevice.clear_logcat
.. automethod:: ADBDevice.get_battery_percentage
.. automethod:: ADBDevice.get_info
.. automethod:: ADBDevice.get_logcat
.. automethod:: ADBDevice.get_prop(self, prop, timeout=None)
.. automethod:: ADBDevice.get_state(self, timeout=None)
.. automethod:: ADBDevice.get_prop
.. automethod:: ADBDevice.get_state
System control methods
++++++++++++++++++++++
.. automethod:: ADBDevice.is_device_ready
.. automethod:: ADBDevice.reboot
File management methods
+++++++++++++++++++++++
.. automethod:: ADBDevice.chmod(self, path, recursive=False, mask="777", timeout=None, root=False)
.. automethod:: ADBDevice.exists(self, path, timeout=None, root=False)
.. automethod:: ADBDevice.is_dir(self, path, timeout=None, root=False)
.. automethod:: ADBDevice.is_file(self, path, timeout=None, root=False)
.. automethod:: ADBDevice.list_files(self, path, timeout=None, root=False)
.. automethod:: ADBDevice.mkdir(self, path, parents=False, timeout=None, root=False)
.. automethod:: ADBDevice.push(self, local, remote, timeout=None)
.. automethod:: ADBDevice.rm(self, path, recursive=False, force=False, timeout=None, root=False)
.. automethod:: ADBDevice.rmdir(self, path, timeout=None, root=False)
.. automethod:: ADBDevice.chmod
.. automethod:: ADBDevice.cp
.. automethod:: ADBDevice.exists
.. automethod:: ADBDevice.is_dir
.. automethod:: ADBDevice.is_file
.. automethod:: ADBDevice.list_files
.. automethod:: ADBDevice.mkdir
.. automethod:: ADBDevice.mv
.. automethod:: ADBDevice.push
.. automethod:: ADBDevice.rm
.. automethod:: ADBDevice.rmdir
.. autoattribute:: ADBDevice.test_root
Process management methods
++++++++++++++++++++++++++
.. automethod:: ADBDevice.get_process_list(self, timeout=None)
.. automethod:: ADBDevice.kill(self, pids, sig=None, attempts=3, wait=5, timeout=None, root=False)
.. automethod:: ADBDevice.pkill(self, appname, sig=None, attempts=3, wait=5, timeout=None, root=False)
.. automethod:: ADBDevice.process_exist(self, process_name, timeout=None)
.. automethod:: ADBDevice.get_process_list
.. automethod:: ADBDevice.kill
.. automethod:: ADBDevice.pkill
.. automethod:: ADBDevice.process_exist
ADBAndroid
``````````
@ -201,24 +209,32 @@ ADBAndroid
Informational methods
+++++++++++++++++++++
.. automethod:: ADBAndroid.get_battery_percentage(self, timeout=None)
.. automethod:: ADBAndroid.get_battery_percentage
System control methods
++++++++++++++++++++++
.. automethod:: ADBAndroid.is_device_ready(self, timeout=None)
.. automethod:: ADBAndroid.power_on(self, timeout=None)
.. automethod:: ADBAndroid.reboot(self, timeout=None)
.. automethod:: ADBAndroid.is_device_ready
.. automethod:: ADBAndroid.power_on
Application management methods
++++++++++++++++++++++++++++++
.. automethod:: ADBAndroid.install_app(self, apk_path, timeout=None)
.. automethod:: ADBAndroid.is_app_installed(self, app_name, timeout=None)
.. automethod:: ADBAndroid.launch_application(self, app_name, activity_name, intent, url=None, extras=None, wait=True, fail_if_running=True, timeout=None)
.. automethod:: ADBAndroid.launch_fennec(self, app_name, intent="android.intent.action.VIEW", moz_env=None, extra_args=None, url=None, wait=True, fail_if_running=True, timeout=None)
.. automethod:: ADBAndroid.stop_application(self, app_name, timeout=None, root=False)
.. automethod:: ADBAndroid.uninstall_app(self, app_name, reboot=False, timeout=None)
.. automethod:: ADBAndroid.update_app(self, apk_path, timeout=None)
.. automethod:: ADBAndroid.install_app
.. automethod:: ADBAndroid.is_app_installed
.. automethod:: ADBAndroid.launch_application
.. automethod:: ADBAndroid.launch_fennec
.. automethod:: ADBAndroid.stop_application
.. automethod:: ADBAndroid.uninstall_app
.. automethod:: ADBAndroid.update_app
ADBB2G
``````
.. autoclass:: ADBB2G
Informational methods
+++++++++++++++++++++
.. automethod:: ADBB2G.get_battery_percentage
.. automethod:: ADBB2G.get_info
.. automethod:: ADBB2G.get_memory_total
ADBProcess
``````````

View File

@ -4,6 +4,7 @@
from adb import ADBError, ADBRootError, ADBTimeoutError, ADBProcess, ADBCommand, ADBHost, ADBDevice
from adb_android import ADBAndroid
from adb_b2g import ADBB2G
from devicemanager import DeviceManager, DMError, ZeroconfListener
from devicemanagerADB import DeviceManagerADB
from devicemanagerSUT import DeviceManagerSUT

View File

@ -2,6 +2,7 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
from abc import ABCMeta, abstractmethod
import os
import posixpath
import re
@ -12,9 +13,7 @@ import traceback
class ADBProcess(object):
"""ADBProcess encapsulates the data related to executing the adb process.
"""
"""ADBProcess encapsulates the data related to executing the adb process."""
def __init__(self, args):
#: command argument argument list.
self.args = args
@ -64,7 +63,6 @@ class ADBError(Exception):
device either exited with a non-zero exitcode or when an
unexpected error condition has occurred. Generally, ADBErrors can
be handled and the device can continue to be used.
"""
pass
@ -73,7 +71,6 @@ class ADBRootError(Exception):
root but the device does not support it. This error is fatal since
there is no recovery possible by the script. You must either root
your device or change your scripts to not require running as root.
"""
pass
@ -94,7 +91,6 @@ class ADBTimeoutError(Exception):
* Rebooting the device manually.
* Rebooting the host.
"""
pass
@ -117,7 +113,6 @@ class ADBCommand(object):
adbcommand = ADBCommand()
except NotImplementedError:
print "ADBCommand can not be instantiated."
"""
def __init__(self,
@ -138,7 +133,6 @@ class ADBCommand(object):
:raises: * ADBError
* ADBTimeoutError
"""
if self.__class__ == ADBCommand:
raise NotImplementedError
@ -211,7 +205,6 @@ class ADBCommand(object):
It is the caller's responsibilty to clean up by closing
the stdout and stderr temporary files.
"""
args = [self._adb_path]
if self._adb_host:
@ -263,7 +256,6 @@ class ADBCommand(object):
:raises: * ADBTimeoutError
* ADBError
"""
adb_process = None
try:
@ -306,7 +298,6 @@ class ADBHost(ADBCommand):
adbhost = ADBHost()
adbhost.start_server()
"""
def __init__(self,
adb='adb',
@ -326,7 +317,6 @@ class ADBHost(ADBCommand):
:raises: * ADBError
* ADBTimeoutError
"""
ADBCommand.__init__(self, adb=adb, adb_host=adb_host,
adb_port=adb_port, logger_name=logger_name,
@ -362,7 +352,6 @@ class ADBHost(ADBCommand):
It is the caller's responsibilty to clean up by closing
the stdout and stderr temporary files.
"""
return ADBCommand.command(self, cmds, timeout=timeout)
@ -382,7 +371,6 @@ class ADBHost(ADBCommand):
:raises: * ADBTimeoutError
* ADBError
"""
return ADBCommand.command_output(self, cmds, timeout=timeout)
@ -415,7 +403,6 @@ class ADBHost(ADBCommand):
while true; do
adb -a fork-server server
done
"""
self.command_output(["start-server"], timeout=timeout)
@ -430,7 +417,6 @@ class ADBHost(ADBCommand):
:type timeout: integer or None
:raises: * ADBTimeoutError
* ADBError
"""
self.command_output(["kill-server"], timeout=timeout)
@ -457,7 +443,6 @@ class ADBHost(ADBCommand):
[{'device_serial': 'b313b945', 'state': 'device', 'product': 'd2vzw',
'usb': '1-7', 'device': 'd2vzw', 'model': 'SCH_I535' }]
"""
# b313b945 device usb:1-7 product:d2vzw model:SCH_I535 device:d2vzw
# from Android system/core/adb/transport.c statename()
@ -486,22 +471,12 @@ class ADBHost(ADBCommand):
class ADBDevice(ADBCommand):
"""ADBDevice provides methods which can be used to interact with
the associated Android-based device.
Android specific features such as Application management are not
included but are provided via the ADBAndroid interface.
::
from mozdevice import ADBDevice
adbdevice = ADBDevice()
print adbdevice.list_files("/mnt/sdcard")
if adbdevice.process_exist("org.mozilla.fennec"):
print "Fennec is running"
"""ADBDevice is an abstract base class which provides methods which
can be used to interact with the associated Android or B2G based
device. It must be used via one of the concrete implementations in
:class:`ADBAndroid` or :class:`ADBB2G`.
"""
__metaclass__ = ABCMeta
def __init__(self,
device=None,
@ -547,8 +522,6 @@ class ADBDevice(ADBCommand):
:raises: * ADBError
* ADBTimeoutError
* ValueError
"""
ADBCommand.__init__(self, adb=adb, adb_host=adb_host,
adb_port=adb_port, logger_name=logger_name,
@ -604,6 +577,9 @@ class ADBDevice(ADBCommand):
except ADBError:
self._ls += " -a"
# Do we have cp?
self._have_cp = self.shell_bool("type cp")
self._logger.debug("ADBDevice: %s" % self.__dict__)
def _get_device_serial(self, device):
@ -644,7 +620,6 @@ class ADBDevice(ADBCommand):
def _escape_command_line(cmd):
"""Utility function to return escaped and quoted version of command
line.
"""
quoted_cmd = []
@ -667,7 +642,6 @@ class ADBDevice(ADBCommand):
def _get_exitcode(file_obj):
"""Get the exitcode from the last line of the file_obj for shell
commands.
"""
file_obj.seek(0, os.SEEK_END)
@ -806,7 +780,6 @@ class ADBDevice(ADBCommand):
It is the caller's responsibilty to clean up by closing
the stdout and stderr temporary files.
"""
return ADBCommand.command(self, cmds,
@ -829,7 +802,6 @@ class ADBDevice(ADBCommand):
:raises: * ADBTimeoutError
* ADBError
"""
return ADBCommand.command_output(self, cmds,
device_serial=self._device_serial,
@ -980,7 +952,6 @@ class ADBDevice(ADBCommand):
It is the caller's responsibilty to clean up by closing
the stdout and stderr temporary files.
"""
if root:
ld_library_path='LD_LIBRARY_PATH=/vendor/lib:/system/lib'
@ -1058,7 +1029,6 @@ class ADBDevice(ADBCommand):
:raises: * ADBTimeoutError
* ADBRootError
"""
adb_process = None
try:
@ -1093,7 +1063,6 @@ class ADBDevice(ADBCommand):
:raises: * ADBTimeoutError
* ADBRootError
* ADBError
"""
adb_process = None
try:
@ -1151,7 +1120,6 @@ class ADBDevice(ADBCommand):
"radio", "events", and "main". Defaults to "main".
:raises: * ADBTimeoutError
* ADBError
"""
buffers = self._get_logcat_buffer_args(buffers)
cmds = ["logcat", "-c"] + buffers
@ -1188,7 +1156,6 @@ class ADBDevice(ADBCommand):
:returns: list of lines logcat output.
:raises: * ADBTimeoutError
* ADBError
"""
buffers = self._get_logcat_buffer_args(buffers)
cmds = ["logcat", "-v", format, "-d"] + buffers + filter_specs
@ -1213,7 +1180,6 @@ class ADBDevice(ADBCommand):
:returns: string value of property.
:raises: * ADBTimeoutError
* ADBError
"""
output = self.shell_output('getprop %s' % prop, timeout=timeout)
return output
@ -1231,7 +1197,6 @@ class ADBDevice(ADBCommand):
:returns: string value of adb get-state.
:raises: * ADBTimeoutError
* ADBError
"""
output = self.command_output(["get-state"], timeout=timeout).strip()
return output
@ -1253,7 +1218,6 @@ class ADBDevice(ADBCommand):
be found.
:raises: * ADBTimeoutError
* ADBError
"""
ip_regexp = re.compile(r'(\w+)\s+UP\s+([1-9]\d{0,2}\.\d{1,3}\.\d{1,3}\.\d{1,3})')
data = self.shell_output('netcfg')
@ -1309,7 +1273,6 @@ class ADBDevice(ADBCommand):
:raises: * ADBTimeoutError
* ADBRootError
* ADBError
"""
path = posixpath.normpath(path.strip())
self._logger.debug('chmod: path=%s, recursive=%s, mask=%s, root=%s' %
@ -1356,7 +1319,6 @@ class ADBDevice(ADBCommand):
:returns: boolean - True if path exists.
:raises: * ADBTimeoutError
* ADBRootError
"""
path = posixpath.normpath(path)
return self.shell_bool('ls -a %s' % path, timeout=timeout, root=root)
@ -1378,7 +1340,6 @@ class ADBDevice(ADBCommand):
directory.
:raises: * ADBTimeoutError
* ADBRootError
"""
path = posixpath.normpath(path)
return self.shell_bool('ls -a %s/' % path, timeout=timeout, root=root)
@ -1400,7 +1361,6 @@ class ADBDevice(ADBCommand):
file.
:raises: * ADBTimeoutError
* ADBRootError
"""
path = posixpath.normpath(path)
return (
@ -1424,7 +1384,6 @@ class ADBDevice(ADBCommand):
:returns: list of files/directories contained in the directory.
:raises: * ADBTimeoutError
* ADBRootError
"""
path = posixpath.normpath(path.strip())
data = []
@ -1461,7 +1420,6 @@ class ADBDevice(ADBCommand):
:raises: * ADBTimeoutError
* ADBRootError
* ADBError
"""
path = posixpath.normpath(path)
if parents:
@ -1504,7 +1462,6 @@ class ADBDevice(ADBCommand):
:type timeout: integer or None
:raises: * ADBTimeoutError
* ADBError
"""
self.command_output(["push", os.path.realpath(local), remote],
timeout=timeout)
@ -1525,7 +1482,6 @@ class ADBDevice(ADBCommand):
:type timeout: integer or None
:raises: * ADBTimeoutError
* ADBError
"""
self.command_output(["pull", remote, os.path.realpath(local)],
timeout=timeout)
@ -1551,7 +1507,6 @@ class ADBDevice(ADBCommand):
:raises: * ADBTimeoutError
* ADBRootError
* ADBError
"""
cmd = "rm"
if recursive:
@ -1580,7 +1535,6 @@ class ADBDevice(ADBCommand):
:raises: * ADBTimeoutError
* ADBRootError
* ADBError
"""
self.shell_output("rmdir %s" % path, timeout=timeout, root=root)
if self.is_dir(path, timeout=timeout, root=root):
@ -1603,7 +1557,6 @@ class ADBDevice(ADBCommand):
on the device.
:raises: * ADBTimeoutError
* ADBError
"""
adb_process = None
try:
@ -1668,7 +1621,6 @@ class ADBDevice(ADBCommand):
:raises: * ADBTimeoutError
* ADBRootError
* ADBError
"""
pid_list = [str(pid) for pid in pids]
for attempt in range(attempts):
@ -1719,7 +1671,6 @@ class ADBDevice(ADBCommand):
:raises: * ADBTimeoutError
* ADBRootError
* ADBError
"""
procs = self.get_process_list(timeout=timeout)
# limit the comparion to the first 75 characters due to a
@ -1753,7 +1704,6 @@ class ADBDevice(ADBCommand):
:raises: * ADBTimeoutError
* ADBError
"""
if not isinstance(process_name, basestring):
raise ADBError("Process name %s is not a string" % process_name)
@ -1783,3 +1733,204 @@ class ADBDevice(ADBCommand):
if proc_name == app[:75]:
return True
return False
def cp(self, source, destination, recursive=False, timeout=None,
root=False):
"""Copies a file or directory on the device.
:param source: string containing the path of the source file or
directory.
:param destination: string containing the path of the destination file
or directory.
:param recursive: optional boolean indicating if a recursive copy is to
be performed. Required if the source is a directory. Defaults to
False. Think cp -R source destination.
:param timeout: optional integer specifying the maximum time in
seconds for any spawned adb process to complete before
throwing an ADBTimeoutError.
This timeout is per adb call. The total time spent
may exceed this value. If it is not specified, the value
set in the ADBDevice constructor is used.
:raises: * ADBTimeoutError
* ADBRootError
* ADBError
"""
source = posixpath.normpath(source)
destination = posixpath.normpath(destination)
if self._have_cp:
r = '-R' if recursive else ''
self.shell_output('cp %s %s %s' % (r, source, destination),
timeout=timeout, root=root)
return
# Emulate cp behavior depending on if source and destination
# already exists and whether they are a directory or file.
if not self.exists(source, timeout=timeout, root=root):
raise ADBError("cp: can't stat '%s': No such file or directory" %
source)
if self.is_file(source, timeout=timeout, root=root):
if self.is_dir(destination, timeout=timeout, root=root):
# Copy the source file into the destination directory
destination = posixpath.join(destination,
posixpath.basename(source))
self.shell_output('dd if=%s of=%s' % (source, destination),
timeout=timeout, root=root)
return
if self.is_file(destination, timeout=timeout, root=root):
raise ADBError('cp: %s: Not a directory' % destination)
if not recursive:
raise ADBError("cp: omitting directory '%s'" % source)
if self.is_dir(destination, timeout=timeout, root=root):
# Copy the source directory into the destination directory.
destination_dir = posixpath.join(destination,
posixpath.basename(source))
else:
# Copy the contents of the source directory into the
# destination directory.
destination_dir = destination
try:
# Do not create parent directories since cp does not.
self.mkdir(destination_dir, timeout=timeout, root=root)
except ADBError as e:
if 'File exists' not in e.message:
raise
for i in self.list_files(source, timeout=timeout, root=root):
self.cp(posixpath.join(source, i),
posixpath.join(destination_dir, i),
recursive=recursive,
timeout=timeout, root=root)
def mv(self, source, destination, timeout=None, root=False):
"""Moves a file or directory on the device.
:param source: string containing the path of the source file or
directory.
:param destination: string containing the path of the destination file
or directory.
:param timeout: optional integer specifying the maximum time in
seconds for any spawned adb process to complete before
throwing an ADBTimeoutError.
This timeout is per adb call. The total time spent
may exceed this value. If it is not specified, the value
set in the ADBDevice constructor is used.
:raises: * ADBTimeoutError
* ADBRootError
* ADBError
"""
source = posixpath.normpath(source)
destination = posixpath.normpath(destination)
self.shell_output('mv %s %s' % (source, destination), timeout=timeout,
root=root)
def reboot(self, timeout=None):
"""Reboots the device.
:param timeout: optional integer specifying the maximum time in
seconds for any spawned adb process to complete before
throwing an ADBTimeoutError.
This timeout is per adb call. The total time spent
may exceed this value. If it is not specified, the value
set in the ADB constructor is used.
:raises: * ADBTimeoutError
* ADBError
reboot() reboots the device, issues an adb wait-for-device in order to
wait for the device to complete rebooting, then calls is_device_ready()
to determine if the device has completed booting.
"""
self.command_output(["reboot"], timeout=timeout)
self.command_output(["wait-for-device"], timeout=timeout)
return self.is_device_ready(timeout=timeout)
@abstractmethod
def is_device_ready(self, timeout=None):
"""Abstract class that returns True if the device is ready.
:param timeout: optional integer specifying the maximum time in
seconds for any spawned adb process to complete before
throwing an ADBTimeoutError.
This timeout is per adb call. The total time spent
may exceed this value. If it is not specified, the value
set in the ADB constructor is used.
:raises: * ADBTimeoutError
* ADBError
"""
return
@abstractmethod
def get_battery_percentage(self, timeout=None):
"""Abstract class that returns the battery charge as a percentage.
:param timeout: optional integer specifying the maximum time in
seconds for any spawned adb process to complete before
throwing an ADBTimeoutError.
This timeout is per adb call. The total time spent
may exceed this value. If it is not specified, the value
set in the ADBDevice constructor is used.
:returns: battery charge as a percentage.
:raises: * ADBTimeoutError
* ADBError
"""
return
def get_info(self, directive=None, timeout=None):
"""
Returns a dictionary of information strings about the device.
:param directive: information you want to get. Options are:
- `battery` - battery charge as a percentage
- `disk` - total, free, available bytes on disk
- `id` - unique id of the device
- `os` - name of the os
- `process` - list of running processes (same as ps)
- `systime` - system time of the device
- `uptime` - uptime of the device
If `directive` is `None`, will return all available information
:param timeout: optional integer specifying the maximum time in
seconds for any spawned adb process to complete before
throwing an ADBTimeoutError.
This timeout is per adb call. The total time spent
may exceed this value. If it is not specified, the value
set in the ADB constructor is used.
:raises: * ADBTimeoutError
* ADBError
"""
directives = ['battery', 'disk', 'id', 'os', 'process', 'systime',
'uptime']
if (directive in directives):
directives = [directive]
info = {}
if 'battery' in directives:
info['battery'] = self.get_battery_percentage(timeout=timeout)
if 'disk' in directives:
info['disk'] = self.shell_output('df /data /system /sdcard',
timeout=timeout).splitlines()
if 'id' in directives:
info['id'] = self.command_output(['get-serialno'], timeout=timeout)
if 'os' in directives:
info['os'] = self.shell_output('getprop ro.build.display.id',
timeout=timeout)
if 'process' in directives:
ps = self.shell_output('ps', timeout=timeout)
info['process'] = ps.splitlines()
if 'systime' in directives:
info['systime'] = self.shell_output('date', timeout=timeout)
if 'uptime' in directives:
uptime = self.shell_output('uptime', timeout=timeout)
if uptime:
m = re.match('up time: ((\d+) days, )*(\d{2}):(\d{2}):(\d{2})',
uptime)
if m:
uptime = '%d days %d hours %d minutes %d seconds' % tuple(
[int(g or 0) for g in m.groups()[1:]])
info['uptime'] = uptime
return info

View File

@ -10,8 +10,19 @@ from adb import ADBDevice, ADBError
from distutils.version import StrictVersion
class ADBAndroidMixin(object):
"""Mixin to extend ADB with Android-specific functionality"""
class ADBAndroid(ADBDevice):
"""ADBAndroid implements :class:`ADBDevice` providing Android-specific
functionality.
::
from mozdevice import ADBAndroid
adbdevice = ADBAndroid()
print adbdevice.list_files("/mnt/sdcard")
if adbdevice.process_exist("org.mozilla.fennec"):
print "Fennec is running"
"""
# Informational methods
@ -28,7 +39,6 @@ class ADBAndroidMixin(object):
:returns: battery charge as a percentage.
:raises: * ADBTimeoutError
* ADBError
"""
level = None
scale = None
@ -67,7 +77,6 @@ class ADBAndroidMixin(object):
:type timeout: integer or None
:raises: * ADBTimeoutError
* ADBError
"""
self.command_output(["wait-for-device"], timeout=timeout)
pm_error_string = "Error: Could not access the Package Manager"
@ -120,7 +129,6 @@ class ADBAndroidMixin(object):
:type timeout: integer or None
:raises: * ADBTimeoutError
* ADBError
"""
try:
self.shell_output('svc power stayon true', timeout=timeout)
@ -131,31 +139,6 @@ class ADBAndroidMixin(object):
raise
self._logger.warning('Unable to set power stayon true: %s' % e)
def reboot(self, timeout=None):
"""Reboots the device.
This method uses the Android only package manager to determine
if the device is ready after the reboot.
:param timeout: The maximum time in
seconds for any spawned adb process to complete before
throwing an ADBTimeoutError.
This timeout is per adb call. The total time spent
may exceed this value. If it is not specified, the value
set in the ADB constructor is used.
:type timeout: integer or None
:raises: * ADBTimeoutError
* ADBError
reboot() reboots the device, issues an adb wait-for-device in order to
wait for the device to complete rebooting, then calls is_device_ready()
to determine if the device has completed booting.
"""
self.command_output(["reboot"], timeout=timeout)
self.command_output(["wait-for-device"], timeout=timeout)
return self.is_device_ready(timeout=timeout)
# Application management methods
def install_app(self, apk_path, timeout=None):
@ -171,7 +154,6 @@ class ADBAndroidMixin(object):
:type timeout: integer or None
:raises: * ADBTimeoutError
* ADBError
"""
data = self.command_output(["install", apk_path], timeout=timeout)
if data.find('Success') == -1:
@ -191,7 +173,6 @@ class ADBAndroidMixin(object):
:type timeout: integer or None
:raises: * ADBTimeoutError
* ADBError
"""
pm_error_string = 'Error: Could not access the Package Manager'
data = self.shell_output("pm list package %s" % app_name, timeout=timeout)
@ -226,7 +207,6 @@ class ADBAndroidMixin(object):
:type timeout: integer or None
:raises: * ADBTimeoutError
* ADBError
"""
# If fail_if_running is True, we throw an exception here. Only one
# instance of an application can be running at once on Android,
@ -287,7 +267,6 @@ class ADBAndroidMixin(object):
:type timeout: integer or None
:raises: * ADBTimeoutError
* ADBError
"""
extras = {}
@ -327,7 +306,6 @@ class ADBAndroidMixin(object):
executed as root.
:raises: * ADBTimeoutError
* ADBError
"""
version = self.shell_output("getprop ro.build.version.release",
timeout=timeout, root=root)
@ -367,7 +345,6 @@ class ADBAndroidMixin(object):
:type timeout: integer or None
:raises: * ADBTimeoutError
* ADBError
"""
if self.is_app_installed(app_name, timeout=timeout):
data = self.command_output(["uninstall", app_name], timeout=timeout)
@ -391,27 +368,8 @@ class ADBAndroidMixin(object):
:type timeout: integer or None
:raises: * ADBTimeoutError
* ADBError
"""
output = self.command_output(["install", "-r", apk_path],
timeout=timeout)
self.reboot(timeout=timeout)
return output
class ADBAndroid(ADBDevice, ADBAndroidMixin):
"""ADBAndroid provides all of the methods of :class:`mozdevice.ADB` with
Android specific extensions useful for that platform.
::
from mozdevice import ADBAndroid as ADBDevice
adb = ADBDevice(...)
if adb.is_device_ready():
adb.install_app("/tmp/build.apk")
adb.launch_fennec("org.mozilla.fennec")
"""
pass

View File

@ -0,0 +1,122 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
import traceback
import mozfile
from adb import ADBDevice, ADBError
class ADBB2G(ADBDevice):
"""ADBB2G implements :class:`ADBDevice` providing B2G-specific
functionality.
::
from mozdevice import ADBB2G
adbdevice = ADBB2G()
print adbdevice.list_files("/mnt/sdcard")
if adbdevice.process_exist("b2g"):
print "B2G is running"
"""
def get_battery_percentage(self, timeout=None):
"""Returns the battery charge as a percentage.
:param timeout: optional integer specifying the maximum time in
seconds for any spawned adb process to complete before
throwing an ADBTimeoutError.
This timeout is per adb call. The total time spent
may exceed this value. If it is not specified, the value
set in the ADBDevice constructor is used.
:returns: battery charge as a percentage.
:raises: * ADBTimeoutError
* ADBError
"""
with mozfile.NamedTemporaryFile() as tf:
self.pull('/sys/class/power_supply/battery/capacity', tf.name,
timeout=timeout)
try:
with open(tf.name) as tf2:
return tf2.read().splitlines()[0]
except Exception as e:
raise ADBError(traceback.format_exception_only(
type(e), e)[0].strip())
def get_memory_total(self, timeout=None):
"""Returns the total memory available with units.
:param timeout: optional integer specifying the maximum time in
seconds for any spawned adb process to complete before
throwing an ADBTimeoutError.
This timeout is per adb call. The total time spent
may exceed this value. If it is not specified, the value
set in the ADBDevice constructor is used.
:returns: memory total with units.
:raises: * ADBTimeoutError
* ADBError
"""
meminfo = {}
with mozfile.NamedTemporaryFile() as tf:
self.pull('/proc/meminfo', tf.name, timeout=timeout)
try:
with open(tf.name) as tf2:
for line in tf2.read().splitlines():
key, value = line.split(':')
meminfo[key] = value.strip()
except Exception as e:
raise ADBError(traceback.format_exception_only(
type(e), e)[0].strip())
return meminfo['MemTotal']
def get_info(self, directive=None, timeout=None):
"""
Returns a dictionary of information strings about the device.
:param directive: information you want to get. Options are:
- `battery` - battery charge as a percentage
- `disk` - total, free, available bytes on disk
- `id` - unique id of the device
- `memtotal` - total memory available on the device
- `os` - name of the os
- `process` - list of running processes (same as ps)
- `systime` - system time of the device
- `uptime` - uptime of the device
If `directive` is `None`, will return all available information
:param timeout: optional integer specifying the maximum time in
seconds for any spawned adb process to complete before
throwing an ADBTimeoutError.
This timeout is per adb call. The total time spent
may exceed this value. If it is not specified, the value
set in the ADB constructor is used.
:raises: * ADBTimeoutError
* ADBError
"""
info = super(ADBB2G, self).get_info(directive=directive,
timeout=timeout)
directives = ['memtotal']
if (directive in directives):
directives = [directive]
if 'memtotal' in directives:
info['memtotal'] = self.get_memory_total(timeout=timeout)
return info
def is_device_ready(self, timeout=None):
"""Returns True if the device is ready.
:param timeout: optional integer specifying the maximum time in
seconds for any spawned adb process to complete before
throwing an ADBTimeoutError.
This timeout is per adb call. The total time spent
may exceed this value. If it is not specified, the value
set in the ADB constructor is used.
:raises: * ADBTimeoutError
* ADBError
"""
return self.shell_bool('ls /sbin', timeout=timeout)

View File

@ -192,7 +192,7 @@ class B2GExecutorBrowser(ExecutorBrowser):
import sys, subprocess
self.device = mozdevice.ADBDevice()
self.device = mozdevice.ADBB2G()
self.device.forward("tcp:%s" % self.marionette_port,
"tcp:2828")
self.executor = None