diff options
author | Than McIntosh <thanm@google.com> | 2016-03-31 15:23:55 -0400 |
---|---|---|
committer | Than McIntosh <thanm@google.com> | 2016-04-12 14:25:27 -0400 |
commit | 6ae324144b240b922799c2aae3f0165971dc55cd (patch) | |
tree | e0b2b02ea4fe23344cee6c3dd5c53058f387eda7 | |
parent | a38abd88b11b7b0723cc7d58e3c13f8232cb648b (diff) | |
download | android_development-6ae324144b240b922799c2aae3f0165971dc55cd.tar.gz android_development-6ae324144b240b922799c2aae3f0165971dc55cd.tar.bz2 android_development-6ae324144b240b922799c2aae3f0165971dc55cd.zip |
Script to perform USB reset of Android device.
Given a serial number, applies correct ioctl()
to reset the USB device with that serial number.
Useful to avoid having to unplug/replug after
flashall + wipe of device.
Change-Id: I7402e1e53cabc19c423ef912a5dc7ade8221b08b
-rwxr-xr-x | scripts/usb-reset-by-serial.py | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/scripts/usb-reset-by-serial.py b/scripts/usb-reset-by-serial.py new file mode 100755 index 000000000..beb7e45aa --- /dev/null +++ b/scripts/usb-reset-by-serial.py @@ -0,0 +1,172 @@ +#!/usr/bin/python +# +# Copyright (C) 2016 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Reset a USB device (presumbly android phone) by serial number. + +Given a serial number, inspects connected USB devices and issues USB +reset to the one that matches. Python version written by Than +McIntosh, based on a perl version from Chris Ferris. Intended for use +on linux. + +""" + +import fcntl +import getopt +import locale +import os +import re +import shlex +import subprocess +import sys + +# Serial number of device that we want to reset +flag_serial = None + +# Debugging verbosity level (0 -> no output) +flag_debug = 0 + +USBDEVFS_RESET = ord("U") << (4*2) | 20 + + +def verbose(level, msg): + """Print debug trace output of verbosity level is >= value in 'level'.""" + if level <= flag_debug: + sys.stderr.write(msg + "\n") + + +def increment_verbosity(): + """Increment debug trace level by 1.""" + global flag_debug + flag_debug += 1 + + +def issue_ioctl_to_device(device): + """Issue USB reset ioctl to device.""" + + try: + fd = open(device, "wb") + except IOError as e: + error("unable to open device %s: " + "%s" % (device, e.strerror)) + verbose(1, "issuing USBDEVFS_RESET ioctl() to %s" % device) + fcntl.ioctl(fd, USBDEVFS_RESET, 0) + fd.close() + + +# perform default locale setup if needed +def set_default_lang_locale(): + if "LANG" not in os.environ: + warning("no env setting for LANG -- using default values") + os.environ["LANG"] = "en_US.UTF-8" + os.environ["LANGUAGE"] = "en_US:" + + +def warning(msg): + """Issue a warning to stderr.""" + sys.stderr.write("warning: " + msg + "\n") + + +def error(msg): + """Issue an error to stderr, then exit.""" + sys.stderr.write("error: " + msg + "\n") + exit(1) + + +# invoke command, returning array of lines read from it +def docmdlines(cmd, nf=None): + """Run a command via subprocess, returning output as an array of lines.""" + verbose(2, "+ docmdlines executing: %s" % cmd) + args = shlex.split(cmd) + mypipe = subprocess.Popen(args, stdout=subprocess.PIPE) + encoding = locale.getdefaultlocale()[1] + pout, perr = mypipe.communicate() + if mypipe.returncode != 0: + if perr: + decoded_err = perr.decode(encoding) + warning(decoded_err) + if nf: + return None + error("command failed (rc=%d): cmd was %s" % (mypipe.returncode, args)) + decoded = pout.decode(encoding) + lines = decoded.strip().split("\n") + return lines + + +def perform(): + """Main driver routine.""" + lines = docmdlines("usb-devices") + dmatch = re.compile(r"^\s*T:\s*Bus\s*=\s*(\d+)\s+.*\s+Dev#=\s*(\d+).*$") + smatch = re.compile(r"^\s*S:\s*SerialNumber=(.*)$") + device = None + found = False + for line in lines: + m = dmatch.match(line) + if m: + p1 = int(m.group(1)) + p2 = int(m.group(2)) + device = "/dev/bus/usb/%03d/%03d" % (p1, p2) + verbose(1, "setting device: %s" % device) + continue + m = smatch.match(line) + if m: + ser = m.group(1) + if ser == flag_serial: + verbose(0, "matched serial %s to device " + "%s, invoking reset" % (ser, device)) + issue_ioctl_to_device(device) + found = True + break + if not found: + error("unable to locate device with serial number %s" % flag_serial) + + +def usage(msgarg): + """Print usage and exit.""" + if msgarg: + sys.stderr.write("error: %s\n" % msgarg) + print """\ + usage: %s [options] XXYYZZ + + where XXYYZZ is the serial number of a connected Android device. + + options: + -d increase debug msg verbosity level + + """ % os.path.basename(sys.argv[0]) + sys.exit(1) + + +def parse_args(): + """Command line argument parsing.""" + global flag_serial + + try: + optlist, args = getopt.getopt(sys.argv[1:], "d") + except getopt.GetoptError as err: + # unrecognized option + usage(str(err)) + if not args or len(args) != 1: + usage("supply a single device serial number as argument") + flag_serial = args[0] + + for opt, _ in optlist: + if opt == "-d": + increment_verbosity() + + +set_default_lang_locale() +parse_args() +perform() |