mozdevice — Interact with remote devices

Mozdevice provides an interface to interact with a remote device such as an Android- or FirefoxOS-based phone connected to a host machine. Currently there are two implementations of the interface: one uses a custom TCP-based protocol to communicate with a server running on the device, another uses Android’s adb utility.

DeviceManager interface

class mozdevice.DeviceManager(logLevel=40)

Represents a connection to a device. Once an implementation of this class is successfully instantiated, you may do things like list/copy files to the device, launch processes on the device, and install or remove applications from the device.

Never instantiate this class directly! Instead, instantiate an implementation of it like DeviceManagerADB or DeviceManagerSUT.

Here’s an example script which lists the files in ‘/mnt/sdcard’ and sees if a process called ‘org.mozilla.fennec’ is running. In this example, we’re instantiating the DeviceManagerADB implementation, but we could just as easily have used DeviceManagerSUT (assuming the device had an agent running speaking the SUT protocol).

import mozdevice

dm = mozdevice.DeviceManagerADB()
print dm.listFiles("/mnt/sdcard")
if dm.processExist("org.mozilla.fennec"):
    print "Fennec is running"

Informational methods

DeviceManager.getInfo(self, directive=None)

Returns a dictionary of information strings about the device.

Parameters:directive

information you want to get. Options are:

  • os - name of the os
  • id - unique id of the device
  • uptime - uptime of the device
  • uptimemillis - uptime of the device in milliseconds (NOT supported on all implementations)
  • systime - system time of the device
  • screen - screen resolution
  • memory - memory stats
  • process - list of running processes (same as ps)
  • disk - total, free, available bytes on disk
  • power - power status (charge, battery temp)
  • temperature - device temperature

If directive is None, will return all available information

DeviceManager.getCurrentTime(self)

Returns device time in milliseconds since the epoch.

DeviceManager.getIP(interfaces=['eth0', 'wlan0'])

Returns the IP of the device, or None if no connection exists.

DeviceManager.saveScreenshot(filename)

Takes a screenshot of what’s being display on the device. Uses “screencap” on newer (Android 3.0+) devices (and some older ones with the functionality backported). This function also works on B2G.

Throws an exception on failure. This will always fail on devices without the screencap utility.

DeviceManager.recordLogcat()

Clears the logcat file making it easier to view specific events.

DeviceManager.getLogcat(filterSpecs=['dalvikvm:I', 'ConnectivityService:S', 'WifiMonitor:S', 'WifiStateTracker:S', 'wpa_supplicant:S', 'NetworkStateTracker:S'], format='time', filterOutRegexps=[])

Returns the contents of the logcat file as a list of strings

File management methods

DeviceManager.pushFile(self, localFilename, remoteFilename, retryLimit=1)

Copies localname from the host to destname on the device.

DeviceManager.pushDir(self, localDirname, remoteDirname, retryLimit=1)

Push local directory from host to remote directory on the device,

DeviceManager.pullFile(self, remoteFilename)

Returns contents of remoteFile using the “pull” command.

Parameters:
  • remoteFilename – Path to file to pull from remote device.
  • offset – Offset in bytes from which to begin reading (optional)
  • length – Number of bytes to read (optional)
DeviceManager.getFile(self, remoteFilename, localFilename)

Copy file from remote device to local file on host.

DeviceManager.getDirectory(self, remoteDirname, localDirname, checkDir=True)

Copy directory structure from device (remoteDirname) to host (localDirname).

DeviceManager.validateFile(self, remoteFilename, localFilename)

Returns True if a file on the remote device has the same md5 hash as a local one.

DeviceManager.mkDir(self, remoteDirname)

Creates a single directory on the device file system.

DeviceManager.mkDirs(self, filename)

Make directory structure on the device.

WARNING: does not create last part of the path. For example, if asked to create /mnt/sdcard/foo/bar/baz, it will only create /mnt/sdcard/foo/bar

DeviceManager.dirExists(self, dirpath)

Returns whether dirpath exists and is a directory on the device file system.

DeviceManager.fileExists(self, filepath)

Return whether filepath exists on the device file system, regardless of file type.

DeviceManager.listFiles(self, rootdir)

Lists files on the device rootdir.

Returns array of filenames, [‘file1’, ‘file2’, ...]

DeviceManager.removeFile(self, filename)

Removes filename from the device.

DeviceManager.removeDir(self, remoteDirname)

Does a recursive delete of directory on the device: rm -Rf remoteDirname.

DeviceManager.chmodDir(self, remoteDirname, mask="777")

Recursively changes file permissions in a directory.

DeviceManager.getDeviceRoot(self)

Gets the device root for the testing area on the device.

For all devices we will use / type slashes and depend on the device-agent to sort those out. The agent will return us the device location where we should store things, we will then create our /tests structure relative to that returned path.

Structure on the device is as follows:

/tests
    /<fennec>|<firefox>  --> approot
    /profile
    /xpcshell
    /reftest
    /mochitest
DeviceManager.getAppRoot(self, packageName=None)

Returns the app root directory.

E.g /tests/fennec or /tests/firefox

DeviceManager.getTestRoot(self, harnessName)

Gets the directory location on the device for a specific test type.

Parameters:harnessName – one of: “xpcshell”, “reftest”, “mochitest”
DeviceManager.getTempDir(self)

Returns a temporary directory we can use on this device, ensuring also that it exists.

Process management methods

DeviceManager.shell(self, cmd, outputfile, env=None, cwd=None, timeout=None, root=False)

Executes shell command on device and returns exit code.

Parameters:
  • cmd – Commandline list to execute
  • outputfile – File to store output
  • env – Environment to pass to exec command
  • cwd – Directory to execute command from
  • timeout – specified in seconds, defaults to ‘default_timeout’
  • root – Specifies whether command requires root privileges
DeviceManager.shellCheckOutput(self, cmd, env=None, cwd=None, timeout=None, root=False)

Executes shell command on device and returns output as a string. Raises if the return code is non-zero.

Parameters:
  • cmd – Commandline list to execute
  • env – Environment to pass to exec command
  • cwd – Directory to execute command from
  • timeout – specified in seconds, defaults to ‘default_timeout’
  • root – Specifies whether command requires root privileges
Raises:

DMError

DeviceManager.getProcessList(self)

Returns array of tuples representing running processes on the device.

Format of tuples is (processId, processName, userId)

DeviceManager.processExist(self, processName)

Returns True if process with name processName is running on device.

DeviceManager.killProcess(self, processName)

Kills the process named processName. If sig is not None, process is killed with the specified signal.

Parameters:
  • processName – path or name of the process to kill
  • sig – signal to pass into the kill command (optional)

System control methods

DeviceManager.reboot(self, ipAddr=None, port=30000)

Reboots the device.

Parameters:
  • wait – block on device to come back up before returning
  • ipAddr – if specified, try to make the device connect to this specific IP address after rebooting (only works with SUT; if None, we try to determine a reasonable address ourselves)

Application management methods

DeviceManager.uninstallAppAndReboot(self, appName, installPath=None)

Uninstalls the named application from device and causes a reboot.

Parameters:
  • appName – the name of the application (e.g org.mozilla.fennec)
  • installPath – the path to where the application was installed (optional)
DeviceManager.installApp(self, appBundlePath, destPath=None)

Installs an application onto the device.

Parameters:
  • appBundlePath – path to the application bundle on the device
  • destPath – destination directory of where application should be installed to (optional)
DeviceManager.uninstallApp(self, appName, installPath=None)

Uninstalls the named application from device and DOES NOT cause a reboot.

Parameters:
  • appName – the name of the application (e.g org.mozilla.fennec)
  • installPath – the path to where the application was installed (optional)
DeviceManager.updateApp(self, appBundlePath, processName=None, destPath=None, ipAddr=None, port=30000)

Updates the application on the device and reboots.

Parameters:
  • appBundlePath – path to the application bundle on the device
  • processName – used to end the process if the applicaiton is currently running (optional)
  • destPath – Destination directory to where the application should be installed (optional)
  • wait – block on device to come back up before returning
  • ipAddr – if specified, try to make the device connect to this specific IP address after rebooting (only works with SUT; if None and wait is True, we try to determine a reasonable address ourselves)

DeviceManagerADB implementation

class mozdevice.DeviceManagerADB(host=None, port=5555, retryLimit=5, packageName='fennec', adbPath='adb', deviceSerial=None, deviceRoot=None, logLevel=40, autoconnect=True, **kwargs)

Implementation of DeviceManager interface that uses the Android “adb” utility to communicate with the device. Normally used to communicate with a device that is directly connected with the host machine over a USB port.

ADB-specific methods

DeviceManagerADB has several methods that are not present in all DeviceManager implementations. Please do not use them in code that is meant to be interoperable.

DeviceManagerADB.forward(local, remote)

Forward socket connections.

Forward specs are one of:
tcp:<port> localabstract:<unix domain socket name> localreserved:<unix domain socket name> localfilesystem:<unix domain socket name> dev:<character device name> jdwp:<process pid> (remote only)
DeviceManagerADB.remount()

Remounts the /system partition on the device read-write.

DeviceManagerADB.devices()

Return a list of connected devices as (serial, status) tuples.

DeviceManagerSUT implementation

class mozdevice.DeviceManagerSUT(host, port=20701, retryLimit=5, deviceRoot=None, logLevel=40, **kwargs)

Implementation of DeviceManager interface that speaks to a device over TCP/IP using the “system under test” protocol. A software agent such as Negatus (http://github.com/mozilla/Negatus) or the Mozilla Android SUTAgent app must be present and listening for connections for this to work.

SUT-specific methods

DeviceManagerSUT has several methods that are only used in specific tests and are not present in all DeviceManager implementations. Please do not use them in code that is meant to be interoperable.

DeviceManagerSUT.unpackFile(filePath, destDir=None)

Unzips a bundle to a location on the device

If destDir is not specified, the bundle is extracted in the same directory

DeviceManagerSUT.adjustResolution(width=1680, height=1050, type='hdmi')

Adjust the screen resolution on the device, REBOOT REQUIRED

NOTE: this only works on a tegra ATM

supported resolutions: 640x480, 800x600, 1024x768, 1152x864, 1200x1024, 1440x900, 1680x1050, 1920x1080

Android extensions

For Android, we provide two variants of the DeviceManager interface with extensions useful for that platform. These classes are called DroidADB and DroidSUT. They inherit all methods from DeviceManagerADB and DeviceManagerSUT. Here is the interface for DroidADB:

DroidADB.launchApplication(appName, activityName, intent, url=None, extras=None, wait=True, failIfRunning=True)

Launches an Android application

Parameters:
  • appName – Name of application (e.g. com.android.chrome)
  • activityName – Name of activity to launch (e.g. .Main)
  • intent – Intent to launch application with
  • url – URL to open
  • extras – Dictionary of extra arguments to launch application with
  • wait – If True, wait for application to start before returning
  • failIfRunning – Raise an exception if instance of application is already running
DroidADB.launchFennec(appName, intent='android.intent.action.VIEW', mozEnv=None, extraArgs=None, url=None, wait=True, failIfRunning=True)

Convenience method to launch Fennec on Android with various debugging arguments

Parameters:
  • appName – Name of fennec application (e.g. org.mozilla.fennec)
  • intent – Intent to launch application with
  • mozEnv – Mozilla specific environment to pass into application
  • extraArgs – Extra arguments to be parsed by fennec
  • url – URL to open
  • wait – If True, wait for application to start before returning
  • failIfRunning – Raise an exception if instance of application is already running
DroidADB.getInstalledApps()

Lists applications installed on this Android device

Returns a list of application names in the form [ ‘org.mozilla.fennec’, ... ]

These methods are also found in the DroidSUT class.