forked from aosp-mirror/platform_development
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
4 changed files
with
286 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
This library provides access to the fastboot utility. | ||
For fastboot bootloader tests, see platform/system/extra/tests/bootloader |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# | ||
# 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. | ||
# | ||
from __future__ import absolute_import | ||
from .device import * # pylint: disable=wildcard-import |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,235 @@ | ||
# | ||
# 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. | ||
# | ||
"""Provides functionality to interact with a device via `fastboot`.""" | ||
|
||
import os | ||
import re | ||
import subprocess | ||
|
||
|
||
class FastbootError(Exception): | ||
"""Something went wrong interacting with fastboot.""" | ||
|
||
|
||
class FastbootDevice(object): | ||
"""Class to interact with a fastboot device.""" | ||
|
||
# Prefix for INFO-type messages when printed by fastboot. If we want | ||
# to parse the output from an INFO message we need to strip this off. | ||
INFO_PREFIX = '(bootloader) ' | ||
|
||
def __init__(self, path='fastboot'): | ||
"""Initialization. | ||
Args: | ||
path: path to the fastboot executable to test with. | ||
Raises: | ||
FastbootError: Failed to find a device in fastboot mode. | ||
""" | ||
self.path = path | ||
|
||
# Make sure the fastboot executable is available. | ||
try: | ||
_subprocess_check_output([self.path, '--version']) | ||
except OSError: | ||
raise FastbootError('Could not execute `{}`'.format(self.path)) | ||
|
||
# Make sure exactly 1 fastboot device is available if <specific device> | ||
# was not given as an argument. Do not try to find an adb device and | ||
# put it in fastboot mode, it would be too easy to accidentally | ||
# download to the wrong device. | ||
if not self._check_single_device(): | ||
raise FastbootError('Requires exactly 1 device in fastboot mode') | ||
|
||
def _check_single_device(self): | ||
"""Returns True if there is exactly one fastboot device attached. | ||
When ANDROID_SERIAL is set it checks that the device is available. | ||
""" | ||
|
||
if 'ANDROID_SERIAL' in os.environ: | ||
try: | ||
self.getvar('product') | ||
return True | ||
except subprocess.CalledProcessError: | ||
return False | ||
devices = _subprocess_check_output([self.path, 'devices']).splitlines() | ||
return len(devices) == 1 and devices[0].split()[1] == 'fastboot' | ||
|
||
def getvar(self, name): | ||
"""Calls `fastboot getvar`. | ||
To query all variables (fastboot getvar all) use getvar_all() | ||
instead. | ||
Args: | ||
name: variable name to access. | ||
Returns: | ||
String value of variable |name| or None if not found. | ||
""" | ||
try: | ||
output = _subprocess_check_output([self.path, 'getvar', name], | ||
stderr=subprocess.STDOUT).splitlines() | ||
except subprocess.CalledProcessError: | ||
return None | ||
# Output format is <name>:<whitespace><value>. | ||
out = 0 | ||
if output[0] == "< waiting for any device >": | ||
out = 1 | ||
result = re.search(r'{}:\s*(.*)'.format(name), output[out]) | ||
if result: | ||
return result.group(1) | ||
else: | ||
return None | ||
|
||
def getvar_all(self): | ||
"""Calls `fastboot getvar all`. | ||
Returns: | ||
A {name, value} dictionary of variables. | ||
""" | ||
output = _subprocess_check_output([self.path, 'getvar', 'all'], | ||
stderr=subprocess.STDOUT).splitlines() | ||
all_vars = {} | ||
for line in output: | ||
result = re.search(r'(.*):\s*(.*)', line) | ||
if result: | ||
var_name = result.group(1) | ||
|
||
# `getvar all` works by sending one INFO message per variable | ||
# so we need to strip out the info prefix string. | ||
if var_name.startswith(self.INFO_PREFIX): | ||
var_name = var_name[len(self.INFO_PREFIX):] | ||
|
||
# In addition to returning all variables the bootloader may | ||
# also think it's supposed to query a return a variable named | ||
# "all", so ignore this line if so. Fastboot also prints a | ||
# summary line that we want to ignore. | ||
if var_name != 'all' and 'total time' not in var_name: | ||
all_vars[var_name] = result.group(2) | ||
return all_vars | ||
|
||
def flashall(self, wipe_user=True, slot=None, skip_secondary=False, quiet=True): | ||
"""Calls `fastboot [-w] flashall`. | ||
Args: | ||
wipe_user: whether to set the -w flag or not. | ||
slot: slot to flash if device supports A/B, otherwise default will be used. | ||
skip_secondary: on A/B devices, flashes only the primary images if true. | ||
quiet: True to hide output, false to send it to stdout. | ||
""" | ||
func = (_subprocess_check_output if quiet else subprocess.check_call) | ||
command = [self.path, 'flashall'] | ||
if slot: | ||
command.extend(['--slot', slot]) | ||
if skip_secondary: | ||
command.append("--skip-secondary") | ||
if wipe_user: | ||
command.append('-w') | ||
func(command, stderr=subprocess.STDOUT) | ||
|
||
def flash(self, partition='cache', img=None, slot=None, quiet=True): | ||
"""Calls `fastboot flash`. | ||
Args: | ||
partition: which partition to flash. | ||
img: path to .img file, otherwise the default will be used. | ||
slot: slot to flash if device supports A/B, otherwise default will be used. | ||
quiet: True to hide output, false to send it to stdout. | ||
""" | ||
func = (_subprocess_check_output if quiet else subprocess.check_call) | ||
command = [self.path, 'flash', partition] | ||
if img: | ||
command.append(img) | ||
if slot: | ||
command.extend(['--slot', slot]) | ||
if skip_secondary: | ||
command.append("--skip-secondary") | ||
func(command, stderr=subprocess.STDOUT) | ||
|
||
def reboot(self, bootloader=False): | ||
"""Calls `fastboot reboot [bootloader]`. | ||
Args: | ||
bootloader: True to reboot back to the bootloader. | ||
""" | ||
command = [self.path, 'reboot'] | ||
if bootloader: | ||
command.append('bootloader') | ||
_subprocess_check_output(command, stderr=subprocess.STDOUT) | ||
|
||
def set_active(self, slot): | ||
"""Calls `fastboot set_active <slot>`. | ||
Args: | ||
slot: The slot to set as the current slot.""" | ||
command = [self.path, 'set_active', slot] | ||
_subprocess_check_output(command, stderr=subprocess.STDOUT) | ||
|
||
# If necessary, modifies subprocess.check_output() or subprocess.Popen() args | ||
# to run the subprocess via Windows PowerShell to work-around an issue in | ||
# Python 2's subprocess class on Windows where it doesn't support Unicode. | ||
def _get_subprocess_args(args): | ||
# Only do this slow work-around if Unicode is in the cmd line on Windows. | ||
# PowerShell takes 600-700ms to startup on a 2013-2014 machine, which is | ||
# very slow. | ||
if os.name != 'nt' or all(not isinstance(arg, unicode) for arg in args[0]): | ||
return args | ||
|
||
def escape_arg(arg): | ||
# Escape for the parsing that the C Runtime does in Windows apps. In | ||
# particular, this will take care of double-quotes. | ||
arg = subprocess.list2cmdline([arg]) | ||
# Escape single-quote with another single-quote because we're about | ||
# to... | ||
arg = arg.replace(u"'", u"''") | ||
# ...put the arg in a single-quoted string for PowerShell to parse. | ||
arg = u"'" + arg + u"'" | ||
return arg | ||
|
||
# Escape command line args. | ||
argv = map(escape_arg, args[0]) | ||
# Cause script errors (such as adb not found) to stop script immediately | ||
# with an error. | ||
ps_code = u'$ErrorActionPreference = "Stop"\r\n' | ||
# Add current directory to the PATH var, to match cmd.exe/CreateProcess() | ||
# behavior. | ||
ps_code += u'$env:Path = ".;" + $env:Path\r\n' | ||
# Precede by &, the PowerShell call operator, and separate args by space. | ||
ps_code += u'& ' + u' '.join(argv) | ||
# Make the PowerShell exit code the exit code of the subprocess. | ||
ps_code += u'\r\nExit $LastExitCode' | ||
# Encode as UTF-16LE (without Byte-Order-Mark) which Windows natively | ||
# understands. | ||
ps_code = ps_code.encode('utf-16le') | ||
|
||
# Encode the PowerShell command as base64 and use the special | ||
# -EncodedCommand option that base64 decodes. Base64 is just plain ASCII, | ||
# so it should have no problem passing through Win32 CreateProcessA() | ||
# (which python erroneously calls instead of CreateProcessW()). | ||
return (['powershell.exe', '-NoProfile', '-NonInteractive', | ||
'-EncodedCommand', base64.b64encode(ps_code)],) + args[1:] | ||
|
||
# Call this instead of subprocess.check_output() to work-around issue in Python | ||
# 2's subprocess class on Windows where it doesn't support Unicode. | ||
def _subprocess_check_output(*args, **kwargs): | ||
try: | ||
return subprocess.check_output(*_get_subprocess_args(args), **kwargs) | ||
except subprocess.CalledProcessError as e: | ||
# Show real command line instead of the powershell.exe command line. | ||
raise subprocess.CalledProcessError(e.returncode, args[0], | ||
output=e.output) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# | ||
# 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. | ||
# | ||
from distutils.core import setup | ||
|
||
|
||
setup( | ||
name='fastboot', | ||
version='0.0.1', | ||
description='A Python interface to the Fastboot utility.', | ||
license='Apache 2.0', | ||
keywords='fastboot android', | ||
package_dir={'fastboot': ''}, | ||
packages=['fastboot'], | ||
classifiers=[ | ||
'Development Status :: 2 - Pre-Alpha', | ||
'Intended Audience :: Developers', | ||
'License :: OSI Approved :: Apache Software License', | ||
] | ||
) |