diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..af375ad --- /dev/null +++ b/.flake8 @@ -0,0 +1,2 @@ +[flake8] +ignore = E501,W504 diff --git a/.gitignore b/.gitignore index e92aa58..a3ddfb2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,20 @@ *.pyc +*.DS_Store* + .cache/ -.coverage -adb.egg-info/ +.eggs/ +.idea/ .tox/ +adb.egg-info/ +build/ +dist/ +htmlcov/ + +.coverage /adb.zip /fastboot.zip -.idea/ -*.DS_Store* \ No newline at end of file + +# Documentation +docs/build +docs/html +docs/source/_static/*.dot diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 0000000..df82692 --- /dev/null +++ b/.pylintrc @@ -0,0 +1,582 @@ +[MASTER] + +# A comma-separated list of package or module names from where C extensions may +# be loaded. Extensions are loading into the active Python interpreter and may +# run arbitrary code. +extension-pkg-whitelist= + +# Add files or directories to the blacklist. They should be base names, not +# paths. +ignore=CVS + +# Add files or directories matching the regex patterns to the blacklist. The +# regex matches against base names, not paths. +ignore-patterns= + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +#init-hook= + +# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the +# number of processors available to use. +jobs=1 + +# Control the amount of potential inferred values when inferring a single +# object. This can help the performance when dealing with large functions or +# complex, nested conditions. +limit-inference-results=100 + +# List of plugins (as comma separated values of python modules names) to load, +# usually to register additional checkers. +load-plugins= + +# Pickle collected data for later comparisons. +persistent=yes + +# Specify a configuration file. +#rcfile= + +# When enabled, pylint would attempt to guess common misconfiguration and emit +# user-friendly hints instead of false-positive error messages. +suggestion-mode=yes + +# Allow loading of arbitrary C extensions. Extensions are imported into the +# active Python interpreter and may run arbitrary code. +unsafe-load-any-extension=no + + +[MESSAGES CONTROL] + +# Only show warnings with the listed confidence levels. Leave empty to show +# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED. +confidence= + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifiers separated by comma (,) or put this +# option multiple times (only on the command line, not in the configuration +# file where it should appear only once). You can also use "--disable=all" to +# disable everything first and then reenable specific checks. For example, if +# you want to run only the similarities checker, you can use "--disable=all +# --enable=similarities". If you want to run only the classes checker, but have +# no Warning level messages displayed, use "--disable=all --enable=classes +# --disable=W". +disable=print-statement, + parameter-unpacking, + unpacking-in-except, + old-raise-syntax, + backtick, + long-suffix, + old-ne-operator, + old-octal-literal, + import-star-module-level, + non-ascii-bytes-literal, + raw-checker-failed, + bad-inline-option, + locally-disabled, + file-ignored, + suppressed-message, + useless-suppression, + deprecated-pragma, + use-symbolic-message-instead, + apply-builtin, + basestring-builtin, + buffer-builtin, + cmp-builtin, + coerce-builtin, + execfile-builtin, + file-builtin, + long-builtin, + raw_input-builtin, + reduce-builtin, + standarderror-builtin, + unicode-builtin, + xrange-builtin, + coerce-method, + delslice-method, + getslice-method, + setslice-method, + no-absolute-import, + old-division, + dict-iter-method, + dict-view-method, + next-method-called, + metaclass-assignment, + indexing-exception, + raising-string, + reload-builtin, + oct-method, + hex-method, + nonzero-method, + cmp-method, + input-builtin, + round-builtin, + intern-builtin, + unichr-builtin, + map-builtin-not-iterating, + zip-builtin-not-iterating, + range-builtin-not-iterating, + filter-builtin-not-iterating, + using-cmp-argument, + eq-without-hash, + div-method, + idiv-method, + rdiv-method, + exception-message-attribute, + invalid-str-codec, + sys-max-int, + bad-python3-import, + deprecated-string-function, + deprecated-str-translate-call, + deprecated-itertools-function, + deprecated-types-field, + next-method-defined, + dict-items-not-iterating, + dict-keys-not-iterating, + dict-values-not-iterating, + deprecated-operator-function, + deprecated-urllib-function, + xreadlines-attribute, + deprecated-sys-function, + exception-escape, + comprehension-escape, + line-too-long, + duplicate-code, + fixme, + too-few-public-methods, + too-many-arguments, + too-many-branches, + too-many-instance-attributes, + too-many-locals, + too-many-statements, + invalid-name, + import-error, + useless-object-inheritance + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time (only on the command line, not in the configuration file where +# it should appear only once). See also the "--disable" option for examples. +enable=c-extension-no-member + + +[REPORTS] + +# Python expression which should return a note less than 10 (10 is the highest +# note). You have access to the variables errors warning, statement which +# respectively contain the number of errors / warnings messages and the total +# number of statements analyzed. This is used by the global evaluation report +# (RP0004). +evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) + +# Template used to display messages. This is a python new-style format string +# used to format the message information. See doc for all details. +#msg-template= + +# Set the output format. Available formats are text, parseable, colorized, json +# and msvs (visual studio). You can also give a reporter class, e.g. +# mypackage.mymodule.MyReporterClass. +output-format=text + +# Tells whether to display a full report or only the messages. +reports=no + +# Activate the evaluation score. +score=yes + + +[REFACTORING] + +# Maximum number of nested blocks for function / method body +max-nested-blocks=5 + +# Complete name of functions that never returns. When checking for +# inconsistent-return-statements if a never returning function is called then +# it will be considered as an explicit return statement and no message will be +# printed. +never-returning-functions=sys.exit + + +[LOGGING] + +# Format style used to check logging format string. `old` means using % +# formatting, while `new` is for `{}` formatting. +logging-format-style=old + +# Logging modules to check that the string format arguments are in logging +# function parameter format. +logging-modules=logging + + +[FORMAT] + +# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. +expected-line-ending-format= + +# Regexp for a line that is allowed to be longer than the limit. +ignore-long-lines=^\s*(# )??$ + +# Number of spaces of indent required inside a hanging or continued line. +indent-after-paren=4 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +indent-string=' ' + +# Maximum number of characters on a single line. +max-line-length=100 + +# Maximum number of lines in a module. +max-module-lines=1000 + +# List of optional constructs for which whitespace checking is disabled. `dict- +# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. +# `trailing-comma` allows a space between comma and closing bracket: (a, ). +# `empty-line` allows space-only lines. +no-space-check=trailing-comma, + dict-separator + +# Allow the body of a class to be on the same line as the declaration if body +# contains single statement. +single-line-class-stmt=no + +# Allow the body of an if to be on the same line as the test if there is no +# else. +single-line-if-stmt=no + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=FIXME, + XXX, + TODO + + +[BASIC] + +# Naming style matching correct argument names. +argument-naming-style=snake_case + +# Regular expression matching correct argument names. Overrides argument- +# naming-style. +#argument-rgx= + +# Naming style matching correct attribute names. +attr-naming-style=snake_case + +# Regular expression matching correct attribute names. Overrides attr-naming- +# style. +#attr-rgx= + +# Bad variable names which should always be refused, separated by a comma. +bad-names=foo, + bar, + baz, + toto, + tutu, + tata + +# Naming style matching correct class attribute names. +class-attribute-naming-style=any + +# Regular expression matching correct class attribute names. Overrides class- +# attribute-naming-style. +#class-attribute-rgx= + +# Naming style matching correct class names. +class-naming-style=PascalCase + +# Regular expression matching correct class names. Overrides class-naming- +# style. +#class-rgx= + +# Naming style matching correct constant names. +const-naming-style=UPPER_CASE + +# Regular expression matching correct constant names. Overrides const-naming- +# style. +#const-rgx= + +# Minimum line length for functions/classes that require docstrings, shorter +# ones are exempt. +docstring-min-length=-1 + +# Naming style matching correct function names. +function-naming-style=snake_case + +# Regular expression matching correct function names. Overrides function- +# naming-style. +#function-rgx= + +# Good variable names which should always be accepted, separated by a comma. +good-names=i, + j, + k, + ex, + Run, + _ + +# Include a hint for the correct naming format with invalid-name. +include-naming-hint=no + +# Naming style matching correct inline iteration names. +inlinevar-naming-style=any + +# Regular expression matching correct inline iteration names. Overrides +# inlinevar-naming-style. +#inlinevar-rgx= + +# Naming style matching correct method names. +method-naming-style=snake_case + +# Regular expression matching correct method names. Overrides method-naming- +# style. +#method-rgx= + +# Naming style matching correct module names. +module-naming-style=snake_case + +# Regular expression matching correct module names. Overrides module-naming- +# style. +#module-rgx= + +# Colon-delimited sets of names that determine each other's naming style when +# the name regexes allow several styles. +name-group= + +# Regular expression which should only match function or class names that do +# not require a docstring. +no-docstring-rgx=^_ + +# List of decorators that produce properties, such as abc.abstractproperty. Add +# to this list to register other decorators that produce valid properties. +# These decorators are taken in consideration only for invalid-name. +property-classes=abc.abstractproperty + +# Naming style matching correct variable names. +variable-naming-style=snake_case + +# Regular expression matching correct variable names. Overrides variable- +# naming-style. +#variable-rgx= + + +[TYPECHECK] + +# List of decorators that produce context managers, such as +# contextlib.contextmanager. Add to this list to register other decorators that +# produce valid context managers. +contextmanager-decorators=contextlib.contextmanager + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E1101 when accessed. Python regular +# expressions are accepted. +generated-members= + +# Tells whether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=yes + +# Tells whether to warn about missing members when the owner of the attribute +# is inferred to be None. +ignore-none=yes + +# This flag controls whether pylint should warn about no-member and similar +# checks whenever an opaque object is returned when inferring. The inference +# can return multiple potential results while evaluating a Python object, but +# some branches might not be evaluated, which results in partial inference. In +# that case, it might be useful to still emit no-member and other checks for +# the rest of the inferred objects. +ignore-on-opaque-inference=yes + +# List of class names for which member attributes should not be checked (useful +# for classes with dynamically set attributes). This supports the use of +# qualified names. +ignored-classes=optparse.Values,thread._local,_thread._local + +# List of module names for which member attributes should not be checked +# (useful for modules/projects where namespaces are manipulated during runtime +# and thus existing member attributes cannot be deduced by static analysis. It +# supports qualified module names, as well as Unix pattern matching. +ignored-modules= + +# Show a hint with possible names when a member name was not found. The aspect +# of finding the hint is based on edit distance. +missing-member-hint=yes + +# The minimum edit distance a name should have in order to be considered a +# similar match for a missing member name. +missing-member-hint-distance=1 + +# The total number of similar names that should be taken in consideration when +# showing a hint for a missing member. +missing-member-max-choices=1 + + +[STRING] + +# This flag controls whether the implicit-str-concat-in-sequence should +# generate a warning on implicit string concatenation in sequences defined over +# several lines. +check-str-concat-over-line-jumps=no + + +[SPELLING] + +# Limits count of emitted suggestions for spelling mistakes. +max-spelling-suggestions=4 + +# Spelling dictionary name. Available dictionaries: none. To make it working +# install python-enchant package.. +spelling-dict= + +# List of comma separated words that should not be checked. +spelling-ignore-words= + +# A path to a file that contains private dictionary; one word per line. +spelling-private-dict-file= + +# Tells whether to store unknown words to indicated private dictionary in +# --spelling-private-dict-file option instead of raising a message. +spelling-store-unknown-words=no + + +[SIMILARITIES] + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + +# Ignore imports when computing similarities. +ignore-imports=no + +# Minimum lines number of a similarity. +min-similarity-lines=4 + + +[VARIABLES] + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid defining new builtins when possible. +additional-builtins= + +# Tells whether unused global variables should be treated as a violation. +allow-global-unused-variables=yes + +# List of strings which can identify a callback function by name. A callback +# name must start or end with one of those strings. +callbacks=cb_, + _cb + +# A regular expression matching the name of dummy variables (i.e. expected to +# not be used). +dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ + +# Argument names that match this expression will be ignored. Default to name +# with leading underscore. +ignored-argument-names=_.*|^ignored_|^unused_ + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# List of qualified module names which can have objects that can redefine +# builtins. +redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io + + +[DESIGN] + +# Maximum number of arguments for function / method. +max-args=5 + +# Maximum number of attributes for a class (see R0902). +max-attributes=7 + +# Maximum number of boolean expressions in an if statement. +max-bool-expr=5 + +# Maximum number of branch for function / method body. +max-branches=12 + +# Maximum number of locals for function / method body. +max-locals=15 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=20 + +# Maximum number of return / yield for function / method body. +max-returns=6 + +# Maximum number of statements in function / method body. +max-statements=50 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=2 + + +[IMPORTS] + +# Allow wildcard imports from modules that define __all__. +allow-wildcard-with-all=no + +# Analyse import fallback blocks. This can be used to support both Python 2 and +# 3 compatible code, which means that the block might have code that exists +# only in one or another interpreter, leading to false positives when analysed. +analyse-fallback-blocks=no + +# Deprecated modules which should not be used, separated by a comma. +deprecated-modules=optparse,tkinter.tix + +# Create a graph of external dependencies in the given file (report RP0402 must +# not be disabled). +ext-import-graph= + +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report RP0402 must not be disabled). +import-graph= + +# Create a graph of internal dependencies in the given file (report RP0402 must +# not be disabled). +int-import-graph= + +# Force import order to recognize a module as part of the standard +# compatibility libraries. +known-standard-library= + +# Force import order to recognize a module as part of a third party library. +known-third-party=enchant + + +[CLASSES] + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__, + __new__, + setUp + +# List of member names, which should be excluded from the protected access +# warning. +exclude-protected=_asdict, + _fields, + _replace, + _source, + _make + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls + +# List of valid names for the first argument in a metaclass class method. +valid-metaclass-classmethod-first-arg=cls + + +[EXCEPTIONS] + +# Exceptions that will emit a warning when being caught. Defaults to +# "BaseException, Exception". +overgeneral-exceptions=BaseException, + Exception diff --git a/.readthedocs.yml b/.readthedocs.yml new file mode 100644 index 0000000..b168698 --- /dev/null +++ b/.readthedocs.yml @@ -0,0 +1,19 @@ +# .readthedocs.yml +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Build documentation in the docs/ directory with Sphinx +sphinx: + configuration: docs/source/conf.py + +# Optionally build your docs in additional formats such as PDF and ePub +formats: all + +# Optionally set the version of Python and requirements required to build your docs +python: + version: 3.7 + install: + - requirements: docs/requirements.txt diff --git a/.travis.yml b/.travis.yml index 2de6a3f..82c14e2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,13 +18,13 @@ cache: - $HOME/.cache/pip install: - - pip install tox coveralls + - pip install tox coveralls flake8 pylint env: - TOXENV=py36 - TOXENV=py27 -script: tox +script: flake8 adb/ && pylint adb/ && tox after_success: - coveralls diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..727e9db --- /dev/null +++ b/Makefile @@ -0,0 +1,23 @@ +.PHONY: release +release: + rm -rf dist + python setup.py sdist bdist_wheel + twine upload dist/* + +.PHONY: docs +docs: + @cd docs/source && rm -f adb*.rst && mkdir -p _static + @cd docs && sphinx-apidoc -f -e -o source/ ../adb/ + @cd docs && make html && make html + +.PHONY: coverage +coverage: + coverage run --source adb setup.py test && coverage html && coverage report -m + +.PHONY: lint +lint: + flake8 adb/ && pylint adb/ + +.PHONY: alltests +alltests: + flake8 adb/ && pylint adb/ && coverage run --source adb setup.py test && coverage report -m diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..38005a2 --- /dev/null +++ b/README.rst @@ -0,0 +1,171 @@ +python-adb +========== + + +.. image:: https://coveralls.io/repos/github/google/python-adb/badge.svg?branch=master + :target: https://coveralls.io/github/google/python-adb?branch=master + :alt: Coverage Status + +.. image:: https://travis-ci.org/google/python-adb.svg?branch=master + :target: https://travis-ci.org/google/python-adb + :alt: Build Status + + +**Documentation:** https://python-adb.readthedocs.io/ + +Note: This is not an official Google project. It is maintained by ex-Google engineers. +For a better maintained option, look at `adb\_shell `_. + +This repository contains a pure-python implementation of the ADB and Fastboot +protocols, using libusb1 for USB communications. + +This is a complete replacement and rearchitecture of the Android project's +`ADB and fastboot code `_. + +This code is mainly targeted to users that need to communicate with Android +devices in an automated fashion, such as in automated testing. It does not have +a daemon between the client and the device, and therefore does not support +multiple simultaneous commands to the same device. It does support any number of +devices and *never* communicates with a device that it wasn't intended to, +unlike the Android project's ADB. + + +Using as standalone tool +------------------------ + +Install using pip: + +.. code-block:: bash + + pip install adb + + +Once installed, two new binaries should be available: ``pyadb`` and ``pyfastboot``. + +.. code-block:: bash + + pyadb devices + pyadb shell ls /sdcard + + +Running ``./make_tools.py`` creates two files: ``adb.zip`` and ``fastboot.zip``. They +can be run similar to native ``adb`` and ``fastboot`` via the python interpreter: + +.. code-block:: bash + + python adb.zip devices + python adb.zip shell ls /sdcard + + +Using as a Python Library +------------------------- + +A `presentation was made at PyCon 2016 `_, +and here's some demo code: + +.. code-block:: python + + import os.path as op + + from adb import adb_commands + from adb import sign_cryptography + + + # KitKat+ devices require authentication + signer = sign_cryptography.CryptographySigner( + op.expanduser('~/.android/adbkey')) + # Connect to the device + device = adb_commands.AdbCommands() + device.ConnectDevice( + rsa_keys=[signer]) + # Now we can use Shell, Pull, Push, etc! + for i in xrange(10): + print device.Shell('echo %d' % i) + + +Pros +---- + +* Simpler code due to use of libusb1 and Python. +* API can be used by other Python code easily. +* Errors are propagated with tracebacks, helping debug connectivity issues. +* No daemon outliving the command. +* Can be packaged as standalone zips that can be run independent of the CPU + architecture (e.g. x86 vs ARM). + + +Cons +---- + +* Technically slower due to Python, mitigated by no daemon. +* Only one command per device at a time. +* More dependencies than Android's ADB. + + +Dependencies +------------ + +* libusb1 (1.0.16+) +* python-libusb1 (1.2.0+) +* **adb.zip**: one of + + * py-cryptography + * python-rsa (3.2+) + +* **fastboot.zip** (optional) + + * python-progressbar (2.3+) + + +History +------- + +1.0.0 +***** + +* Initial version + + +1.1.0 +***** + +* Added TcpHandle (jameyhicks) +* Various timing and other changes (alusco) + + +1.2.0 +***** + +* Update to libusb1 1.6+ (bytearray output) +* Add support for Python 3.6 +* Create adb.zip and fastboot.zip as executable tools. +* Add Travis CI integration +* Support multiple crypto libraries (M2Crypto + python-rsa) +* Push directories + + +1.3.0 +***** + +Backwards Incompatible changes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +``adb_commands.AdbCommands`` is now a normal class rather than a collection of staticmethods. Using the following example code to get started: + +.. code-block:: python + + device = adb_commands.AdbCommands() + device.ConnectDevice(rsa_keys=[signer]) + + +Other changes/fixes +^^^^^^^^^^^^^^^^^^^ + +Many changes since 1.2.0! + +* New entrypoints exposed by pip: pyadb and pyfastboot +* Lots of Python 2/3 compatibility fixes +* Windows compatibility fixes +* Transfer progress available (``Push``, ``Pull``, ``Install``) +* Handle some misbehaving devices (double CLSE bug) +* New options for ``Push`` and ``Install`` (``st_mode`` and ``grant_permissions``) diff --git a/adb/adb_commands.py b/adb/adb_commands.py index 734e31c..9a34102 100644 --- a/adb/adb_commands.py +++ b/adb/adb_commands.py @@ -11,6 +11,7 @@ # 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. + """A libusb1-based ADB reimplementation. ADB was giving us trouble with its client/server architecture, which is great @@ -20,6 +21,36 @@ subprocess and a network socket. All timeouts are in milliseconds. + + +.. rubric:: Contents + +* :class:`AdbCommands` + + * :meth:`AdbCommands.__reset` + * :meth:`AdbCommands._Connect` + * :meth:`AdbCommands._get_service_connection` + * :meth:`AdbCommands.Close` + * :meth:`AdbCommands.ConnectDevice` + * :meth:`AdbCommands.Devices` + * :meth:`AdbCommands.DisableVerity` + * :meth:`AdbCommands.EnableVerity` + * :meth:`AdbCommands.GetState` + * :meth:`AdbCommands.Install` + * :meth:`AdbCommands.InteractiveShell` + * :meth:`AdbCommands.List` + * :meth:`AdbCommands.Logcat` + * :meth:`AdbCommands.Pull` + * :meth:`AdbCommands.Push` + * :meth:`AdbCommands.Reboot` + * :meth:`AdbCommands.RebootBootloader` + * :meth:`AdbCommands.Remount` + * :meth:`AdbCommands.Root` + * :meth:`AdbCommands.Shell` + * :meth:`AdbCommands.Stat` + * :meth:`AdbCommands.StreamingShell` + * :meth:`AdbCommands.Uninstall` + """ import io @@ -31,53 +62,90 @@ from adb import common from adb import filesync_protocol -# From adb.h +try: + file_types = (file, io.IOBase) +except NameError: + file_types = (io.IOBase,) + + +#: From adb.h CLASS = 0xFF + +#: From adb.h SUBCLASS = 0x42 + +#: From adb.h PROTOCOL = 0x01 -# pylint: disable=invalid-name -DeviceIsAvailable = common.InterfaceMatcher(CLASS, SUBCLASS, PROTOCOL) -try: - # Imported locally to keep compatibility with previous code. - from adb.sign_cryptography import CryptographySigner -except ImportError: - # Ignore this error when cryptography is not installed, there are other options. - pass +#: From adb.h +DeviceIsAvailable = common.InterfaceMatcher(CLASS, SUBCLASS, PROTOCOL) class AdbCommands(object): """Exposes adb-like methods for use. Some methods are more-pythonic and/or have more options. + + .. image:: _static/adb.adb_commands.AdbCommands.__init__.CALLER_GRAPH.svg + + Attributes + ---------- + build_props : TODO, None + TODO + filesync_handler : filesync_protocol.FilesyncProtocol + TODO + protocol_handler : adb_protocol.AdbMessage + TODO + _device_state : TODO, None + TODO + _handle : adb.common.TcpHandle, adb.common.UsbHandle, None + TODO + _service_connections : dict + [TODO] Connection table tracks each open AdbConnection objects per service type for program functions that + choose to persist an AdbConnection object for their functionality, using :func:`AdbCommands._get_service_connection` + """ protocol_handler = adb_protocol.AdbMessage filesync_handler = filesync_protocol.FilesyncProtocol def __init__(self): - - self.__reset() - - def __reset(self): self.build_props = None - self._handle = None self._device_state = None - - # Connection table tracks each open AdbConnection objects per service type for program functions - # that choose to persist an AdbConnection object for their functionality, using - # self._get_service_connection + self._handle = None self._service_connections = {} - def _get_service_connection(self, service, service_command=None, create=True, timeout_ms=None): - """ - Based on the service, get the AdbConnection for that service or create one if it doesnt exist + def __reset(self): + """TODO + + .. image:: _static/adb.adb_commands.AdbCommands.__reset.CALL_GRAPH.svg + + .. image:: _static/adb.adb_commands.AdbCommands.__reset.CALLER_GRAPH.svg - :param service: - :param service_command: Additional service parameters to append - :param create: If False, dont create a connection if it does not exist - :return: """ + self.__init__() + def _get_service_connection(self, service, service_command=None, create=True, timeout_ms=None): + """Based on the service, get the AdbConnection for that service or create one if it doesnt exist + + .. image:: _static/adb.adb_commands.AdbCommands._get_service_connection.CALLER_GRAPH.svg + + Parameters + ---------- + service : TODO + TODO + service_command : TODO, None + Additional service parameters to append + create : bool + If False, don't create a connection if it does not exist + timeout_ms : int, None + TODO + + Returns + ------- + connection : TODO + TODO + + """ connection = self._service_connections.get(service, None) if connection: @@ -91,40 +159,50 @@ def _get_service_connection(self, service, service_command=None, create=True, ti else: destination_str = service - connection = self.protocol_handler.Open( - self._handle, destination=destination_str, timeout_ms=timeout_ms) + connection = self.protocol_handler.Open(self._handle, destination=destination_str, timeout_ms=timeout_ms) self._service_connections.update({service: connection}) return connection def ConnectDevice(self, port_path=None, serial=None, default_timeout_ms=None, **kwargs): - """Convenience function to setup a transport handle for the adb device from - usb path or serial then connect to it. - - Args: - port_path: The filename of usb port to use. - serial: The serial number of the device to use. - default_timeout_ms: The default timeout in milliseconds to use. - kwargs: handle: Device handle to use (instance of common.TcpHandle or common.UsbHandle) - banner: Connection banner to pass to the remote device - rsa_keys: List of AuthSigner subclass instances to be used for - authentication. The device can either accept one of these via the Sign - method, or we will send the result of GetPublicKey from the first one - if the device doesn't accept any of them. - auth_timeout_ms: Timeout to wait for when sending a new public key. This - is only relevant when we send a new public key. The device shows a - dialog and this timeout is how long to wait for that dialog. If used - in automation, this should be low to catch such a case as a failure - quickly; while in interactive settings it should be high to allow - users to accept the dialog. We default to automation here, so it's low - by default. - - If serial specifies a TCP address:port, then a TCP connection is - used instead of a USB connection. - """ + """Convenience function to setup a transport handle for the adb device from usb path or serial then connect to + it. + + .. image:: _static/adb.adb_commands.AdbCommands.ConnectDevice.CALL_GRAPH.svg + + Parameters + ---------- + port_path : TODO, None + The filename of usb port to use. + serial : TODO, None + The serial number of the device to use. If serial specifies a TCP address:port, then a TCP connection is + used instead of a USB connection. + default_timeout_ms : TODO, None + The default timeout in milliseconds to use. + **kwargs + Keyword arguments + handle : common.TcpHandle, common.UsbHandle + Device handle to use + banner : TODO + Connection banner to pass to the remote device + rsa_keys : list[adb_protocol.AuthSigner] + List of AuthSigner subclass instances to be used for authentication. The device can either accept one + of these via the ``Sign`` method, or we will send the result of ``GetPublicKey`` from the first one if the + device doesn't accept any of them. + auth_timeout_ms : int + Timeout to wait for when sending a new public key. This is only relevant when we send a new public key. The + device shows a dialog and this timeout is how long to wait for that dialog. If used in automation, this + should be low to catch such a case as a failure quickly; while in interactive settings it should be high to + allow users to accept the dialog. We default to automation here, so it's low by default. + + Returns + ------- + self : AdbCommands + TODO - # If there isnt a handle override (used by tests), build one here + """ + # If there isn't a handle override (used by tests), build one here if 'handle' in kwargs: self._handle = kwargs.pop('handle') else: @@ -135,20 +213,25 @@ def ConnectDevice(self, port_path=None, serial=None, default_timeout_ms=None, ** if serial and ':' in serial: self._handle = common.TcpHandle(serial, timeout_ms=default_timeout_ms) else: - self._handle = common.UsbHandle.FindAndOpen( - DeviceIsAvailable, port_path=port_path, serial=serial, - timeout_ms=default_timeout_ms) + self._handle = common.UsbHandle.FindAndOpen(DeviceIsAvailable, port_path=port_path, serial=serial, timeout_ms=default_timeout_ms) self._Connect(**kwargs) return self def Close(self): + """TODO + + .. image:: _static/adb.adb_commands.AdbCommands.Close.CALL_GRAPH.svg + + .. image:: _static/adb.adb_commands.AdbCommands.Close.CALLER_GRAPH.svg + + """ for conn in list(self._service_connections.values()): if conn: try: conn.Close() - except: + except: # noqa pylint: disable=bare-except pass if self._handle: @@ -159,14 +242,22 @@ def Close(self): def _Connect(self, banner=None, **kwargs): """Connect to the device. - Args: - banner: See protocol_handler.Connect. - **kwargs: See protocol_handler.Connect and adb_commands.ConnectDevice for kwargs. - Includes handle, rsa_keys, and auth_timeout_ms. - Returns: - An instance of this class if the device connected successfully. - """ + .. image:: _static/adb.adb_commands.AdbCommands._Connect.CALLER_GRAPH.svg + + Parameters + ---------- + banner : bytes, None + A string to send as a host identifier. (See :meth:`adb.adb_protocol.AdbMessage.Connect`.) + **kwargs : TODO + See :meth:`adb.adb_protocol.AdbMessage.Connect` and :meth:`AdbCommands.ConnectDevice` for kwargs. Includes ``handle``, ``rsa_keys``, and + ``auth_timeout_ms``. + Returns + ------- + bool + ``True`` + + """ if not banner: banner = socket.gethostname().encode() @@ -183,10 +274,27 @@ def _Connect(self, banner=None, **kwargs): @classmethod def Devices(cls): - """Get a generator of UsbHandle for devices available.""" + """Get a generator of :py:class:`~adb.common.UsbHandle` for devices available. + + Returns + ------- + TODO + TODO + + """ return common.UsbHandle.FindDevices(DeviceIsAvailable) def GetState(self): + """TODO + + .. image:: _static/adb.adb_commands.AdbCommands.GetState.CALL_GRAPH.svg + + Returns + ------- + self._device_state : TODO + TODO + + """ return self._device_state def Install(self, apk_path, destination_dir='', replace_existing=True, @@ -196,17 +304,30 @@ def Install(self, apk_path, destination_dir='', replace_existing=True, Doesn't support verifier file, instead allows destination directory to be overridden. - Args: - apk_path: Local path to apk to install. - destination_dir: Optional destination directory. Use /system/app/ for - persistent applications. - replace_existing: whether to replace existing application - grant_permissions: If True, grant all permissions to the app specified in its manifest - timeout_ms: Expected timeout for pushing and installing. - transfer_progress_callback: callback method that accepts filename, bytes_written and total_bytes of APK transfer - - Returns: - The pm install output. + .. image:: _static/adb.adb_commands.AdbCommands.Install.CALL_GRAPH.svg + + .. image:: _static/adb.adb_commands.AdbCommands.Install.CALLER_GRAPH.svg + + Parameters + ---------- + apk_path : TODO + Local path to apk to install. + destination_dir : str + Optional destination directory. Use ``/system/app/`` for persistent applications. + replace_existing : bool + Whether to replace existing application + grant_permissions : bool + If ``True``, grant all permissions to the app specified in its manifest + timeout_ms : int, None + Expected timeout for pushing and installing. + transfer_progress_callback : TODO, None + callback method that accepts ``filename``, ``bytes_written``, and ``total_bytes`` of APK transfer + + Returns + ------- + ret : TODO + The ``pm install`` output. + """ if not destination_dir: destination_dir = '/data/local/tmp/' @@ -225,20 +346,29 @@ def Install(self, apk_path, destination_dir='', replace_existing=True, # Remove the apk rm_cmd = ['rm', destination_path] - rmret = self.Shell(' '.join(rm_cmd), timeout_ms=timeout_ms) + self.Shell(' '.join(rm_cmd), timeout_ms=timeout_ms) return ret def Uninstall(self, package_name, keep_data=False, timeout_ms=None): """Removes a package from the device. - Args: - package_name: Package name of target package. - keep_data: whether to keep the data and cache directories - timeout_ms: Expected timeout for pushing and installing. + .. image:: _static/adb.adb_commands.AdbCommands.Uninstall.CALL_GRAPH.svg + + Parameters + ---------- + package_name : TODO + Package name of target package. + keep_data : bool + Whether to keep the data and cache directories + timeout_ms : int, None + Expected timeout for pushing and installing. + + Returns + ------- + TODO + The ``pm uninstall`` output. - Returns: - The pm uninstall output. """ cmd = ['pm uninstall'] if keep_data: @@ -250,57 +380,78 @@ def Uninstall(self, package_name, keep_data=False, timeout_ms=None): def Push(self, source_file, device_filename, mtime='0', timeout_ms=None, progress_callback=None, st_mode=None): """Push a file or directory to the device. - Args: - source_file: Either a filename, a directory or file-like object to push to - the device. - device_filename: Destination on the device to write to. - mtime: Optional, modification time to set on the file. - timeout_ms: Expected timeout for any part of the push. - st_mode: stat mode for filename - progress_callback: callback method that accepts filename, bytes_written and total_bytes, - total_bytes will be -1 for file-like objects - """ + .. image:: _static/adb.adb_commands.AdbCommands.Push.CALL_GRAPH.svg + + .. image:: _static/adb.adb_commands.AdbCommands.Push.CALLER_GRAPH.svg + + Parameters + ---------- + source_file : TODO + Either a filename, a directory or file-like object to push to the device. + device_filename : TODO + Destination on the device to write to. + mtime : str + Modification time to set on the file. + timeout_ms : int, None + Expected timeout for any part of the push. + progress_callback : TODO, None + Callback method that accepts filename, bytes_written and total_bytes, total_bytes will be -1 for file-like + objects + st_mode : TODO, None + Stat mode for filename + """ if isinstance(source_file, str): if os.path.isdir(source_file): self.Shell("mkdir " + device_filename) for f in os.listdir(source_file): - self.Push(os.path.join(source_file, f), device_filename + '/' + f, - progress_callback=progress_callback) + self.Push(os.path.join(source_file, f), device_filename + '/' + f, progress_callback=progress_callback) return + source_file = open(source_file, "rb") with source_file: - connection = self.protocol_handler.Open( - self._handle, destination=b'sync:', timeout_ms=timeout_ms) - kwargs={} + connection = self.protocol_handler.Open(self._handle, destination=b'sync:', timeout_ms=timeout_ms) + kwargs = {} if st_mode is not None: kwargs['st_mode'] = st_mode - self.filesync_handler.Push(connection, source_file, device_filename, - mtime=int(mtime), progress_callback=progress_callback, **kwargs) + self.filesync_handler.Push(connection, source_file, device_filename, mtime=int(mtime), progress_callback=progress_callback, **kwargs) connection.Close() def Pull(self, device_filename, dest_file=None, timeout_ms=None, progress_callback=None): """Pull a file from the device. - Args: - device_filename: Filename on the device to pull. - dest_file: If set, a filename or writable file-like object. - timeout_ms: Expected timeout for any part of the pull. - progress_callback: callback method that accepts filename, bytes_written and total_bytes, - total_bytes will be -1 for file-like objects + Parameters + ---------- + device_filename : TODO + Filename on the device to pull. + dest_file : str, file, io.IOBase, None + If set, a filename or writable file-like object. + timeout_ms : int, None + Expected timeout for any part of the pull. + progress_callback : TODO, None + Callback method that accepts filename, bytes_written and total_bytes, total_bytes will be -1 for file-like + objects + + Returns + ------- + TODO + The file data if ``dest_file`` is not set. Otherwise, ``True`` if the destination file exists + + Raises + ------ + ValueError + If ``dest_file`` is of unknown type. - Returns: - The file data if dest_file is not set. Otherwise, True if the destination file exists """ if not dest_file: dest_file = io.BytesIO() elif isinstance(dest_file, str): dest_file = open(dest_file, 'wb') - elif isinstance(dest_file, file): + elif isinstance(dest_file, file_types): pass else: - raise ValueError("destfile is of unknown type") + raise ValueError("dest_file is of unknown type") conn = self.protocol_handler.Open( self._handle, destination=b'sync:', timeout_ms=timeout_ms) @@ -310,26 +461,52 @@ def Pull(self, device_filename, dest_file=None, timeout_ms=None, progress_callba conn.Close() if isinstance(dest_file, io.BytesIO): return dest_file.getvalue() - else: - dest_file.close() - if hasattr(dest_file, 'name'): - return os.path.exists(dest_file.name) - # We don't know what the path is, so we just assume it exists. - return True + + dest_file.close() + if hasattr(dest_file, 'name'): + return os.path.exists(dest_file.name) + + # We don't know what the path is, so we just assume it exists. + return True def Stat(self, device_filename): - """Get a file's stat() information.""" + """Get a file's ``stat()`` information. + + .. image:: _static/adb.adb_commands.AdbCommands.Stat.CALLER_GRAPH.svg + + Parameters + ---------- + device_filename : TODO + TODO + + Returns + ------- + mode : TODO + TODO + size : TODO + TODO + mtime : TODO + TODO + + """ connection = self.protocol_handler.Open(self._handle, destination=b'sync:') - mode, size, mtime = self.filesync_handler.Stat( - connection, device_filename) + mode, size, mtime = self.filesync_handler.Stat(connection, device_filename) connection.Close() return mode, size, mtime def List(self, device_path): """Return a directory listing of the given path. - Args: - device_path: Directory to list. + Parameters + ---------- + device_path : TODO + Directory to list. + + Returns + ------- + listing : TODO + TODO + """ connection = self.protocol_handler.Open(self._handle, destination=b'sync:') listing = self.filesync_handler.List(connection, device_path) @@ -339,81 +516,151 @@ def List(self, device_path): def Reboot(self, destination=b''): """Reboot the device. - Args: - destination: Specify 'bootloader' for fastboot. + .. image:: _static/adb.adb_commands.AdbCommands.Reboot.CALLER_GRAPH.svg + + Parameters + ---------- + destination : bytes + Specify ``'bootloader'`` for fastboot. + """ self.protocol_handler.Open(self._handle, b'reboot:%s' % destination) def RebootBootloader(self): - """Reboot device into fastboot.""" + """Reboot device into fastboot. + + .. image:: _static/adb.adb_commands.AdbCommands.RebootBootloader.CALL_GRAPH.svg + + """ self.Reboot(b'bootloader') def Remount(self): - """Remount / as read-write.""" + """Remount / as read-write. + + Returns + ------- + TODO + TODO + + """ return self.protocol_handler.Command(self._handle, service=b'remount') def Root(self): - """Restart adbd as root on the device.""" + """Restart ``adbd`` as root on the device. + + Returns + ------- + TODO + TODO + + """ return self.protocol_handler.Command(self._handle, service=b'root') def EnableVerity(self): - """Re-enable dm-verity checking on userdebug builds""" + """Re-enable dm-verity checking on userdebug builds. + + Returns + ------- + TODO + TODO + + """ return self.protocol_handler.Command(self._handle, service=b'enable-verity') def DisableVerity(self): - """Disable dm-verity checking on userdebug builds""" + """Disable dm-verity checking on userdebug builds. + + Returns + ------- + TODO + TODO + + """ return self.protocol_handler.Command(self._handle, service=b'disable-verity') def Shell(self, command, timeout_ms=None): """Run command on the device, returning the output. - Args: - command: Shell command to run - timeout_ms: Maximum time to allow the command to run. + .. image:: _static/adb.adb_commands.AdbCommands.Shell.CALLER_GRAPH.svg + + Parameters + ---------- + command : TODO + Shell command to run + timeout_ms : int, None + Maximum time to allow the command to run. + + Returns + ------- + TODO + TODO + """ - return self.protocol_handler.Command( - self._handle, service=b'shell', command=command, - timeout_ms=timeout_ms) + return self.protocol_handler.Command(self._handle, service=b'shell', command=command, timeout_ms=timeout_ms) def StreamingShell(self, command, timeout_ms=None): """Run command on the device, yielding each line of output. - Args: - command: Command to run on the target. - timeout_ms: Maximum time to allow the command to run. + .. image:: _static/adb.adb_commands.AdbCommands.StreamingShell.CALLER_GRAPH.svg + + Parameters + ---------- + command : bytes + Command to run on the target. + timeout_ms : int, None + Maximum time to allow the command to run. + + Returns + ------- + generator + The responses from the shell command. - Yields: - The responses from the shell command. """ - return self.protocol_handler.StreamingCommand( - self._handle, service=b'shell', command=command, - timeout_ms=timeout_ms) + return self.protocol_handler.StreamingCommand(self._handle, service=b'shell', command=command, timeout_ms=timeout_ms) def Logcat(self, options, timeout_ms=None): - """Run 'shell logcat' and stream the output to stdout. + """Run ``shell logcat`` and stream the output to stdout. + + .. image:: _static/adb.adb_commands.AdbCommands.Logcat.CALL_GRAPH.svg + + Parameters + ---------- + options : str + Arguments to pass to ``logcat`` + timeout_ms : int, None + Maximum time to allow the command to run. + + Returns + ------- + generator + The responses from the ``logcat`` command - Args: - options: Arguments to pass to 'logcat'. - timeout_ms: Maximum time to allow the command to run. """ return self.StreamingShell('logcat %s' % options, timeout_ms) def InteractiveShell(self, cmd=None, strip_cmd=True, delim=None, strip_delim=True): - """Get stdout from the currently open interactive shell and optionally run a command - on the device, returning all output. - - Args: - cmd: Optional. Command to run on the target. - strip_cmd: Optional (default True). Strip command name from stdout. - delim: Optional. Delimiter to look for in the output to know when to stop expecting more output - (usually the shell prompt) - strip_delim: Optional (default True): Strip the provided delimiter from the output - - Returns: - The stdout from the shell command. + """Get stdout from the currently open interactive shell and optionally run a command on the device, returning + all output. + + .. image:: _static/adb.adb_commands.AdbCommands.InteractiveShell.CALL_GRAPH.svg + + Parameters + ---------- + cmd : TODO, None + Command to run on the target. + strip_cmd : bool + Strip command name from stdout. + delim : TODO, None + Delimiter to look for in the output to know when to stop expecting more output (usually the shell prompt) + strip_delim : bool + Strip the provided delimiter from the output + + Returns + ------- + TODO + The stdout from the shell command. + """ conn = self._get_service_connection(b'shell:') - return self.protocol_handler.InteractiveShellCommand( - conn, cmd=cmd, strip_cmd=strip_cmd, - delim=delim, strip_delim=strip_delim) + return self.protocol_handler.InteractiveShellCommand(conn, cmd=cmd, strip_cmd=strip_cmd, delim=delim, strip_delim=strip_delim) diff --git a/adb/adb_debug.py b/adb/adb_debug.py index 6037269..94340b1 100644 --- a/adb/adb_debug.py +++ b/adb/adb_debug.py @@ -13,7 +13,17 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""Daemon-less ADB client in python.""" +"""Daemon-less ADB client in python. + + +.. rubric:: Contents + +* :func:`Devices` +* :func:`List` +* :func:`Logcat` +* :func:`Shell` + +""" import argparse import functools @@ -47,14 +57,32 @@ def Devices(args): """Lists the available devices. - Mimics 'adb devices' output: + Mimics ``adb devices`` output: + + :: + List of devices attached 015DB7591102001A device 1,2 + + + .. seealso:: :meth:`adb.adb_commands.AdbCommands.Devices` + + .. image:: _static/adb.adb_debug.Devices.CALLER_GRAPH.svg + + Parameters + ---------- + args : argparse.ArgumentParser + CLI arguments; see :func:`adb.common_cli.GetDeviceArguments`. + + Returns + ------- + int + 0 + """ for d in adb_commands.AdbCommands.Devices(): if args.output_port_path: - print('%s\tdevice\t%s' % ( - d.serial_number, ','.join(str(p) for p in d.port_path))) + print('%s\tdevice\t%s' % (d.serial_number, ','.join(str(p) for p in d.port_path))) else: print('%s\tdevice' % d.serial_number) return 0 @@ -63,16 +91,27 @@ def Devices(args): def List(device, device_path): """Prints a directory listing. - Args: - device_path: Directory to list. + .. seealso:: :meth:`adb.adb_commands.AdbCommands.List` + + Parameters + ---------- + device : adb.adb_commands.AdbCommands + TODO + device_path : str, bytes + Directory to list. + + Yields + ------ + str + A formatted listing for a file in ``device_path`` + """ files = device.List(device_path) files.sort(key=lambda x: x.filename) maxname = max(len(f.filename) for f in files) maxsize = max(len(str(f.size)) for f in files) for f in files: - mode = ( - ('d' if stat.S_ISDIR(f.mode) else '-') + + mode = (('d' if stat.S_ISDIR(f.mode) else '-') + ('r' if f.mode & stat.S_IRUSR else '-') + ('w' if f.mode & stat.S_IWUSR else '-') + ('x' if f.mode & stat.S_IXUSR else '-') + @@ -83,6 +122,7 @@ def List(device, device_path): ('w' if f.mode & stat.S_IWOTH else '-') + ('x' if f.mode & stat.S_IXOTH else '-')) t = time.gmtime(f.mtime) + yield '%s %*d %04d-%02d-%02d %02d:%02d:%02d %-*s\n' % ( mode, maxsize, f.size, t.tm_year, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, @@ -91,85 +131,94 @@ def List(device, device_path): @functools.wraps(adb_commands.AdbCommands.Logcat) def Logcat(device, *options): - return device.Logcat( - device, ' '.join(options), timeout_ms=0) + """Run ``shell logcat`` and stream the output to stdout. + + .. seealso:: :meth:`adb.adb_commands.AdbCommands.Logcat` + + Parameters + ---------- + device : adb.adb_commands.AdbCommands + TODO + options : list[str] + Arguments to pass to ``logcat`` + + Returns + ------- + generator + The responses from the ``logcat`` command + + """ + return device.Logcat(device, ' '.join(options), timeout_ms=0) def Shell(device, *command): """Runs a command on the device and prints the stdout. - Args: - command: Command to run on the target. + .. seealso:: :meth:`adb.adb_commands.AdbCommands.StreamingShell`, :meth:`adb.adb_commands.AdbCommands.InteractiveShell` + + Parameters + ---------- + device : adb.adb_commands.AdbCommands + TODO + command : list[str] + Command to run on the target. + """ if command: return device.StreamingShell(' '.join(command)) - else: - # Retrieve the initial terminal prompt to use as a delimiter for future reads - terminal_prompt = device.InteractiveShell() - print(terminal_prompt.decode('utf-8')) - - # Accept user input in a loop and write that into the interactive shells stdin, then print output - while True: - cmd = input('> ') - if not cmd: - continue - elif cmd == 'exit': - break - else: - stdout = device.InteractiveShell(cmd, strip_cmd=True, delim=terminal_prompt, strip_delim=True) - if stdout: - if isinstance(stdout, bytes): - stdout = stdout.decode('utf-8') - print(stdout) - - device.Close() + + # Retrieve the initial terminal prompt to use as a delimiter for future reads + terminal_prompt = device.InteractiveShell() + print(terminal_prompt.decode('utf-8')) + + # Accept user input in a loop and write that into the interactive shells stdin, then print output + while True: + cmd = input('> ') + if not cmd: + continue + + if cmd == 'exit': + break + + stdout = device.InteractiveShell(cmd, strip_cmd=True, delim=terminal_prompt, strip_delim=True) + if stdout: + if isinstance(stdout, bytes): + stdout = stdout.decode('utf-8') + print(stdout) + + device.Close() def main(): + """TODO""" common = common_cli.GetCommonArguments() - common.add_argument( - '--rsa_key_path', action='append', default=[], - metavar='~/.android/adbkey', - help='RSA key(s) to use, use multiple times to load mulitple keys') - common.add_argument( - '--auth_timeout_s', default=60., metavar='60', type=int, - help='Seconds to wait for the dialog to be accepted when using ' - 'authenticated ADB.') + common.add_argument('--rsa_key_path', action='append', default=[], metavar='~/.android/adbkey', + help='RSA key(s) to use, use multiple times to load mulitple keys') + common.add_argument('--auth_timeout_s', default=60., metavar='60', type=int, + help='Seconds to wait for the dialog to be accepted when using authenticated ADB.') + device = common_cli.GetDeviceArguments() parents = [common, device] - parser = argparse.ArgumentParser( - description=sys.modules[__name__].__doc__, parents=[common]) + parser = argparse.ArgumentParser(description=sys.modules[__name__].__doc__, parents=[common]) subparsers = parser.add_subparsers(title='Commands', dest='command_name') - subparser = subparsers.add_parser( - name='help', help='Prints the commands available') - subparser = subparsers.add_parser( - name='devices', help='Lists the available devices', parents=[common]) - subparser.add_argument( - '--output_port_path', action='store_true', - help='Outputs the port_path alongside the serial') + subparser = subparsers.add_parser(name='help', help='Prints the commands available') + subparser = subparsers.add_parser(name='devices', help='Lists the available devices', parents=[common]) + + subparser.add_argument('--output_port_path', action='store_true', help='Outputs the port_path alongside the serial') - common_cli.MakeSubparser( - subparsers, parents, adb_commands.AdbCommands.Install) + common_cli.MakeSubparser(subparsers, parents, adb_commands.AdbCommands.Install) common_cli.MakeSubparser(subparsers, parents, adb_commands.AdbCommands.Uninstall) common_cli.MakeSubparser(subparsers, parents, List) common_cli.MakeSubparser(subparsers, parents, Logcat) - common_cli.MakeSubparser( - subparsers, parents, adb_commands.AdbCommands.Push, - {'source_file': 'Filename or directory to push to the device.'}) - common_cli.MakeSubparser( - subparsers, parents, adb_commands.AdbCommands.Pull, - { - 'dest_file': 'Filename to write to on the host, if not specified, ' - 'prints the content to stdout.', - }) - common_cli.MakeSubparser( - subparsers, parents, adb_commands.AdbCommands.Reboot) - common_cli.MakeSubparser( - subparsers, parents, adb_commands.AdbCommands.RebootBootloader) - common_cli.MakeSubparser( - subparsers, parents, adb_commands.AdbCommands.Remount) + common_cli.MakeSubparser(subparsers, parents, adb_commands.AdbCommands.Push, + {'source_file': 'Filename or directory to push to the device.'}) + common_cli.MakeSubparser(subparsers, parents, adb_commands.AdbCommands.Pull, + {'dest_file': 'Filename to write to on the host, if not specified, prints the content to stdout.'}) + common_cli.MakeSubparser(subparsers, parents, adb_commands.AdbCommands.Reboot) + common_cli.MakeSubparser(subparsers, parents, adb_commands.AdbCommands.RebootBootloader) + common_cli.MakeSubparser(subparsers, parents, adb_commands.AdbCommands.Remount) common_cli.MakeSubparser(subparsers, parents, adb_commands.AdbCommands.Root) common_cli.MakeSubparser(subparsers, parents, adb_commands.AdbCommands.EnableVerity) common_cli.MakeSubparser(subparsers, parents, adb_commands.AdbCommands.DisableVerity) @@ -182,29 +231,32 @@ def main(): args = parser.parse_args() if args.verbose: logging.basicConfig(level=logging.DEBUG) + if not args.rsa_key_path: default = os.path.expanduser('~/.android/adbkey') if os.path.isfile(default): args.rsa_key_path = [default] + if args.rsa_key_path and not rsa_signer: parser.error('Please install either cryptography, python-rsa, or PycryptoDome') # Hacks so that the generated doc is nicer. if args.command_name == 'devices': return Devices(args) + if args.command_name == 'help': parser.print_help() return 0 + if args.command_name == 'logcat': args.positional = args.options elif args.command_name == 'shell': args.positional = args.command - return common_cli.StartCli( - args, - adb_commands.AdbCommands, - auth_timeout_ms=int(args.auth_timeout_s * 1000), - rsa_keys=[rsa_signer(path) for path in args.rsa_key_path]) + return common_cli.StartCli(args, + adb_commands.AdbCommands, + auth_timeout_ms=int(args.auth_timeout_s * 1000), + rsa_keys=[rsa_signer(path) for path in args.rsa_key_path]) if __name__ == '__main__': diff --git a/adb/adb_keygen.py b/adb/adb_keygen.py new file mode 100644 index 0000000..c524940 --- /dev/null +++ b/adb/adb_keygen.py @@ -0,0 +1,247 @@ +"""This file implements encoding and decoding logic for Android's custom RSA +public key binary format. Public keys are stored as a sequence of +little-endian 32 bit words. Note that Android only supports little-endian +processors, so we don't do any byte order conversions when parsing the binary +struct. + +Structure from: +https://github.com/aosp-mirror/platform_system_core/blob/c55fab4a59cfa461857c6a61d8a0f1ae4591900c/libcrypto_utils/android_pubkey.c + +.. code-block:: c + + typedef struct RSAPublicKey { + // Modulus length. This must be ANDROID_PUBKEY_MODULUS_SIZE_WORDS + uint32_t modulus_size_words; + + // Precomputed montgomery parameter: -1 / n[0] mod 2^32 + uint32_t n0inv; + + // RSA modulus as a little-endian array + uint8_t modulus[ANDROID_PUBKEY_MODULUS_SIZE]; + + // Montgomery parameter R^2 as a little-endian array of little-endian words + uint8_t rr[ANDROID_PUBKEY_MODULUS_SIZE]; + + // RSA modulus: 3 or 65537 + uint32_t exponent; + } RSAPublicKey; + + +.. rubric:: Contents + +* :func:`_to_bytes` +* :func:`decode_pubkey` +* :func:`decode_pubkey_file` +* :func:`encode_pubkey` +* :func:`get_user_info` +* :func:`keygen` +* :func:`write_public_keyfile` + +""" + + +from __future__ import print_function + +import os +import base64 +import socket +import struct +import sys + +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric import rsa + + +if sys.version_info[0] == 2: + FileNotFoundError = IOError # pylint: disable=redefined-builtin + + +#: Size of an RSA modulus such as an encrypted block or a signature. +ANDROID_PUBKEY_MODULUS_SIZE = (2048 // 8) + +#: Python representation of "struct RSAPublicKey" +ANDROID_RSAPUBLICKEY_STRUCT = ( + '<' # Little-endian + 'L' # uint32_t modulus_size_words; + 'L' # uint32_t n0inv; + '{modulus_size}s' # uint8_t modulus[ANDROID_PUBKEY_MODULUS_SIZE]; + '{modulus_size}s' # uint8_t rr[ANDROID_PUBKEY_MODULUS_SIZE]; + 'L' # uint32_t exponent; +).format(modulus_size=ANDROID_PUBKEY_MODULUS_SIZE) + + +#: Size of the RSA modulus in words. +ANDROID_PUBKEY_MODULUS_SIZE_WORDS = (ANDROID_PUBKEY_MODULUS_SIZE // 4) + + +def _to_bytes(n, length, endianess='big'): + """Partial python2 compatibility with int.to_bytes + + https://stackoverflow.com/a/20793663 + + Parameters + ---------- + n : TODO + TODO + length : TODO + TODO + endianess : str, TODO + TODO + + Returns + ------- + TODO + TODO + + """ + if not hasattr(n, 'to_bytes'): + h = '{:x}'.format(n) + s = ('0' * (len(h) % 2) + h).zfill(length * 2).decode('hex') + return s if endianess == 'big' else s[::-1] + return n.to_bytes(length, endianess) + + +def decode_pubkey(public_key): + """Decode a public RSA key stored in Android's custom binary format. + + Parameters + ---------- + public_key : TODO + TODO + + """ + binary_key_data = base64.b64decode(public_key) + modulus_size_words, n0inv, modulus_bytes, rr_bytes, exponent = struct.unpack(ANDROID_RSAPUBLICKEY_STRUCT, binary_key_data) + assert modulus_size_words == ANDROID_PUBKEY_MODULUS_SIZE_WORDS + modulus = reversed(modulus_bytes) + rr = reversed(rr_bytes) + print('modulus_size_words:', hex(modulus_size_words)) + print('n0inv:', hex(n0inv)) + print('modulus: ', end='') + print(*map(hex, modulus), sep=':') + print('rr: ', end='') + print(*map(hex, rr), sep=':') + print('exponent:', hex(exponent)) + + +def decode_pubkey_file(public_key_path): + """TODO + + Parameters + ---------- + public_key_path : str + TODO + + """ + with open(public_key_path, 'rb') as fd: + decode_pubkey(fd.read()) + + +def encode_pubkey(private_key_path): + """Encodes a public RSA key into Android's custom binary format. + + Parameters + ---------- + private_key_path : str + TODO + + Returns + ------- + TODO + TODO + + """ + with open(private_key_path, 'rb') as key_file: + key = serialization.load_pem_private_key(key_file.read(), password=None, backend=default_backend()).private_numbers().public_numbers + + # Compute and store n0inv = -1 / N[0] mod 2^32. + # BN_set_bit(r32, 32) + r32 = 1 << 32 + # BN_mod(n0inv, key->n, r32, ctx) + n0inv = key.n % r32 + # BN_mod_inverse(n0inv, n0inv, r32, ctx) + n0inv = rsa._modinv(n0inv, r32) # pylint: disable=protected-access + # BN_sub(n0inv, r32, n0inv) + n0inv = r32 - n0inv + + # Compute and store rr = (2^(rsa_size)) ^ 2 mod N. + # BN_set_bit(rr, ANDROID_PUBKEY_MODULUS_SIZE * 8) + rr = 1 << (ANDROID_PUBKEY_MODULUS_SIZE * 8) + # BN_mod_sqr(rr, rr, key->n, ctx) + rr = (rr ** 2) % key.n + + return struct.pack( + ANDROID_RSAPUBLICKEY_STRUCT, + ANDROID_PUBKEY_MODULUS_SIZE_WORDS, + n0inv, + _to_bytes(key.n, ANDROID_PUBKEY_MODULUS_SIZE, 'little'), + _to_bytes(rr, ANDROID_PUBKEY_MODULUS_SIZE, 'little'), + key.e + ) + + +def get_user_info(): + """TODO + + Returns + ------- + str + ``' @`` + + """ + try: + username = os.getlogin() + except (FileNotFoundError, OSError): + username = 'unknown' + + if not username: + username = 'unknown' + + hostname = socket.gethostname() + if not hostname: + hostname = 'unknown' + + return ' ' + username + '@' + hostname + + +def write_public_keyfile(private_key_path, public_key_path): + """Write a public keyfile to ``public_key_path`` in Android's custom + RSA public key format given a path to a private keyfile. + + Parameters + ---------- + private_key_path : TODO + TODO + public_key_path : TODO + TODO + + """ + public_key = encode_pubkey(private_key_path) + assert len(public_key) == struct.calcsize(ANDROID_RSAPUBLICKEY_STRUCT) + + with open(public_key_path, 'wb') as public_key_file: + public_key_file.write(base64.b64encode(public_key)) + public_key_file.write(get_user_info().encode()) + + +def keygen(filepath): + """Generate an ADB public/private key pair. + + * The private key is stored in ``filepath``. + * The public key is stored in ``filepath + '.pub'`` + + (Existing files will be overwritten.) + + Parameters + ---------- + filepath : str + File path to write the private/public keypair + + """ + private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()) + + with open(filepath, 'wb') as private_key_file: + private_key_file.write(private_key.private_bytes(encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.PKCS8, encryption_algorithm=serialization.NoEncryption())) + + write_public_keyfile(filepath, filepath + '.pub') diff --git a/adb/adb_protocol.py b/adb/adb_protocol.py index 4ff28c7..e05c88a 100644 --- a/adb/adb_protocol.py +++ b/adb/adb_protocol.py @@ -11,10 +11,50 @@ # 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. + """ADB protocol implementation. Implements the ADB protocol as seen in android's adb/adbd binaries, but only the host side. + + +.. rubric:: Contents + +* :class:`_AdbConnection` + + * :meth:`_AdbConnection._Send` + * :meth:`_AdbConnection.Close` + * :meth:`_AdbConnection.Okay` + * :meth:`_AdbConnection.ReadUntil` + * :meth:`_AdbConnection.ReadUntilClose` + * :meth:`_AdbConnection.Write` + +* :class:`AdbMessage` + + * :meth:`AdbMessage.CalculateChecksum` + * :meth:`AdbMessage.checksum` + * :meth:`AdbMessage.Command` + * :meth:`AdbMessage.Connect` + * :meth:`AdbMessage.InteractiveShellCommand` + * :meth:`AdbMessage.Open` + * :meth:`AdbMessage.Pack` + * :meth:`AdbMessage.Read` + * :meth:`AdbMessage.Send` + * :meth:`AdbMessage.StreamingCommand` + * :meth:`AdbMessage.Unpack` + +* :class:`AuthSigner` + + * :meth:`AuthSigner.GetPublicKey` + * :meth:`AuthSigner.Sign` + +* :func:`find_backspace_runs` +* :class:`InterleavedDataError` +* :class:`InvalidChecksumError` +* :class:`InvalidCommandError` +* :class:`InvalidResponseError` +* :func:`MakeWireIDs` + """ import struct @@ -22,18 +62,81 @@ from io import BytesIO from adb import usb_exceptions -# Maximum amount of data in an ADB packet. + +#: Maximum amount of data in an ADB packet. MAX_ADB_DATA = 4096 -# ADB protocol version. + +#: ADB protocol version. VERSION = 0x01000000 -# AUTH constants for arg0. +#: AUTH constants for arg0. AUTH_TOKEN = 1 + +#: AUTH constants for arg0. AUTH_SIGNATURE = 2 + +#: AUTH constants for arg0. AUTH_RSAPUBLICKEY = 3 +class InvalidCommandError(Exception): + """Got an invalid command over USB. + + .. image:: _static/adb.adb_protocol.InvalidCommandError.CALL_GRAPH.svg + + .. image:: _static/adb.adb_protocol.InvalidCommandError.__init__.CALLER_GRAPH.svg + + """ + def __init__(self, message, response_header, response_data): + if response_header == b'FAIL': + message = 'Command failed, device said so. (%s)' % message + super(InvalidCommandError, self).__init__(message, response_header, response_data) + + +class InvalidResponseError(Exception): + """Got an invalid response to our command. + + .. image:: _static/adb.adb_protocol.InvalidResponseError.CALL_GRAPH.svg + + """ + + +class InvalidChecksumError(Exception): + """Checksum of data didn't match expected checksum. + + .. image:: _static/adb.adb_protocol.InvalidChecksumError.CALL_GRAPH.svg + + """ + + +class InterleavedDataError(Exception): + """We only support command sent serially. + + .. image:: _static/adb.adb_protocol.InterleavedDataError.CALL_GRAPH.svg + + """ + + def find_backspace_runs(stdout_bytes, start_pos): + """TODO + + .. image:: _static/adb.adb_protocol.find_backspace_runs.CALLER_GRAPH.svg + + Parameters + ---------- + stdout_bytes : TODO + TODO + start_pos : TODO + TODO + + Returns + ------- + int + The index/position of the first backspace. + num_backspaces : int + TODO + + """ first_backspace_pos = stdout_bytes[start_pos:].find(b'\x08') if first_backspace_pos == -1: return -1, 0 @@ -50,33 +153,23 @@ def find_backspace_runs(stdout_bytes, start_pos): return (start_pos + first_backspace_pos), num_backspaces -class InvalidCommandError(Exception): - """Got an invalid command over USB.""" - - def __init__(self, message, response_header, response_data): - if response_header == b'FAIL': - message = 'Command failed, device said so. (%s)' % message - super(InvalidCommandError, self).__init__( - message, response_header, response_data) - - -class InvalidResponseError(Exception): - """Got an invalid response to our command.""" - - -class InvalidChecksumError(Exception): - """Checksum of data didn't match expected checksum.""" - +def MakeWireIDs(ids): + """TODO -class InterleavedDataError(Exception): - """We only support command sent serially.""" + Parameters + ---------- + ids : list[bytes] + TODO + Returns + ------- + id_to_wire : dict + TODO + wire_to_id : dict + TODO -def MakeWireIDs(ids): - id_to_wire = { - cmd_id: sum(c << (i * 8) for i, c in enumerate(bytearray(cmd_id))) - for cmd_id in ids - } + """ + id_to_wire = {cmd_id: sum(c << (i * 8) for i, c in enumerate(bytearray(cmd_id))) for cmd_id in ids} wire_to_id = {wire: cmd_id for cmd_id, wire in id_to_wire.items()} return id_to_wire, wire_to_id @@ -85,17 +178,61 @@ class AuthSigner(object): """Signer for use with authenticated ADB, introduced in 4.4.x/KitKat.""" def Sign(self, data): - """Signs given data using a private key.""" + """Signs given data using a private key. + + Parameters + ---------- + data : bytes + The data to be signed + + Raises + ------ + NotImplementedError + This method is implemented in subclasses. + + """ raise NotImplementedError() def GetPublicKey(self): - """Returns the public key in PEM format without headers or newlines.""" + """Returns the public key in PEM format without headers or newlines. + + Raises + ------ + NotImplementedError + This method is implemented in subclasses. + + """ raise NotImplementedError() class _AdbConnection(object): - """ADB Connection.""" + """ADB Connection. + + .. image:: _static/adb.adb_protocol._AdbConnection.__init__.CALLER_GRAPH.svg + + Parameters + ---------- + usb : adb.common.UsbHandle + TODO + local_id : TODO + TODO + remote_id : TODO + TODO + timeout_ms : int + Timeout in milliseconds for USB packets. + + Attributes + ---------- + local_id : TODO + The ID for the sender + remote_id : TODO + The ID for the recipient + timeout_ms : int + Timeout in milliseconds for USB packets. + usb : adb.common.UsbHandle + TODO + """ def __init__(self, usb, local_id, remote_id, timeout_ms): self.usb = usb self.local_id = local_id @@ -103,80 +240,204 @@ def __init__(self, usb, local_id, remote_id, timeout_ms): self.timeout_ms = timeout_ms def _Send(self, command, arg0, arg1, data=b''): + """TODO + + .. image:: _static/adb.adb_protocol._AdbConnection._Send.CALLER_GRAPH.svg + + Parameters + ---------- + command : TODO + TODO + arg0 : TODO + TODO + arg1 : TODO + TODO + data : bytes + TODO + + """ message = AdbMessage(command, arg0, arg1, data) message.Send(self.usb, self.timeout_ms) def Write(self, data): - """Write a packet and expect an Ack.""" + """Write a packet and expect an Ack. + + .. image:: _static/adb.adb_protocol._AdbConnection.Write.CALL_GRAPH.svg + + Parameters + ---------- + data : TODO + TODO + + Returns + ------- + int + ``len(data)`` + + Raises + ------ + usb_exceptions.AdbCommandFailureException + The command failed. + adb.adb_protocol.InvalidCommandError + Expected an OKAY in response to a WRITE, got something else. + + """ self._Send(b'WRTE', arg0=self.local_id, arg1=self.remote_id, data=data) + # Expect an ack in response. cmd, okay_data = self.ReadUntil(b'OKAY') if cmd != b'OKAY': if cmd == b'FAIL': - raise usb_exceptions.AdbCommandFailureException( - 'Command failed.', okay_data) - raise InvalidCommandError( - 'Expected an OKAY in response to a WRITE, got %s (%s)', - cmd, okay_data) + raise usb_exceptions.AdbCommandFailureException('Command failed.', okay_data) + + raise InvalidCommandError('Expected an OKAY in response to a WRITE, got {0} ({1})'.format(cmd, okay_data), cmd, okay_data) + return len(data) def Okay(self): + """TODO + + .. image:: _static/adb.adb_protocol._AdbConnection.Okay.CALL_GRAPH.svg + + .. image:: _static/adb.adb_protocol._AdbConnection.Okay.CALLER_GRAPH.svg + + """ self._Send(b'OKAY', arg0=self.local_id, arg1=self.remote_id) def ReadUntil(self, *expected_cmds): - """Read a packet, Ack any write packets.""" - cmd, remote_id, local_id, data = AdbMessage.Read( - self.usb, expected_cmds, self.timeout_ms) - if local_id != 0 and self.local_id != local_id: + """Read a packet, Ack any write packets. + + .. image:: _static/adb.adb_protocol._AdbConnection.ReadUntil.CALL_GRAPH.svg + + .. image:: _static/adb.adb_protocol._AdbConnection.ReadUntil.CALLER_GRAPH.svg + + Parameters + ---------- + *expected_cmds : TODO + TODO + + Returns + ------- + cmd : TODO + TODO + data : TODO + TODO + + Raises + ------ + adb.adb_protocol.InterleavedDataError + We don't support multiple streams... + adb.adb_protocol.InvalidResponseError + Incorrect remote id. + + """ + cmd, remote_id, local_id, data = AdbMessage.Read(self.usb, expected_cmds, self.timeout_ms) + + if local_id not in (0, self.local_id): raise InterleavedDataError("We don't support multiple streams...") - if remote_id != 0 and self.remote_id != remote_id: - raise InvalidResponseError( - 'Incorrect remote id, expected %s got %s' % ( - self.remote_id, remote_id)) + + if remote_id not in (0, self.remote_id): + raise InvalidResponseError('Incorrect remote id, expected {0} got {1}'.format(self.remote_id, remote_id)) + # Ack write packets. if cmd == b'WRTE': self.Okay() + return cmd, data def ReadUntilClose(self): - """Yield packets until a Close packet is received.""" + """Yield packets until a ``b'CLSE'`` packet is received. + + .. image:: _static/adb.adb_protocol._AdbConnection.ReadUntilClose.CALL_GRAPH.svg + + Yields + ------ + data : TODO + TODO + + """ while True: cmd, data = self.ReadUntil(b'CLSE', b'WRTE') + if cmd == b'CLSE': self._Send(b'CLSE', arg0=self.local_id, arg1=self.remote_id) break + if cmd != b'WRTE': if cmd == b'FAIL': - raise usb_exceptions.AdbCommandFailureException( - 'Command failed.', data) - raise InvalidCommandError('Expected a WRITE or a CLOSE, got %s (%s)', - cmd, data) + raise usb_exceptions.AdbCommandFailureException('Command failed.', data) + + raise InvalidCommandError('Expected a WRITE or a CLOSE, got {0} ({1})'.format(cmd, data), cmd, data) + yield data def Close(self): + """TODO + + .. image:: _static/adb.adb_protocol._AdbConnection.Close.CALL_GRAPH.svg + + .. image:: _static/adb.adb_protocol._AdbConnection.Close.CALLER_GRAPH.svg + + Raises + ------ + usb_exceptions.AdbCommandFailureException + Command failed. + adb.adb_protocol.InvalidCommandError + Expected a ``CLSE`` response but received something else. + + """ self._Send(b'CLSE', arg0=self.local_id, arg1=self.remote_id) cmd, data = self.ReadUntil(b'CLSE') if cmd != b'CLSE': if cmd == b'FAIL': raise usb_exceptions.AdbCommandFailureException('Command failed.', data) - raise InvalidCommandError('Expected a CLSE response, got %s (%s)', - cmd, data) + raise InvalidCommandError('Expected a CLSE response, got {0} ({1})'.format(cmd, data), cmd, data) class AdbMessage(object): """ADB Protocol and message class. - Protocol Notes + .. rubric:: local_id/remote_id - local_id/remote_id: - Turns out the documentation is host/device ambidextrous, so local_id is the - id for 'the sender' and remote_id is for 'the recipient'. So since we're - only on the host, we'll re-document with host_id and device_id: + Turns out the documentation is host/device ambidextrous, so ``local_id`` is the id for 'the sender' and + ``remote_id`` is for 'the recipient'. So since we're only on the host, we'll re-document with host_id and device_id: + + :: OPEN(host_id, 0, 'shell:XXX') READY/OKAY(device_id, host_id, '') WRITE(0, host_id, 'data') CLOSE(device_id, host_id, '') + + + .. image:: _static/adb.adb_protocol.AdbMessage.__init__.CALLER_GRAPH.svg + + Parameters + ---------- + command : bytes, None + One of: ``[b'SYNC', b'CNXN', b'AUTH', b'OPEN', b'OKAY', b'CLSE', b'WRTE']`` + arg0 : TODO, None + TODO + arg1 : TODO, None + TODO + data : bytes + TODO + + Attributes + ---------- + command : int + The value in :const:`AdbMessage.commands` that corresponds to the ``command`` parameter + commands : dict + A dictionary with keys ``[b'SYNC', b'CNXN', b'AUTH', b'OPEN', b'OKAY', b'CLSE', b'WRTE']``. + connections : int + TODO + constants : dict + A dictionary with values ``[b'SYNC', b'CNXN', b'AUTH', b'OPEN', b'OKAY', b'CLSE', b'WRTE']``. + format : bytes + The format for unpacking the ADB message. + ids : list[bytes] + ``[b'SYNC', b'CNXN', b'AUTH', b'OPEN', b'OKAY', b'CLSE', b'WRTE']`` + """ ids = [b'SYNC', b'CNXN', b'AUTH', b'OPEN', b'OKAY', b'CLSE', b'WRTE'] @@ -195,10 +456,32 @@ def __init__(self, command=None, arg0=None, arg1=None, data=b''): @property def checksum(self): + """TODO + + .. image:: _static/adb.adb_protocol.AdbMessage.checksum.CALL_GRAPH.svg + + .. image:: _static/adb.adb_protocol.AdbMessage.checksum.CALLER_GRAPH.svg + + Returns + ------- + TODO + TODO + + """ return self.CalculateChecksum(self.data) @staticmethod def CalculateChecksum(data): + """TODO + + .. image:: _static/adb.adb_protocol.AdbMessage.CalculateChecksum.CALLER_GRAPH.svg + + Returns + ------- + TODO + TODO + + """ # The checksum is just a sum of all the bytes. I swear. if isinstance(data, bytearray): total = sum(data) @@ -215,198 +498,313 @@ def CalculateChecksum(data): return total & 0xFFFFFFFF def Pack(self): - """Returns this message in an over-the-wire format.""" - return struct.pack(self.format, self.command, self.arg0, self.arg1, - len(self.data), self.checksum, self.magic) + """Returns this message in an over-the-wire format. + + .. image:: _static/adb.adb_protocol.AdbMessage.Pack.CALL_GRAPH.svg + + .. image:: _static/adb.adb_protocol.AdbMessage.Pack.CALLER_GRAPH.svg + + Returns + ------- + bytes + TODO + + """ + return struct.pack(self.format, self.command, self.arg0, self.arg1, len(self.data), self.checksum, self.magic) @classmethod def Unpack(cls, message): + """TODO + + .. image:: _static/adb.adb_protocol.AdbMessage.Unpack.CALLER_GRAPH.svg + + Parameters + ---------- + message : TODO + TODO + + Returns + ------- + cmd : TODO + TODO + arg0 : TODO + TODO + arg1 : TODO + TODO + data_length : TODO + TODO + data_checksum : TODO + TODO + unused_magic : TODO + TODO + + Raises + ------ + ValueError + Unable to unpack the ADB command. + + """ try: - cmd, arg0, arg1, data_length, data_checksum, unused_magic = struct.unpack( - cls.format, message) + cmd, arg0, arg1, data_length, data_checksum, unused_magic = struct.unpack(cls.format, message) except struct.error as e: raise ValueError('Unable to unpack ADB command.', cls.format, message, e) + return cmd, arg0, arg1, data_length, data_checksum def Send(self, usb, timeout_ms=None): - """Send this message over USB.""" + """Send this message over USB. + + .. image:: _static/adb.adb_protocol.AdbMessage.Send.CALL_GRAPH.svg + + Parameters + ---------- + usb : adb.common.TcpHandle, adb.common.UsbHandle + TODO + timeout_ms : int, None + Timeout in milliseconds for USB packets. + + """ usb.BulkWrite(self.Pack(), timeout_ms) usb.BulkWrite(self.data, timeout_ms) @classmethod def Read(cls, usb, expected_cmds, timeout_ms=None, total_timeout_ms=None): - """Receive a response from the device.""" + """Receive a response from the device. + + .. image:: _static/adb.adb_protocol.AdbMessage.Read.CALL_GRAPH.svg + + .. image:: _static/adb.adb_protocol.AdbMessage.Read.CALLER_GRAPH.svg + + Parameters + ---------- + usb : adb.common.TcpHandle, adb.common.UsbHandle + TODO + expected_cmds : TODO + Read until we receive a header ID that is in ``expected_cmds`` + timeout_ms : int, None + Timeout in milliseconds for USB packets. + total_timeout_ms : int, None + The total time to wait for a command in ``expected_cmds`` + + Returns + ------- + command : TODO + TODO + arg0 : TODO + TODO + arg1 : TODO + TODO + bytes + TODO + + Raises + ------ + adb.adb_protocol.InvalidCommandError + Unknown command *or* never got one of the expected responses. + adb.adb_protocol.InvalidChecksumError + Received checksum does not match the expected checksum. + + """ total_timeout_ms = usb.Timeout(total_timeout_ms) start = time.time() + while True: msg = usb.BulkRead(24, timeout_ms) cmd, arg0, arg1, data_length, data_checksum = cls.Unpack(msg) command = cls.constants.get(cmd) if not command: - raise InvalidCommandError( - 'Unknown command: %x' % cmd, cmd, (arg0, arg1)) + raise InvalidCommandError('Unknown command: %x' % cmd, cmd, (arg0, arg1)) + if command in expected_cmds: break if time.time() - start > total_timeout_ms: - raise InvalidCommandError( - 'Never got one of the expected responses (%s)' % expected_cmds, - cmd, (timeout_ms, total_timeout_ms)) + raise InvalidCommandError('Never got one of the expected responses (%s)' % expected_cmds, cmd, (timeout_ms, total_timeout_ms)) if data_length > 0: data = bytearray() while data_length > 0: temp = usb.BulkRead(data_length, timeout_ms) if len(temp) != data_length: - print( - "Data_length {} does not match actual number of bytes read: {}".format(data_length, len(temp))) + print("Data_length {} does not match actual number of bytes read: {}".format(data_length, len(temp))) data += temp data_length -= len(temp) actual_checksum = cls.CalculateChecksum(data) if actual_checksum != data_checksum: - raise InvalidChecksumError( - 'Received checksum %s != %s', (actual_checksum, data_checksum)) + raise InvalidChecksumError('Received checksum {0} != {1}'.format(actual_checksum, data_checksum)) else: data = b'' + return command, arg0, arg1, bytes(data) @classmethod def Connect(cls, usb, banner=b'notadb', rsa_keys=None, auth_timeout_ms=100): """Establish a new connection to the device. - Args: - usb: A USBHandle with BulkRead and BulkWrite methods. - banner: A string to send as a host identifier. - rsa_keys: List of AuthSigner subclass instances to be used for - authentication. The device can either accept one of these via the Sign - method, or we will send the result of GetPublicKey from the first one - if the device doesn't accept any of them. - auth_timeout_ms: Timeout to wait for when sending a new public key. This - is only relevant when we send a new public key. The device shows a - dialog and this timeout is how long to wait for that dialog. If used - in automation, this should be low to catch such a case as a failure - quickly; while in interactive settings it should be high to allow - users to accept the dialog. We default to automation here, so it's low - by default. - - Returns: - The device's reported banner. Always starts with the state (device, - recovery, or sideload), sometimes includes information after a : with - various product information. - - Raises: - usb_exceptions.DeviceAuthError: When the device expects authentication, - but we weren't given any valid keys. - InvalidResponseError: When the device does authentication in an - unexpected way. + .. image:: _static/adb.adb_protocol.AdbMessage.Connect.CALL_GRAPH.svg + + Parameters + ---------- + usb : adb.common.TcpHandle, adb.common.UsbHandle + A :class:`adb.common.TcpHandle` or :class:`adb.common.UsbHandle` instance with ``BulkRead`` and ``BulkWrite`` methods. + banner : str + A string to send as a host identifier. + rsa_keys : list[adb_protocol.AuthSigner] + List of :class:`AuthSigner` subclass instances to be used for authentication. The device can either accept one of + these via the ``Sign`` method, or we will send the result of ``GetPublicKey`` from the first one if the + device doesn't accept any of them. + auth_timeout_ms : int + Timeout to wait for when sending a new public key. This + is only relevant when we send a new public key. The device shows a + dialog and this timeout is how long to wait for that dialog. If used + in automation, this should be low to catch such a case as a failure + quickly; while in interactive settings it should be high to allow + users to accept the dialog. We default to automation here, so it's low + by default. + + Returns + ------- + banner : TODO + The device's reported banner. Always starts with the state (device, recovery, or sideload), sometimes + includes information after a : with various product information. + + Raises + ------ + adb.usb_exceptions.DeviceAuthError + When the device expects authentication, but we weren't given any valid keys. + adb.adb_protocol.InvalidResponseError + When the device does authentication in an unexpected way. + usb_exceptions.ReadFailedError + TODO + """ # In py3, convert unicode to bytes. In py2, convert str to bytes. # It's later joined into a byte string, so in py2, this ends up kind of being a no-op. if isinstance(banner, str): banner = bytearray(banner, 'utf-8') - msg = cls( - command=b'CNXN', arg0=VERSION, arg1=MAX_ADB_DATA, - data=b'host::%s\0' % banner) + msg = cls(command=b'CNXN', arg0=VERSION, arg1=MAX_ADB_DATA, data=b'host::%s\0' % banner) msg.Send(usb) cmd, arg0, arg1, banner = cls.Read(usb, [b'CNXN', b'AUTH']) if cmd == b'AUTH': if not rsa_keys: - raise usb_exceptions.DeviceAuthError( - 'Device authentication required, no keys available.') + raise usb_exceptions.DeviceAuthError('Device authentication required, no keys available.') + # Loop through our keys, signing the last 'banner' or token. for rsa_key in rsa_keys: if arg0 != AUTH_TOKEN: - raise InvalidResponseError( - 'Unknown AUTH response: %s %s %s' % (arg0, arg1, banner)) + raise InvalidResponseError('Unknown AUTH response: %s %s %s' % (arg0, arg1, banner)) # Do not mangle the banner property here by converting it to a string signed_token = rsa_key.Sign(banner) - msg = cls( - command=b'AUTH', arg0=AUTH_SIGNATURE, arg1=0, data=signed_token) + msg = cls(command=b'AUTH', arg0=AUTH_SIGNATURE, arg1=0, data=signed_token) msg.Send(usb) cmd, arg0, unused_arg1, banner = cls.Read(usb, [b'CNXN', b'AUTH']) if cmd == b'CNXN': return banner + # None of the keys worked, so send a public key. - msg = cls( - command=b'AUTH', arg0=AUTH_RSAPUBLICKEY, arg1=0, - data=rsa_keys[0].GetPublicKey() + b'\0') + msg = cls(command=b'AUTH', arg0=AUTH_RSAPUBLICKEY, arg1=0, data=rsa_keys[0].GetPublicKey() + b'\0') msg.Send(usb) try: - cmd, arg0, unused_arg1, banner = cls.Read( - usb, [b'CNXN'], timeout_ms=auth_timeout_ms) + cmd, arg0, unused_arg1, banner = cls.Read(usb, [b'CNXN'], timeout_ms=auth_timeout_ms) except usb_exceptions.ReadFailedError as e: if e.usb_error.value == -7: # Timeout. - raise usb_exceptions.DeviceAuthError( - 'Accept auth key on device, then retry.') + raise usb_exceptions.DeviceAuthError('Accept auth key on device, then retry.') + raise + # This didn't time-out, so we got a CNXN response. return banner return banner @classmethod def Open(cls, usb, destination, timeout_ms=None): - """Opens a new connection to the device via an OPEN message. + """Opens a new connection to the device via an ``OPEN`` message. + + Not the same as the posix ``open`` or any other google3 Open methods. + + .. image:: _static/adb.adb_protocol.AdbMessage.Open.CALL_GRAPH.svg - Not the same as the posix 'open' or any other google3 Open methods. + .. image:: _static/adb.adb_protocol.AdbMessage.Open.CALLER_GRAPH.svg - Args: - usb: USB device handle with BulkRead and BulkWrite methods. - destination: The service:command string. - timeout_ms: Timeout in milliseconds for USB packets. + Parameters + ---------- + usb : adb.common.TcpHandle, adb.common.UsbHandle + A :class:`adb.common.TcpHandle` or :class:`adb.common.UsbHandle` instance with ``BulkRead`` and ``BulkWrite`` methods. + destination : TODO + The service:command string. + timeout_ms : int, None + Timeout in milliseconds for USB packets. - Raises: - InvalidResponseError: Wrong local_id sent to us. - InvalidCommandError: Didn't get a ready response. + Returns + ------- + _AdbConnection, None + The local connection id. + + Raises + ------ + adb.adb_protocol.InvalidResponseError + Wrong local_id sent to us. + adb.adb_protocol.InvalidCommandError + Didn't get a ready response. - Returns: - The local connection id. """ local_id = 1 - msg = cls( - command=b'OPEN', arg0=local_id, arg1=0, - data=destination + b'\0') + msg = cls(command=b'OPEN', arg0=local_id, arg1=0, data=destination + b'\0') msg.Send(usb, timeout_ms) - cmd, remote_id, their_local_id, _ = cls.Read(usb, [b'CLSE', b'OKAY'], - timeout_ms=timeout_ms) + cmd, remote_id, their_local_id, _ = cls.Read(usb, [b'CLSE', b'OKAY'], timeout_ms=timeout_ms) + if local_id != their_local_id: - raise InvalidResponseError( - 'Expected the local_id to be {}, got {}'.format(local_id, their_local_id)) + raise InvalidResponseError('Expected the local_id to be {}, got {}'.format(local_id, their_local_id)) + if cmd == b'CLSE': # Some devices seem to be sending CLSE once more after a request, this *should* handle it - cmd, remote_id, their_local_id, _ = cls.Read(usb, [b'CLSE', b'OKAY'], - timeout_ms=timeout_ms) + cmd, remote_id, their_local_id, _ = cls.Read(usb, [b'CLSE', b'OKAY'], timeout_ms=timeout_ms) # Device doesn't support this service. if cmd == b'CLSE': return None + if cmd != b'OKAY': - raise InvalidCommandError('Expected a ready response, got {}'.format(cmd), - cmd, (remote_id, their_local_id)) + raise InvalidCommandError('Expected a ready response, got {}'.format(cmd), cmd, (remote_id, their_local_id)) + return _AdbConnection(usb, local_id, remote_id, timeout_ms) @classmethod def Command(cls, usb, service, command='', timeout_ms=None): """One complete set of USB packets for a single command. - Sends service:command in a new connection, reading the data for the + Sends ``service:command`` in a new connection, reading the data for the response. All the data is held in memory, large responses will be slow and can fill up memory. - Args: - usb: USB device handle with BulkRead and BulkWrite methods. - service: The service on the device to talk to. - command: The command to send to the service. - timeout_ms: Timeout for USB packets, in milliseconds. + .. image:: _static/adb.adb_protocol.AdbMessage.Command.CALL_GRAPH.svg + + Parameters + ---------- + usb : adb.common.TcpHandle, adb.common.UsbHandle + A :class:`adb.common.TcpHandle` or :class:`adb.common.UsbHandle` instance with ``BulkRead`` and ``BulkWrite`` methods. + service : TODO + The service on the device to talk to. + command : str + The command to send to the service. + timeout_ms : int, None + Timeout in milliseconds for USB packets. + + Returns + ------- + str + The response from the service. + + Raises + ------ + adb.adb_protocol.InterleavedDataError + Multiple streams running over usb. + adb.adb_protocol.InvalidCommandError + Got an unexpected response command. - Raises: - InterleavedDataError: Multiple streams running over usb. - InvalidCommandError: Got an unexpected response command. - - Returns: - The response from the service. """ return ''.join(cls.StreamingCommand(usb, service, command, timeout_ms)) @@ -414,28 +812,42 @@ def Command(cls, usb, service, command='', timeout_ms=None): def StreamingCommand(cls, usb, service, command='', timeout_ms=None): """One complete set of USB packets for a single command. - Sends service:command in a new connection, reading the data for the + Sends ``service:command`` in a new connection, reading the data for the response. All the data is held in memory, large responses will be slow and can fill up memory. - Args: - usb: USB device handle with BulkRead and BulkWrite methods. - service: The service on the device to talk to. - command: The command to send to the service. - timeout_ms: Timeout for USB packets, in milliseconds. - - Raises: - InterleavedDataError: Multiple streams running over usb. - InvalidCommandError: Got an unexpected response command. + .. image:: _static/adb.adb_protocol.AdbMessage.StreamingCommand.CALL_GRAPH.svg + + .. image:: _static/adb.adb_protocol.AdbMessage.StreamingCommand.CALLER_GRAPH.svg + + Parameters + ---------- + usb : adb.common.TcpHandle, adb.common.UsbHandle + A :class:`adb.common.TcpHandle` or :class:`adb.common.UsbHandle` instance with ``BulkRead`` and ``BulkWrite`` methods. + service : TODO + The service on the device to talk to. + command : str + The command to send to the service. + timeout_ms : int, None + Timeout in milliseconds for USB packets. + + Yields + ------ + str + The responses from the service. + + Raises + ------ + adb.adb_protocol.InterleavedDataError + Multiple streams running over usb. + adb.adb_protocol.InvalidCommandError + Got an unexpected response command. - Yields: - The responses from the service. """ if not isinstance(command, bytes): command = command.encode('utf8') - connection = cls.Open( - usb, destination=b'%s:%s' % (service, command), - timeout_ms=timeout_ms) + + connection = cls.Open(usb, destination=b'%s:%s' % (service, command), timeout_ms=timeout_ms) for data in connection.ReadUntilClose(): yield data.decode('utf8') @@ -444,18 +856,29 @@ def InteractiveShellCommand(cls, conn, cmd=None, strip_cmd=True, delim=None, str """Retrieves stdout of the current InteractiveShell and sends a shell command if provided TODO: Should we turn this into a yield based function so we can stream all output? - Args: - conn: Instance of AdbConnection - cmd: Optional. Command to run on the target. - strip_cmd: Optional (default True). Strip command name from stdout. - delim: Optional. Delimiter to look for in the output to know when to stop expecting more output - (usually the shell prompt) - strip_delim: Optional (default True): Strip the provided delimiter from the output - clean_stdout: Cleanup the stdout stream of any backspaces and the characters that were deleted by the backspace - Returns: - The stdout from the shell command. - """ + .. image:: _static/adb.adb_protocol.AdbMessage.InteractiveShellCommand.CALL_GRAPH.svg + + Parameters + ---------- + conn : AdbConnection + Instance of AdbConnection + cmd : str, None + Command to run on the target. + strip_cmd : bool + Strip command name from stdout. + delim : TODO + Delimiter to look for in the output to know when to stop expecting more output (usually the shell prompt) + strip_delim : bool + Strip the provided delimiter from the output + clean_stdout : bool + Cleanup the stdout stream of any backspaces and the characters that were deleted by the backspace + + Returns + ------- + stdout : TODO + The stdout from the shell command. + """ if delim is not None and not isinstance(delim, bytes): delim = delim.encode('utf-8') @@ -484,7 +907,7 @@ def InteractiveShellCommand(cls, conn, cmd=None, strip_cmd=True, delim=None, str cmd = cmd.encode('utf8') # Send the cmd raw - bytes_written = conn.Write(cmd) + conn.Write(cmd) if delim: # Expect multiple WRTE cmds until the delim (usually terminal prompt) is detected @@ -557,7 +980,7 @@ def InteractiveShellCommand(cls, conn, cmd=None, strip_cmd=True, delim=None, str stdout = stdout.rstrip() - except Exception as e: + except Exception as e: # pylint: disable=broad-except print("InteractiveShell exception (most likely timeout): {}".format(e)) return stdout diff --git a/adb/common.py b/adb/common.py index 0c78728..51a9f84 100644 --- a/adb/common.py +++ b/adb/common.py @@ -11,40 +11,125 @@ # 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. + """Common code for ADB and Fastboot. -Common usb browsing, and usb communication. +Common usb browsing and usb communication. + + +.. rubric:: Contents + +* :func:`GetInterface` +* :func:`InterfaceMatcher` +* :class:`TcpHandle` + + * :meth:`TcpHandle._connect` + * :meth:`TcpHandle.BulkRead` + * :meth:`TcpHandle.BulkWrite` + * :meth:`TcpHandle.Close` + * :meth:`TcpHandle.serial_number` + * :meth:`TcpHandle.Timeout` + * :meth:`TcpHandle.TimeoutSeconds` + +* :class:`UsbHandle` + + * :meth:`UsbHandle.BulkRead` + * :meth:`UsbHandle.BulkReadAsync` + * :meth:`UsbHandle.BulkWrite` + * :meth:`UsbHandle.Close` + * :meth:`UsbHandle.Find` + * :meth:`UsbHandle.FindAndOpen` + * :meth:`UsbHandle.FindDevices` + * :meth:`UsbHandle.FindFirst` + * :meth:`UsbHandle.FlushBuffers` + * :meth:`UsbHandle.Open` + * :meth:`UsbHandle.port_path` + * :meth:`UsbHandle.PortPathMatcher` + * :meth:`UsbHandle.serial_number` + * :meth:`UsbHandle.SerialMatcher` + * :meth:`UsbHandle.Timeout` + * :meth:`UsbHandle.usb_info` + """ + import logging import platform +import re +import select import socket import threading import weakref -import select import libusb1 import usb1 +try: + from libusb1 import LIBUSB_ERROR_NOT_FOUND, LIBUSB_ERROR_TIMEOUT # pylint: disable=ungrouped-imports +except ImportError: # pragma: no cover + LIBUSB_ERROR_NOT_FOUND = 'LIBUSB_ERROR_NOT_FOUND' + LIBUSB_ERROR_TIMEOUT = 'LIBUSB_ERROR_TIMEOUT' + from adb import usb_exceptions + +#: Default timeout DEFAULT_TIMEOUT_MS = 10000 +SYSFS_PORT_SPLIT_RE = re.compile("[,/:.-]") + _LOG = logging.getLogger('android_usb') def GetInterface(setting): - """Get the class, subclass, and protocol for the given USB setting.""" + """Get the class, subclass, and protocol for the given USB setting. + + .. image:: _static/adb.common.GetInterface.CALLER_GRAPH.svg + + Parameters + ---------- + setting : TODO + TODO + + Returns + ------- + TODO + TODO + TODO + TODO + TODO + TODO + + """ return (setting.getClass(), setting.getSubClass(), setting.getProtocol()) def InterfaceMatcher(clazz, subclass, protocol): - """Returns a matcher that returns the setting with the given interface.""" + """Returns a matcher that returns the setting with the given interface. + + .. image:: _static/adb.common.InterfaceMatcher.CALL_GRAPH.svg + + Parameters + ---------- + clazz : TODO + TODO + subclass : TODO + TODO + protocol : TODO + TODO + + Returns + ------- + Matcher : function + TODO + + """ interface = (clazz, subclass, protocol) def Matcher(device): for setting in device.iterSettings(): if GetInterface(setting) == interface: return setting + return None return Matcher @@ -56,33 +141,76 @@ class UsbHandle(object): and interface claiming. Important methods: - FlushBuffers() - BulkRead(int length) - BulkWrite(bytes data) - """ + * `UsbHandle.FlushBuffers` + * `UsbHandle.BulkRead` + * `UsbHandle.BulkWrite(bytes data)` + + .. image:: _static/adb.common.UsbHandle.__init__.CALLER_GRAPH.svg + + Parameters + ---------- + device : TODO + libusb_device to connect to. + setting : TODO + libusb setting with the correct endpoints to communicate with. + usb_info : TODO, None + String describing the usb path/serial/device, for debugging. + timeout_ms : TODO, None + Timeout in milliseconds for all I/O. + + Attributes + ---------- + _device : TODO + libusb_device to connect to. + _handle : TODO + TODO + _interface_number : TODO + TODO + _max_read_packet_len : TODO + TODO + _read_endpoint : TODO + TODO + _setting : TODO + libusb setting with the correct endpoints to communicate with. + _timeout_ms : TODO, None + Timeout in milliseconds for all I/O. + _usb_info : TODO + String describing the usb path/serial/device, for debugging. + _write_endpoint : TODO, None + TODO + """ _HANDLE_CACHE = weakref.WeakValueDictionary() _HANDLE_CACHE_LOCK = threading.Lock() def __init__(self, device, setting, usb_info=None, timeout_ms=None): - """Initialize USB Handle. - - Arguments: - device: libusb_device to connect to. - setting: libusb setting with the correct endpoints to communicate with. - usb_info: String describing the usb path/serial/device, for debugging. - timeout_ms: Timeout in milliseconds for all I/O. - """ + """Initialize USB Handle.""" self._setting = setting self._device = device self._handle = None + self._interface_number = None + self._read_endpoint = None + self._write_endpoint = None + self._usb_info = usb_info or '' self._timeout_ms = timeout_ms if timeout_ms else DEFAULT_TIMEOUT_MS self._max_read_packet_len = 0 @property def usb_info(self): + """TODO + + .. image:: _static/adb.common.UsbHandle.usb_info.CALL_GRAPH.svg + + .. image:: _static/adb.common.UsbHandle.usb_info.CALLER_GRAPH.svg + + Returns + ------- + TODO + TODO + + """ try: sn = self.serial_number except libusb1.USBError: @@ -92,7 +220,11 @@ def usb_info(self): return self._usb_info def Open(self): - """Opens the USB device for this setting, and claims the interface.""" + """Opens the USB device for this setting, and claims the interface. + + .. image:: _static/adb.common.UsbHandle.Open.CALL_GRAPH.svg + + """ # Make sure we close any previous handle open to this usb device. port_path = tuple(self.port_path) with self._HANDLE_CACHE_LOCK: @@ -117,11 +249,10 @@ def Open(self): handle = self._device.open() iface_number = self._setting.getNumber() try: - if (platform.system() != 'Windows' - and handle.kernelDriverActive(iface_number)): + if (platform.system() != 'Windows' and handle.kernelDriverActive(iface_number)): handle.detachKernelDriver(iface_number) except libusb1.USBError as e: - if e.value == libusb1.LIBUSB_ERROR_NOT_FOUND: + if e.value == LIBUSB_ERROR_NOT_FOUND: _LOG.warning('Kernel driver not found for interface: %s.', iface_number) else: raise @@ -136,13 +267,40 @@ def Open(self): @property def serial_number(self): + """TODO + + .. image:: _static/adb.common.UsbHandle.serial_number.CALLER_GRAPH.svg + + Returns + ------- + TODO + TODO + + """ return self._device.getSerialNumber() @property def port_path(self): + """TODO + + .. image:: _static/adb.common.UsbHandle.port_path.CALLER_GRAPH.svg + + Returns + ------- + TODO + TODO + + """ return [self._device.getBusNumber()] + self._device.getPortNumberList() def Close(self): + """TODO + + .. image:: _static/adb.common.UsbHandle.Close.CALL_GRAPH.svg + + .. image:: _static/adb.common.UsbHandle.Close.CALLER_GRAPH.svg + + """ if self._handle is None: return try: @@ -155,53 +313,144 @@ def Close(self): self._handle = None def Timeout(self, timeout_ms): + """TODO + + .. image:: _static/adb.common.UsbHandle.Timeout.CALLER_GRAPH.svg + + Returns + ------- + TODO + TODO + + """ return timeout_ms if timeout_ms is not None else self._timeout_ms def FlushBuffers(self): + """TODO + + .. image:: _static/adb.common.UsbHandle.FlushBuffers.CALL_GRAPH.svg + + Raises + ------ + adb.usb_exceptions.ReadFailedError + TODO + + """ while True: try: self.BulkRead(self._max_read_packet_len, timeout_ms=10) except usb_exceptions.ReadFailedError as e: - if e.usb_error.value == libusb1.LIBUSB_ERROR_TIMEOUT: + if e.usb_error.value == LIBUSB_ERROR_TIMEOUT: break raise def BulkWrite(self, data, timeout_ms=None): + """TODO + + .. image:: _static/adb.common.UsbHandle.BulkWrite.CALL_GRAPH.svg + + Parameters + ---------- + data : bytes + TODO + timeout_ms : TODO, None + TODO + + Returns + ------- + TODO + TODO + + Raises + ------ + adb.usb_exceptions.WriteFailedError + This handle has been closed, probably due to another being opened + adb.usb_exceptions.WriteFailedError + Could not send data + + """ if self._handle is None: - raise usb_exceptions.WriteFailedError( - 'This handle has been closed, probably due to another being opened.', - None) + raise usb_exceptions.WriteFailedError('This handle has been closed, probably due to another being opened.', None) + try: - return self._handle.bulkWrite( - self._write_endpoint, data, timeout=self.Timeout(timeout_ms)) + return self._handle.bulkWrite(self._write_endpoint, data, timeout=self.Timeout(timeout_ms)) + except libusb1.USBError as e: - raise usb_exceptions.WriteFailedError( - 'Could not send data to %s (timeout %sms)' % ( - self.usb_info, self.Timeout(timeout_ms)), e) + raise usb_exceptions.WriteFailedError('Could not send data to %s (timeout %sms)' % (self.usb_info, self.Timeout(timeout_ms)), e) def BulkRead(self, length, timeout_ms=None): + """TODO + + .. image:: _static/adb.common.UsbHandle.BulkRead.CALL_GRAPH.svg + + .. image:: _static/adb.common.UsbHandle.BulkRead.CALLER_GRAPH.svg + + Parameters + ---------- + length : int + TODO + timeout_ms : TODO, None + TODO + + Returns + ------- + bytearray + TODO + + Raises + ------ + usb_exceptions.ReadFailedError + Could not receive data + + """ if self._handle is None: - raise usb_exceptions.ReadFailedError( - 'This handle has been closed, probably due to another being opened.', - None) + raise usb_exceptions.ReadFailedError('This handle has been closed, probably due to another being opened.', None) try: # python-libusb1 > 1.6 exposes bytearray()s now instead of bytes/str. # To support older and newer versions, we ensure everything's bytearray() # from here on out. - return bytearray(self._handle.bulkRead( - self._read_endpoint, length, timeout=self.Timeout(timeout_ms))) + return bytearray(self._handle.bulkRead(self._read_endpoint, length, timeout=self.Timeout(timeout_ms))) except libusb1.USBError as e: - raise usb_exceptions.ReadFailedError( - 'Could not receive data from %s (timeout %sms)' % ( - self.usb_info, self.Timeout(timeout_ms)), e) + raise usb_exceptions.ReadFailedError('Could not receive data from %s (timeout %sms)' % (self.usb_info, self.Timeout(timeout_ms)), e) def BulkReadAsync(self, length, timeout_ms=None): + """TODO + + Parameters + ---------- + length : int + TODO + timeout_ms : TODO, None + TODO + + Raises + ------ + NotImplementedError + This is always raised because this method is not implemented. + + """ # See: https://pypi.python.org/pypi/libusb1 "Asynchronous I/O" section - return + raise NotImplementedError @classmethod def PortPathMatcher(cls, port_path): - """Returns a device matcher for the given port path.""" + """Returns a device matcher for the given port path. + + .. image:: _static/adb.common.UsbHandle.SerialMatcher.CALL_GRAPH.svg + + .. image:: _static/adb.common.UsbHandle.PortPathMatcher.CALLER_GRAPH.svg + + Parameters + ---------- + port_path : TODO + TODO + + Returns + ------- + function + TODO + + """ if isinstance(port_path, str): # Convert from sysfs path to port_path. port_path = [int(part) for part in SYSFS_PORT_SPLIT_RE.split(port_path)] @@ -209,22 +458,78 @@ def PortPathMatcher(cls, port_path): @classmethod def SerialMatcher(cls, serial): - """Returns a device matcher for the given serial.""" + """Returns a device matcher for the given serial. + + .. image:: _static/adb.common.UsbHandle.SerialMatcher.CALLER_GRAPH.svg + + Parameters + ---------- + serial : TODO + TODO + + Returns + ------- + function + TODO + + """ return lambda device: device.serial_number == serial @classmethod - def FindAndOpen(cls, setting_matcher, - port_path=None, serial=None, timeout_ms=None): - dev = cls.Find( - setting_matcher, port_path=port_path, serial=serial, - timeout_ms=timeout_ms) + def FindAndOpen(cls, setting_matcher, port_path=None, serial=None, timeout_ms=None): + """TODO + + .. image:: _static/adb.common.UsbHandle.FindAndOpen.CALL_GRAPH.svg + + .. image:: _static/adb.common.UsbHandle.FindAndOpen.CALLER_GRAPH.svg + + Parameters + ---------- + setting_matcher : TODO + TODO + port_path : TODO, None + TODO + serial : TODO, None + TODO + timeout_ms : TODO, None + TODO + + Returns + ------- + dev : TODO + TODO + + """ + dev = cls.Find(setting_matcher, port_path=port_path, serial=serial, timeout_ms=timeout_ms) dev.Open() dev.FlushBuffers() return dev @classmethod def Find(cls, setting_matcher, port_path=None, serial=None, timeout_ms=None): - """Gets the first device that matches according to the keyword args.""" + """Gets the first device that matches according to the keyword args. + + .. image:: _static/adb.common.UsbHandle.Find.CALL_GRAPH.svg + + .. image:: _static/adb.common.UsbHandle.Find.CALLER_GRAPH.svg + + Parameters + ---------- + setting_matcher : TODO + TODO + port_path : TODO, None + TODO + serial : TODO, None + TODO + timeout_ms : TODO, None + TODO + + Returns + ------- + TODO + TODO + + """ if port_path: device_matcher = cls.PortPathMatcher(port_path) usb_info = port_path @@ -234,46 +539,66 @@ def Find(cls, setting_matcher, port_path=None, serial=None, timeout_ms=None): else: device_matcher = None usb_info = 'first' - return cls.FindFirst(setting_matcher, device_matcher, - usb_info=usb_info, timeout_ms=timeout_ms) + return cls.FindFirst(setting_matcher, device_matcher, usb_info=usb_info, timeout_ms=timeout_ms) @classmethod def FindFirst(cls, setting_matcher, device_matcher=None, **kwargs): """Find and return the first matching device. - Args: - setting_matcher: See cls.FindDevices. - device_matcher: See cls.FindDevices. - **kwargs: See cls.FindDevices. + .. image:: _static/adb.common.UsbHandle.FindFirst.CALL_GRAPH.svg + + .. image:: _static/adb.common.UsbHandle.FindFirst.CALLER_GRAPH.svg + + Parameters + ---------- + setting_matcher : TODO + See :meth:`UsbHandle.FindDevices`. + device_matcher : TODO + See :meth:`UsbHandle.FindDevices`. + **kwargs : TODO + See :meth:`UsbHandle.FindDevices`. - Returns: - An instance of UsbHandle. + Returns + ------- + TODO + An instance of UsbHandle. + + Raises + ------ + adb.usb_exceptions.DeviceNotFoundError + Raised if the device is not available. - Raises: - DeviceNotFoundError: Raised if the device is not available. """ try: - return next(cls.FindDevices( - setting_matcher, device_matcher=device_matcher, **kwargs)) + return next(cls.FindDevices(setting_matcher, device_matcher=device_matcher, **kwargs)) except StopIteration: - raise usb_exceptions.DeviceNotFoundError( - 'No device available, or it is in the wrong configuration.') + raise usb_exceptions.DeviceNotFoundError('No device available, or it is in the wrong configuration.') @classmethod def FindDevices(cls, setting_matcher, device_matcher=None, usb_info='', timeout_ms=None): """Find and yield the devices that match. - Args: - setting_matcher: Function that returns the setting to use given a - usb1.USBDevice, or None if the device doesn't have a valid setting. - device_matcher: Function that returns True if the given UsbHandle is - valid. None to match any device. - usb_info: Info string describing device(s). - timeout_ms: Default timeout of commands in milliseconds. + .. image:: _static/adb.common.UsbHandle.FindDevices.CALLER_GRAPH.svg + + Parameters + ---------- + setting_matcher : TODO + Function that returns the setting to use given a ``usb1.USBDevice``, or ``None`` + if the device doesn't have a valid setting. + device_matcher : TODO, None + Function that returns ``True`` if the given ``UsbHandle`` is + valid. ``None`` to match any device. + usb_info : str + Info string describing device(s). + timeout_ms : TODO, None + Default timeout of commands in milliseconds. + + Yields + ------ + TODO + UsbHandle instances - Yields: - UsbHandle instances """ ctx = usb1.USBContext() for device in ctx.getDeviceList(skip_on_error=True): @@ -289,15 +614,32 @@ def FindDevices(cls, setting_matcher, device_matcher=None, class TcpHandle(object): """TCP connection object. - Provides same interface as UsbHandle. """ + Provides same interface as `UsbHandle`. + + .. image:: _static/adb.common.TcpHandle.__init__.CALLER_GRAPH.svg + + Parameters + ---------- + serial : str, bytes, bytearray + Android device serial of the form "host" or "host:port". (Host may be an IP address or a host name.) + timeout_ms : TODO, None + TODO + + Attributes + ---------- + _connection : TODO, None + TODO + _serial_number : str + ``:`` + _timeout_ms : float, None + TODO + host : str, TODO + TODO + port : str, int, TODO + TODO + """ def __init__(self, serial, timeout_ms=None): - """Initialize the TCP Handle. - Arguments: - serial: Android device serial of the form host or host:port. - - Host may be an IP address or a host name. - """ # if necessary, convert serial to a unicode string if isinstance(serial, (bytes, bytearray)): serial = serial.decode('utf-8') @@ -315,40 +657,136 @@ def __init__(self, serial, timeout_ms=None): self._connect() def _connect(self): + """TODO + + .. image:: _static/adb.common.TcpHandle._connect.CALL_GRAPH.svg + + """ timeout = self.TimeoutSeconds(self._timeout_ms) - self._connection = socket.create_connection((self.host, self.port), - timeout=timeout) + self._connection = socket.create_connection((self.host, self.port), timeout=timeout) if timeout: self._connection.setblocking(0) @property def serial_number(self): + """TODO + + .. image:: _static/adb.common.TcpHandle.serial_number.CALLER_GRAPH.svg + + Returns + ------- + self._serial_number : str + The ``_serial_number`` attribute (``:``) + + """ return self._serial_number def BulkWrite(self, data, timeout=None): + """TODO + + .. image:: _static/adb.common.TcpHandle.BulkWrite.CALL_GRAPH.svg + + Parameters + ---------- + data : TODO + TODO + timeout : TODO, None + TODO + + Returns + ------- + TODO + TODO + + Raises + ------ + adb.usb_exceptions.TcpTimeoutException + Sending data timed out. No data was sent. + + """ t = self.TimeoutSeconds(timeout) _, writeable, _ = select.select([], [self._connection], [], t) if writeable: return self._connection.send(data) - msg = 'Sending data to {} timed out after {}s. No data was sent.'.format( - self.serial_number, t) + msg = 'Sending data to {} timed out after {}s. No data was sent.'.format(self.serial_number, t) raise usb_exceptions.TcpTimeoutException(msg) def BulkRead(self, numbytes, timeout=None): + """TODO + + .. image:: _static/adb.common.TcpHandle.BulkRead.CALL_GRAPH.svg + + Parameters + ---------- + numbytes : int + TODO + timeout_ms : TODO, None + TODO + + Returns + ------- + TODO + TODO + + Raises + ------ + adb.usb_exceptions.TcpTimeoutException + Reading timed out. + + """ t = self.TimeoutSeconds(timeout) readable, _, _ = select.select([self._connection], [], [], t) if readable: return self._connection.recv(numbytes) - msg = 'Reading from {} timed out (Timeout {}s)'.format( - self._serial_number, t) + msg = 'Reading from {} timed out (Timeout {}s)'.format(self._serial_number, t) raise usb_exceptions.TcpTimeoutException(msg) def Timeout(self, timeout_ms): + """TODO + + .. image:: _static/adb.common.TcpHandle.Timeout.CALLER_GRAPH.svg + + Parameters + ---------- + timeout_ms : TODO + TODO + + Returns + ------- + float + TODO + + """ return float(timeout_ms) if timeout_ms is not None else self._timeout_ms def TimeoutSeconds(self, timeout_ms): + """TODO + + .. image:: _static/adb.common.TcpHandle.TimeoutSeconds.CALL_GRAPH.svg + + .. image:: _static/adb.common.TcpHandle.TimeoutSeconds.CALLER_GRAPH.svg + + Parameters + ---------- + timeout_ms : TODO + TODO + + Returns + ------- + float + TODO + + """ timeout = self.Timeout(timeout_ms) return timeout / 1000.0 if timeout is not None else timeout def Close(self): + """TODO + + Returns + ------- + TODO + TODO + + """ return self._connection.close() diff --git a/adb/common_cli.py b/adb/common_cli.py index b4ab5e8..83f972f 100644 --- a/adb/common_cli.py +++ b/adb/common_cli.py @@ -11,12 +11,26 @@ # 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. + """Common code for ADB and Fastboot CLI. Usage introspects the given class for methods, args, and docs to show the user. -StartCli handles connecting to a device, calling the expected method, and +:func:`StartCli` handles connecting to a device, calling the expected method, and outputting the results. + + +.. rubric:: Contents + +* :func:`_DocToArgs` +* :class:`_PortPathAction` +* :func:`_RunMethod` +* :func:`GetCommonArguments` +* :func:`GetDeviceArguments` +* :func:`MakeSubparser` +* :class:`PositionalArg` +* :func:`StartCli` + """ from __future__ import print_function @@ -32,68 +46,130 @@ class _PortPathAction(argparse.Action): + """TODO + + .. image:: _static/adb.common_cli._PortPathAction.CALL_GRAPH.svg + + """ def __call__(self, parser, namespace, values, option_string=None): - setattr( - namespace, self.dest, - [int(i) for i in values.replace('/', ',').split(',')]) + setattr(namespace, self.dest, [int(i) for i in values.replace('/', ',').split(',')]) class PositionalArg(argparse.Action): + """A positional CLI argument. + + .. image:: _static/adb.common_cli.PositionalArg.CALL_GRAPH.svg + + """ def __call__(self, parser, namespace, values, option_string=None): namespace.positional.append(values) def GetDeviceArguments(): + """Return a parser for device-related CLI commands. + + Returns + ------- + group : argparse.ArgumentParser + A parser for device-related CLI commands. + + """ group = argparse.ArgumentParser('Device', add_help=False) - group.add_argument( - '--timeout_ms', default=10000, type=int, metavar='10000', - help='Timeout in milliseconds.') - group.add_argument( - '--port_path', action=_PortPathAction, - help='USB port path integers (eg 1,2 or 2,1,1)') - group.add_argument( - '-s', '--serial', - help='Device serial to look for (host:port or USB serial)') + group.add_argument('--timeout_ms', default=10000, type=int, metavar='10000', help='Timeout in milliseconds.') + group.add_argument('--port_path', action=_PortPathAction, help='USB port path integers (eg 1,2 or 2,1,1)') + group.add_argument('-s', '--serial', help='Device serial to look for (host:port or USB serial)') + return group def GetCommonArguments(): + """Return a parser for common CLI commands. + + Returns + ------- + group : argparse.ArgumentParser + A parser for common CLI commands. + + """ group = argparse.ArgumentParser('Common', add_help=False) group.add_argument('--verbose', action='store_true', help='Enable logging') return group def _DocToArgs(doc): - """Converts a docstring documenting arguments into a dict.""" - m = None + """Converts a docstring documenting arguments into a dict. + + .. image:: _static/adb.common_cli._DocToArgs.CALLER_GRAPH.svg + + Parameters + ---------- + doc : str + The docstring for a method; see `MakeSubparser`. + + Returns + ------- + out : dict + A dictionary of arguments and their descriptions from the docstring ``doc``. + + """ offset = None - in_arg = False + param = None out = {} + for l in doc.splitlines(): - if l.strip() == 'Args:': - in_arg = True - elif in_arg: - if not l.strip(): + if l.strip() == 'Parameters': + offset = len(l.rstrip()) - len(l.strip()) + + elif offset: + # The "----------" line + if l.strip() == '-' * len('Parameters'): + continue + + if l.strip() in ['Returns', 'Yields', 'Raises']: break - if offset is None: - offset = len(l) - len(l.lstrip()) - l = l[offset:] - if l[0] == ' ' and m: - out[m.group(1)] += ' ' + l.lstrip() - else: - m = re.match(r'^([a-z_]+): (.+)$', l.strip()) - out[m.group(1)] = m.group(2) + + # start of a parameter + if len(l.rstrip()) - len(l.strip()) == offset: + param = l.strip().split()[0] + out[param] = '' + + # add to a parameter + elif l.strip(): + if out[param]: + out[param] += ' ' + l.strip() + else: + out[param] = l.strip() + return out def MakeSubparser(subparsers, parents, method, arguments=None): - """Returns an argparse subparser to create a 'subcommand' to adb.""" + """Returns an argparse subparser to create a 'subcommand' to adb. + + .. image:: _static/adb.common_cli.MakeSubparser.CALL_GRAPH.svg + + Parameters + ---------- + subparsers : TODO + TODO + parents : TODO + TODO + method : TODO + TODO + arguments : TODO, None + TODO + + Returns + ------- + subparser : TODO + TODO + + """ name = ('-'.join(re.split(r'([A-Z][a-z]+)', method.__name__)[1:-1:2])).lower() - help = method.__doc__.splitlines()[0] - subparser = subparsers.add_parser( - name=name, description=help, help=help.rstrip('.'), parents=parents) + help = method.__doc__.splitlines()[0] # pylint: disable=redefined-builtin + subparser = subparsers.add_parser(name=name, description=help, help=help.rstrip('.'), parents=parents) subparser.set_defaults(method=method, positional=[]) - argspec = inspect.getargspec(method) + argspec = inspect.getfullargspec(method) # Figure out positionals and default argument, if any. Explicitly includes # arguments that default to '' but excludes arguments that default to None. @@ -122,7 +198,25 @@ def MakeSubparser(subparsers, parents, method, arguments=None): def _RunMethod(dev, args, extra): - """Runs a method registered via MakeSubparser.""" + """Runs a method registered via :func:`MakeSubparser`. + + .. image:: _static/adb.common_cli._RunMethod.CALLER_GRAPH.svg + + Parameters + ---------- + dev : TODO + TODO + args : TODO + TODO + extra : TODO + TODO + + Returns + ------- + int + 0 + + """ logging.info('%s(%s)', args.method.__name__, ', '.join(args.positional)) result = args.method(dev, *args.positional, **extra) if result is not None: @@ -144,7 +238,29 @@ def _RunMethod(dev, args, extra): def StartCli(args, adb_commands, extra=None, **device_kwargs): - """Starts a common CLI interface for this usb path and protocol.""" + """Starts a common CLI interface for this usb path and protocol. + + Handles connecting to a device, calling the expected method, and outputting the results. + + .. image:: _static/adb.common_cli.StartCli.CALL_GRAPH.svg + + Parameters + ---------- + args : TODO + TODO + adb_commands : TODO + TODO + extra : TODO, None + TODO + **device_kwargs : TODO + TODO + + Returns + ------- + TODO + TODO + + """ try: dev = adb_commands() dev.ConnectDevice(port_path=args.port_path, serial=args.serial, default_timeout_ms=args.timeout_ms, diff --git a/adb/debug.py b/adb/debug.py new file mode 100644 index 0000000..80372d8 --- /dev/null +++ b/adb/debug.py @@ -0,0 +1,23 @@ +"""TEMPORARY. + +""" + + +TRUE = True # pragma: no cover +FALSE = False # pragma: no cover +PRINTABLE_TYPES = (int, float, str, bool, bytes, bytearray, type(None)) # pragma: no cover + + +def debug_print(name, var): # pragma: no cover + """Print debugging info.""" + if isinstance(var, PRINTABLE_TYPES): + print("type({}) = {}, value = {}".format(name, type(var).__name__, var)) + elif isinstance(var, (tuple, list)): + if not var: + print("type({}) = {}, value = {}".format(name, type(var).__name__, var)) + elif isinstance(var[0], PRINTABLE_TYPES): + print("type({}) = {}[{}], value = {}".format(name, type(var).__name__, type(var[0]).__name__, var)) + else: + print("type({}) = {}[{}]".format(name, type(var).__name__, type(var[0]).__name__)) + else: + print("type({}) = {}".format(name, type(var).__name__)) diff --git a/adb/fastboot.py b/adb/fastboot.py index 1507494..f05d107 100644 --- a/adb/fastboot.py +++ b/adb/fastboot.py @@ -11,7 +11,46 @@ # 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. -"""A libusb1-based fastboot implementation.""" + +"""A libusb1-based fastboot implementation. + + +.. rubric:: Contents + +* :class:`FastbootCommands` + + * :meth:`FastbootCommands.__reset` + * :meth:`FastbootCommands._SimpleCommand` + * :meth:`FastbootCommands.Close` + * :meth:`FastbootCommands.ConnectDevice` + * :meth:`FastbootCommands.Continue` + * :meth:`FastbootCommands.Devices` + * :meth:`FastbootCommands.Download` + * :meth:`FastbootCommands.Erase` + * :meth:`FastbootCommands.Flash` + * :meth:`FastbootCommands.FlashFromFile` + * :meth:`FastbootCommands.Getvar` + * :meth:`FastbootCommands.Oem` + * :meth:`FastbootCommands.Reboot` + * :meth:`FastbootCommands.RebootBootloader` + * :meth:`FastbootCommands.usb_handle` + +* :class:`FastbootInvalidResponse` +* :class:`FastbootProtocol` + + * :meth:`FastbootProtocol._AcceptResponses` + * :meth:`FastbootProtocol._HandleProgress` + * :meth:`FastbootProtocol._Write` + * :meth:`FastbootProtocol.HandleDataSending` + * :meth:`FastbootProtocol.HandleSimpleResponses` + * :meth:`FastbootProtocol.SendCommand` + * :meth:`FastbootProtocol.usb_handle` + +* :class:`FastbootRemoteFailure` +* :class:`FastbootStateMismatch` +* :class:`FastbootTransferError` + +""" import binascii import collections @@ -25,63 +64,113 @@ _LOG = logging.getLogger('fastboot') -DEFAULT_MESSAGE_CALLBACK = lambda m: logging.info('Got %s from device', m) -FastbootMessage = collections.namedtuple( # pylint: disable=invalid-name - 'FastbootMessage', ['message', 'header']) +#: TODO +DEFAULT_MESSAGE_CALLBACK = lambda m: logging.info('Got %s from device', m) # noqa: E731 -# From fastboot.c +#: FastbootMessage +FastbootMessage = collections.namedtuple('FastbootMessage', ['message', 'header']) # pylint: disable=invalid-name + +#: From fastboot.c VENDORS = {0x18D1, 0x0451, 0x0502, 0x0FCE, 0x05C6, 0x22B8, 0x0955, 0x413C, 0x2314, 0x0BB4, 0x8087} + +#: From fastboot.c CLASS = 0xFF + +#: From fastboot.c SUBCLASS = 0x42 + +#: From fastboot.c PROTOCOL = 0x03 -# pylint: disable=invalid-name -DeviceIsAvailable = common.InterfaceMatcher(CLASS, SUBCLASS, PROTOCOL) + +#: TODO +DeviceIsAvailable = common.InterfaceMatcher(CLASS, SUBCLASS, PROTOCOL) # pylint: disable=invalid-name # pylint doesn't understand cross-module exception baseclasses. -# pylint: disable=nonstandard-exception +# pylint: disable=bad-option-value class FastbootTransferError(usb_exceptions.FormatMessageWithArgumentsException): - """Transfer error.""" + """Transfer error. + + .. image:: _static/adb.fastboot.FastbootTransferError.CALL_GRAPH.svg + + """ class FastbootRemoteFailure(usb_exceptions.FormatMessageWithArgumentsException): - """Remote error.""" + """Remote error. + + .. image:: _static/adb.fastboot.FastbootRemoteFailure.CALL_GRAPH.svg + + """ class FastbootStateMismatch(usb_exceptions.FormatMessageWithArgumentsException): - """Fastboot and uboot's state machines are arguing. You Lose.""" + """Fastboot and uboot's state machines are arguing. You Lose. + .. image:: _static/adb.fastboot.FastbootStateMismatch.CALL_GRAPH.svg -class FastbootInvalidResponse( - usb_exceptions.FormatMessageWithArgumentsException): - """Fastboot responded with a header we didn't expect.""" + """ + + +class FastbootInvalidResponse(usb_exceptions.FormatMessageWithArgumentsException): + """Fastboot responded with a header we didn't expect. + + .. image:: _static/adb.fastboot.FastbootInvalidResponse.CALL_GRAPH.svg + + """ class FastbootProtocol(object): - """Encapsulates the fastboot protocol.""" + """Encapsulates the fastboot protocol. + + .. image:: _static/adb.fastboot.FastbootProtocol.__init__.CALLER_GRAPH.svg + + Parameters + ---------- + usb : adb.common.UsbHandle + :class:`adb.common.UsbHandle` instance. + chunk_kb : int + Packet size. For older devices, 4 may be required. + + Attributes + ---------- + chunk_kb : int + Packet size. For older devices, 4 may be required. + usb : adb.common.UsbHandle + :class:`adb.common.UsbHandle` instance. + + """ FINAL_HEADERS = {b'OKAY', b'DATA'} def __init__(self, usb, chunk_kb=1024): - """Constructs a FastbootProtocol instance. - - Args: - usb: UsbHandle instance. - chunk_kb: Packet size. For older devices, 4 may be required. - """ self.usb = usb self.chunk_kb = chunk_kb @property def usb_handle(self): + """TODO + + Returns + ------- + self.usb : adb.common.UsbHandle + :class:`adb.common.UsbHandle` instance. + + """ return self.usb def SendCommand(self, command, arg=None): """Sends a command to the device. - Args: - command: The command to send. - arg: Optional argument to the command. + .. image:: _static/adb.fastboot.FastbootProtocol.SendCommand.CALL_GRAPH.svg + + Parameters + ---------- + command : str + The command to send. + arg : str + Optional argument to the command. + """ if arg is not None: if not isinstance(arg, bytes): @@ -90,16 +179,25 @@ def SendCommand(self, command, arg=None): self._Write(io.BytesIO(command), len(command)) - def HandleSimpleResponses( - self, timeout_ms=None, info_cb=DEFAULT_MESSAGE_CALLBACK): + def HandleSimpleResponses(self, timeout_ms=None, info_cb=DEFAULT_MESSAGE_CALLBACK): """Accepts normal responses from the device. - Args: - timeout_ms: Timeout in milliseconds to wait for each response. - info_cb: Optional callback for text sent from the bootloader. + .. image:: _static/adb.fastboot.FastbootProtocol.HandleSimpleResponses.CALL_GRAPH.svg + + .. image:: _static/adb.fastboot.FastbootProtocol.HandleSimpleResponses.CALLER_GRAPH.svg + + Parameters + ---------- + timeout_ms : TODO, None + Timeout in milliseconds to wait for each response. + info_cb : TODO + Optional callback for text sent from the bootloader. + + Returns + ------- + TODO + OKAY packet's message. - Returns: - OKAY packet's message. """ return self._AcceptResponses(b'OKAY', info_cb, timeout_ms=timeout_ms) @@ -108,50 +206,79 @@ def HandleDataSending(self, source_file, source_len, progress_callback=None, timeout_ms=None): """Handles the protocol for sending data to the device. - Args: - source_file: File-object to read from for the device. - source_len: Amount of data, in bytes, to send to the device. - info_cb: Optional callback for text sent from the bootloader. - progress_callback: Callback that takes the current and the total progress - of the current file. - timeout_ms: Timeout in milliseconds to wait for each response. - - Raises: - FastbootTransferError: When fastboot can't handle this amount of data. - FastbootStateMismatch: Fastboot responded with the wrong packet type. - FastbootRemoteFailure: Fastboot reported failure. - FastbootInvalidResponse: Fastboot responded with an unknown packet type. - - Returns: - OKAY packet's message. + .. image:: _static/adb.fastboot.FastbootProtocol.HandleDataSending.CALL_GRAPH.svg + + .. image:: _static/adb.fastboot.FastbootProtocol.HandleDataSending.CALLER_GRAPH.svg + + Parameters + ---------- + source_file : TODO + File-object to read from for the device. + source_len : TODO + Amount of data, in bytes, to send to the device. + info_cb : TODO + Optional callback for text sent from the bootloader. + progress_callback : TODO, None + Callback that takes the current and the total progress of the current file. + timeout_ms : TODO, None + Timeout in milliseconds to wait for each response. + + Returns + ------- + TODO + OKAY packet's message. + + Raises + ------ + adb.fastboot.FastbootTransferError + When fastboot can't handle this amount of data. + adb.fastboot.FastbootStateMismatch + Fastboot responded with the wrong packet type. + adb.fastboot.FastbootRemoteFailure + Fastboot reported failure. + adb.fastboot.FastbootInvalidResponse + Fastboot responded with an unknown packet type. + """ - accepted_size = self._AcceptResponses( - b'DATA', info_cb, timeout_ms=timeout_ms) + accepted_size = self._AcceptResponses(b'DATA', info_cb, timeout_ms=timeout_ms) accepted_size = binascii.unhexlify(accepted_size[:8]) accepted_size, = struct.unpack(b'>I', accepted_size) if accepted_size != source_len: - raise FastbootTransferError( - 'Device refused to download %s bytes of data (accepts %s bytes)', - source_len, accepted_size) + raise FastbootTransferError('Device refused to download {0} bytes of data (accepts {1} bytes)'.format(source_len, accepted_size)) + self._Write(source_file, accepted_size, progress_callback) + return self._AcceptResponses(b'OKAY', info_cb, timeout_ms=timeout_ms) def _AcceptResponses(self, expected_header, info_cb, timeout_ms=None): """Accepts responses until the expected header or a FAIL. - Args: - expected_header: OKAY or DATA - info_cb: Optional callback for text sent from the bootloader. - timeout_ms: Timeout in milliseconds to wait for each response. + .. image:: _static/adb.fastboot.FastbootProtocol._AcceptResponses.CALLER_GRAPH.svg + + Parameters + ---------- + expected_header : TODO + ``OKAY`` or ``DATA`` + info_cb : TODO + Optional callback for text sent from the bootloader. + timeout_ms : TODO + Timeout in milliseconds to wait for each response. + + Returns + ------- + TODO + OKAY packet's message. + + Raises + ------ + adb.fastboot.FastbootStateMismatch + Fastboot responded with the wrong packet type. + adb.fastboot.FastbootRemoteFailure + Fastboot reported failure. + adb.fastboot.FastbootInvalidResponse + Fastboot responded with an unknown packet type. - Raises: - FastbootStateMismatch: Fastboot responded with the wrong packet type. - FastbootRemoteFailure: Fastboot reported failure. - FastbootInvalidResponse: Fastboot responded with an unknown packet type. - - Returns: - OKAY packet's message. """ while True: response = self.usb.BulkRead(64, timeout_ms=timeout_ms) @@ -162,32 +289,56 @@ def _AcceptResponses(self, expected_header, info_cb, timeout_ms=None): info_cb(FastbootMessage(remaining, header)) elif header in self.FINAL_HEADERS: if header != expected_header: - raise FastbootStateMismatch( - 'Expected %s, got %s', expected_header, header) + raise FastbootStateMismatch('Expected {0}, got {1}'.format(expected_header, header)) if header == b'OKAY': info_cb(FastbootMessage(remaining, header)) return remaining elif header == b'FAIL': info_cb(FastbootMessage(remaining, header)) - raise FastbootRemoteFailure('FAIL: %s', remaining) + raise FastbootRemoteFailure('FAIL: {0}'.format(remaining)) else: - raise FastbootInvalidResponse( - 'Got unknown header %s and response %s', header, remaining) + raise FastbootInvalidResponse('Got unknown header {0} and response {1}'.format(header, remaining)) + + @staticmethod + def _HandleProgress(total, progress_callback): + """Calls the callback with the current progress and total. + + .. image:: _static/adb.fastboot.FastbootProtocol._HandleProgress.CALLER_GRAPH.svg - def _HandleProgress(self, total, progress_callback): - """Calls the callback with the current progress and total .""" + Parameters + ---------- + total : TODO + TODO + progress_callback : TODO + TODO + + """ current = 0 while True: current += yield try: progress_callback(current, total) except Exception: # pylint: disable=broad-except - _LOG.exception('Progress callback raised an exception. %s', - progress_callback) + _LOG.exception('Progress callback raised an exception. %s', progress_callback) continue def _Write(self, data, length, progress_callback=None): - """Sends the data to the device, tracking progress with the callback.""" + """Sends the data to the device, tracking progress with the callback. + + .. image:: _static/adb.fastboot.FastbootProtocol._Write.CALL_GRAPH.svg + + .. image:: _static/adb.fastboot.FastbootProtocol._Write.CALLER_GRAPH.svg + + Parameters + ---------- + data : TODO + TODO + length : TODO + TODO + progress_callback : TODO, None + TODO + + """ if progress_callback: progress = self._HandleProgress(length, progress_callback) next(progress) @@ -201,60 +352,88 @@ def _Write(self, data, length, progress_callback=None): class FastbootCommands(object): - """Encapsulates the fastboot commands.""" + """Encapsulates the fastboot commands. - def __init__(self): - """Constructs a FastbootCommands instance. + .. image:: _static/adb.fastboot.FastbootCommands.__init__.CALLER_GRAPH.svg - Args: - usb: UsbHandle instance. - """ - self.__reset() + Attributes + ---------- + _handle : TODO, None + TODO + _protocol : TODO, None + TODO - def __reset(self): + """ + def __init__(self): self._handle = None self._protocol = None + def __reset(self): + """TODO + + .. image:: _static/adb.fastboot.FastbootCommands.__reset.CALL_GRAPH.svg + + """ + self.__init__() + @property def usb_handle(self): + """TODO + + Returns + ------- + self._handle : TODO + TODO + + """ return self._handle def Close(self): + """TODO""" self._handle.Close() def ConnectDevice(self, port_path=None, serial=None, default_timeout_ms=None, chunk_kb=1024, **kwargs): """Convenience function to get an adb device from usb path or serial. - Args: - port_path: The filename of usb port to use. - serial: The serial number of the device to use. - default_timeout_ms: The default timeout in milliseconds to use. - chunk_kb: Amount of data, in kilobytes, to break fastboot packets up into - kwargs: handle: Device handle to use (instance of common.TcpHandle or common.UsbHandle) - banner: Connection banner to pass to the remote device - rsa_keys: List of AuthSigner subclass instances to be used for - authentication. The device can either accept one of these via the Sign - method, or we will send the result of GetPublicKey from the first one - if the device doesn't accept any of them. - auth_timeout_ms: Timeout to wait for when sending a new public key. This - is only relevant when we send a new public key. The device shows a - dialog and this timeout is how long to wait for that dialog. If used - in automation, this should be low to catch such a case as a failure - quickly; while in interactive settings it should be high to allow - users to accept the dialog. We default to automation here, so it's low - by default. - - If serial specifies a TCP address:port, then a TCP connection is - used instead of a USB connection. + Parameters + ---------- + port_path : TODO, None + The filename of usb port to use. + serial : TODO, None + The serial number of the device to use. If serial specifies a TCP address:port, then a TCP connection is + used instead of a USB connection. + default_timeout_ms : TODO, None + The default timeout in milliseconds to use. + chunk_kb : int + Amount of data, in kilobytes, to break fastboot packets up into + **kwargs : dict + Keyword arguments + handle : adb.common.TcpHandle, adb.common.UsbHandle + Device handle to use + banner : TODO + Connection banner to pass to the remote device + rsa_keys : list[adb_protocol.AuthSigner] + List of AuthSigner subclass instances to be used for authentication. The device can either accept one of + these via the ``Sign`` method, or we will send the result of ``GetPublicKey`` from the first one if the + device doesn't accept any of them. + auth_timeout_ms : TODO + Timeout to wait for when sending a new public key. This is only relevant when we send a new public key. The + device shows a dialog and this timeout is how long to wait for that dialog. If used in automation, this + should be low to catch such a case as a failure quickly; while in interactive settings it should be high to + allow users to accept the dialog. We default to automation here, so it's low by default. + + Returns + ------- + self : FastbootCommands + TODO + """ if 'handle' in kwargs: self._handle = kwargs['handle'] else: - self._handle = common.UsbHandle.FindAndOpen( - DeviceIsAvailable, port_path=port_path, serial=serial, - timeout_ms=default_timeout_ms) + self._handle = common.UsbHandle.FindAndOpen(DeviceIsAvailable, port_path=port_path, serial=serial, timeout_ms=default_timeout_ms) self._protocol = FastbootProtocol(self._handle, chunk_kb) @@ -262,10 +441,40 @@ def ConnectDevice(self, port_path=None, serial=None, default_timeout_ms=None, ch @classmethod def Devices(cls): - """Get a generator of UsbHandle for devices available.""" + """Get a generator of UsbHandle for devices available. + + Returns + ------- + TODO + TODO + + """ return common.UsbHandle.FindDevices(DeviceIsAvailable) def _SimpleCommand(self, command, arg=None, **kwargs): + """TODO + + .. image:: _static/adb.fastboot.FastbootCommands._SimpleCommand.CALL_GRAPH.svg + + .. image:: _static/adb.fastboot.FastbootCommands._SimpleCommand.CALLER_GRAPH.svg + + Parameters + ---------- + command : TODO + TODO + arg : TODO, None + TODO + **kwargs : dict + Keyword arguments + TODO + TODO + + Returns + ------- + TODO + TODO + + """ self._protocol.SendCommand(command, arg) return self._protocol.HandleSimpleResponses(**kwargs) @@ -273,42 +482,61 @@ def FlashFromFile(self, partition, source_file, source_len=0, info_cb=DEFAULT_MESSAGE_CALLBACK, progress_callback=None): """Flashes a partition from the file on disk. - Args: - partition: Partition name to flash to. - source_file: Filename to download to the device. - source_len: Optional length of source_file, uses os.stat if not provided. - info_cb: See Download. - progress_callback: See Download. + .. image:: _static/adb.fastboot.FastbootCommands.FlashFromFile.CALL_GRAPH.svg + + .. image:: _static/adb.fastboot.FastbootCommands.FlashFromFile.CALLER_GRAPH.svg + + Parameters + ---------- + partition : TODO + Partition name to flash to. + source_file : TODO + Filename to download to the device. + source_len : int + Optional length of source_file, uses os.stat if not provided. + info_cb : TODO + See Download. + progress_callback : TODO + See Download. + + Returns + ------- + TODO + Download and flash responses, normally nothing. - Returns: - Download and flash responses, normally nothing. """ if source_len == 0: # Fall back to stat. source_len = os.stat(source_file).st_size - download_response = self.Download( - source_file, source_len=source_len, info_cb=info_cb, - progress_callback=progress_callback) + download_response = self.Download(source_file, source_len=source_len, info_cb=info_cb, progress_callback=progress_callback) flash_response = self.Flash(partition, info_cb=info_cb) + return download_response + flash_response def Download(self, source_file, source_len=0, info_cb=DEFAULT_MESSAGE_CALLBACK, progress_callback=None): """Downloads a file to the device. - Args: - source_file: A filename or file-like object to download to the device. - source_len: Optional length of source_file. If source_file is a file-like - object and source_len is not provided, source_file is read into - memory. - info_cb: Optional callback accepting FastbootMessage for text sent from - the bootloader. - progress_callback: Optional callback called with the percent of the - source_file downloaded. Note, this doesn't include progress of the - actual flashing. - - Returns: - Response to a download request, normally nothing. + .. image:: _static/adb.fastboot.FastbootCommands.Download.CALLER_GRAPH.svg + + Parameters + ---------- + source_file : TODO + A filename or file-like object to download to the device. + source_len : int + Optional length of source_file. If ``source_file`` is a file-like object and ``source_len`` is not provided, + ``source_file`` is read into memory. + info_cb : TODO + Optional callback accepting FastbootMessage for text sent from the bootloader. + progress_callback : TODO, None + Optional callback called with the percent of the source_file downloaded. Note, this doesn't include progress + of the actual flashing. + + Returns + ------- + TODO + Response to a download request, normally nothing. + """ if isinstance(source_file, str): source_len = os.stat(source_file).st_size @@ -322,77 +550,137 @@ def Download(self, source_file, source_len=0, source_len = len(data) self._protocol.SendCommand(b'download', b'%08x' % source_len) - return self._protocol.HandleDataSending( - source_file, source_len, info_cb, progress_callback=progress_callback) + + return self._protocol.HandleDataSending(source_file, source_len, info_cb, progress_callback=progress_callback) def Flash(self, partition, timeout_ms=0, info_cb=DEFAULT_MESSAGE_CALLBACK): """Flashes the last downloaded file to the given partition. - Args: - partition: Partition to overwrite with the new image. - timeout_ms: Optional timeout in milliseconds to wait for it to finish. - info_cb: See Download. Usually no messages. + .. image:: _static/adb.fastboot.FastbootCommands.Flash.CALL_GRAPH.svg + + .. image:: _static/adb.fastboot.FastbootCommands.Flash.CALLER_GRAPH.svg - Returns: - Response to a download request, normally nothing. + Parameters + ---------- + partition : TODO + Partition to overwrite with the new image. + timeout_ms : int + Optional timeout in milliseconds to wait for it to finish. + info_cb : TODO + See :meth:`FastbootCommands.Download`. Usually no messages. + + Returns + ------- + TODO + Response to a download request, normally nothing. """ - return self._SimpleCommand(b'flash', arg=partition, info_cb=info_cb, - timeout_ms=timeout_ms) + return self._SimpleCommand(b'flash', arg=partition, info_cb=info_cb, timeout_ms=timeout_ms) def Erase(self, partition, timeout_ms=None): """Erases the given partition. - Args: - partition: Partition to clear. + .. image:: _static/adb.fastboot.FastbootCommands.Erase.CALL_GRAPH.svg + + Parameters + ---------- + partition : TODO + Partition to clear. + timeout_ms : TODO, None + TODO + """ self._SimpleCommand(b'erase', arg=partition, timeout_ms=timeout_ms) def Getvar(self, var, info_cb=DEFAULT_MESSAGE_CALLBACK): """Returns the given variable's definition. - Args: - var: A variable the bootloader tracks. Use 'all' to get them all. - info_cb: See Download. Usually no messages. + .. image:: _static/adb.fastboot.FastbootCommands.Getvar.CALL_GRAPH.svg + + Parameters + ---------- + var : TODO + A variable the bootloader tracks. Use 'all' to get them all. + info_cb : TODO + See :meth:`FastbootCommands.Download`. Usually no messages. + + Returns + ------- + TODO + Value of ``var`` according to the current bootloader. - Returns: - Value of var according to the current bootloader. """ return self._SimpleCommand(b'getvar', arg=var, info_cb=info_cb) def Oem(self, command, timeout_ms=None, info_cb=DEFAULT_MESSAGE_CALLBACK): """Executes an OEM command on the device. - Args: - command: Command to execute, such as 'poweroff' or 'bootconfig read'. - timeout_ms: Optional timeout in milliseconds to wait for a response. - info_cb: See Download. Messages vary based on command. + .. image:: _static/adb.fastboot.FastbootCommands.Oem.CALL_GRAPH.svg + + Parameters + ---------- + command : TODO + Command to execute, such as 'poweroff' or 'bootconfig read'. + timeout_ms : TODO, None + Optional timeout in milliseconds to wait for a response. + info_cb : TODO + See :meth:`FastbootCommands.Download`. Messages vary based on command. - Returns: + Returns + ------- The final response from the device. """ if not isinstance(command, bytes): command = command.encode('utf8') - return self._SimpleCommand( - b'oem %s' % command, timeout_ms=timeout_ms, info_cb=info_cb) + + return self._SimpleCommand(b'oem %s' % command, timeout_ms=timeout_ms, info_cb=info_cb) def Continue(self): - """Continues execution past fastboot into the system.""" + """Continues execution past fastboot into the system. + + .. image:: _static/adb.fastboot.FastbootCommands.Continue.CALL_GRAPH.svg + + Returns + ------- + TODO + TODO + + """ return self._SimpleCommand(b'continue') def Reboot(self, target_mode=b'', timeout_ms=None): """Reboots the device. - Args: - target_mode: Normal reboot when unspecified. Can specify other target - modes such as 'recovery' or 'bootloader'. - timeout_ms: Optional timeout in milliseconds to wait for a response. + .. image:: _static/adb.fastboot.FastbootCommands.Reboot.CALL_GRAPH.svg + + Parameters + ---------- + target_mode : bytes + Normal reboot when unspecified. Can specify other target modes such as 'recovery' or 'bootloader'. + timeout_ms : TODO, None + Optional timeout in milliseconds to wait for a response. - Returns: + Returns + ------- + TODO Usually the empty string. Depends on the bootloader and the target_mode. + """ - return self._SimpleCommand( - b'reboot', arg=target_mode or None, timeout_ms=timeout_ms) + return self._SimpleCommand(b'reboot', arg=target_mode or None, timeout_ms=timeout_ms) def RebootBootloader(self, timeout_ms=None): - """Reboots into the bootloader, usually equiv to Reboot('bootloader').""" + """Reboots into the bootloader, usually equiv to Reboot('bootloader'). + + .. image:: _static/adb.fastboot.FastbootCommands.RebootBootloader.CALL_GRAPH.svg + + Parameters + ---------- + timeout_ms : TODO, None + TODO + + Returns + ------- + TODO + TODO + + """ return self._SimpleCommand(b'reboot-bootloader', timeout_ms=timeout_ms) diff --git a/adb/fastboot_debug.py b/adb/fastboot_debug.py index e168f69..22d4394 100755 --- a/adb/fastboot_debug.py +++ b/adb/fastboot_debug.py @@ -15,8 +15,14 @@ """Fastboot in python. -Call it similar to how you call android's fastboot. Call it similar to how you -call android's fastboot, but this only accepts usb paths and no serials. +Call it similar to how you call android's fastboot, but this only accepts usb paths and no serials. + + +.. rubric:: Contents + +* :func:`_InfoCb` +* :func:`Devices` + """ import argparse @@ -34,11 +40,24 @@ progressbar = None -def Devices(args): +def Devices(): """Lists the available devices. - List of devices attached - 015DB7591102001A device + :: + + List of devices attached + 015DB7591102001A device + + + .. seealso:: :meth:`adb.fastboot.FastbootCommands.Devices` + + .. image:: _static/adb.fastboot_debug.Devices.CALLER_GRAPH.svg + + Returns + ------- + int + 0 + """ for device in fastboot.FastbootCommands.Devices(): print('%s\tdevice' % device.serial_number) @@ -46,6 +65,14 @@ def Devices(args): def _InfoCb(message): + """Print a message to stdout. + + Parameters + ---------- + message : adb.fastboot.FastbootMessage + A :class:`~adb.fastboot.FastbootMessage` with ``header`` and ``message`` attributes + + """ # Use an unbuffered version of stdout. if not message.message: return @@ -54,38 +81,26 @@ def _InfoCb(message): def main(): + """TODO""" common = common_cli.GetCommonArguments() device = common_cli.GetDeviceArguments() - device.add_argument( - '--chunk_kb', type=int, default=1024, metavar='1024', - help='Size of packets to write in Kb. For older devices, it may be ' - 'required to use 4.') + device.add_argument('--chunk_kb', type=int, default=1024, metavar='1024', + help='Size of packets to write in Kb. For older devices, it may be required to use 4.') parents = [common, device] - parser = argparse.ArgumentParser( - description=sys.modules[__name__].__doc__, parents=[common]) + parser = argparse.ArgumentParser(description=sys.modules[__name__].__doc__, parents=[common]) subparsers = parser.add_subparsers(title='Commands', dest='command_name') - subparser = subparsers.add_parser( - name='help', help='Prints the commands available') - subparser = subparsers.add_parser( - name='devices', help='Lists the available devices', parents=[common]) - common_cli.MakeSubparser( - subparsers, parents, fastboot.FastbootCommands.Continue) - - common_cli.MakeSubparser( - subparsers, parents, fastboot.FastbootCommands.Download, - {'source_file': 'Filename on the host to push'}) - common_cli.MakeSubparser( - subparsers, parents, fastboot.FastbootCommands.Erase) - common_cli.MakeSubparser( - subparsers, parents, fastboot.FastbootCommands.Flash) - common_cli.MakeSubparser( - subparsers, parents, fastboot.FastbootCommands.Getvar) - common_cli.MakeSubparser( - subparsers, parents, fastboot.FastbootCommands.Oem) - common_cli.MakeSubparser( - subparsers, parents, fastboot.FastbootCommands.Reboot) + subparser = subparsers.add_parser(name='help', help='Prints the commands available') # pylint: disable=unused-variable + subparser = subparsers.add_parser(name='devices', help='Lists the available devices', parents=[common]) # noqa: F841 + + common_cli.MakeSubparser(subparsers, parents, fastboot.FastbootCommands.Continue) + common_cli.MakeSubparser(subparsers, parents, fastboot.FastbootCommands.Download, {'source_file': 'Filename on the host to push'}) + common_cli.MakeSubparser(subparsers, parents, fastboot.FastbootCommands.Erase) + common_cli.MakeSubparser(subparsers, parents, fastboot.FastbootCommands.Flash) + common_cli.MakeSubparser(subparsers, parents, fastboot.FastbootCommands.Getvar) + common_cli.MakeSubparser(subparsers, parents, fastboot.FastbootCommands.Oem) + common_cli.MakeSubparser(subparsers, parents, fastboot.FastbootCommands.Reboot) if len(sys.argv) == 1: parser.print_help() @@ -95,18 +110,17 @@ def main(): if args.verbose: logging.basicConfig(level=logging.DEBUG) if args.command_name == 'devices': - return Devices(args) + return Devices() if args.command_name == 'help': parser.print_help() return 0 kwargs = {} - argspec = inspect.getargspec(args.method) + argspec = inspect.getfullargspec(args.method) if 'info_cb' in argspec.args: kwargs['info_cb'] = _InfoCb if 'progress_callback' in argspec.args and progressbar: - bar = progressbar.ProgessBar( - widgets=[progressbar.Bar(), progressbar.Percentage()]) + bar = progressbar.ProgessBar(widgets=[progressbar.Bar(), progressbar.Percentage()]) # pylint: disable=blacklisted-name bar.start() def SetProgress(current, total): diff --git a/adb/filesync_protocol.py b/adb/filesync_protocol.py index d0547f4..bc1c3de 100644 --- a/adb/filesync_protocol.py +++ b/adb/filesync_protocol.py @@ -11,13 +11,41 @@ # 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. + """ADB protocol implementation. Implements the ADB protocol as seen in android's adb/adbd binaries, but only the host side. + + +.. rubric:: Contents + +* :class:`FileSyncConnection` + + * :meth:`FileSyncConnection.Read` + * :meth:`FileSyncConnection.ReadUntil` + * :meth:`FileSyncConnection.Send` + * :meth:`FileSyncConnection._CanAddToSendBuffer` + * :meth:`FileSyncConnection._Flush` + * :meth:`FileSyncConnection._ReadBuffered` + +* :class:`FilesyncProtocol` + + * :meth:`FilesyncProtocol._HandleProgress` + * :meth:`FilesyncProtocol.List` + * :meth:`FilesyncProtocol.Pull` + * :meth:`FilesyncProtocol.Push` + * :meth:`FilesyncProtocol.Stat` + +* :class:`InterleavedDataError` +* :class:`InvalidChecksumError` +* :class:`PullFailedError` +* :class:`PushFailedError` + """ import collections +import io import os import stat import struct @@ -28,30 +56,52 @@ from adb import adb_protocol from adb import usb_exceptions -# Default mode for pushed files. + +try: + file_types = (file, io.IOBase) +except NameError: + file_types = (io.IOBase,) + +#: Default mode for pushed files. DEFAULT_PUSH_MODE = stat.S_IFREG | stat.S_IRWXU | stat.S_IRWXG -# Maximum size of a filesync DATA packet. + +#: Maximum size of a filesync DATA packet. MAX_PUSH_DATA = 2 * 1024 class InvalidChecksumError(Exception): - """Checksum of data didn't match expected checksum.""" + """Checksum of data didn't match expected checksum. + + .. image:: _static/adb.filesync_protocol.InvalidChecksumError.CALL_GRAPH.svg + + """ class InterleavedDataError(Exception): - """We only support command sent serially.""" + """We only support command sent serially. + + .. image:: _static/adb.filesync_protocol.InterleavedDataError.CALL_GRAPH.svg + + """ class PushFailedError(Exception): - """Pushing a file failed for some reason.""" + """Pushing a file failed for some reason. + + .. image:: _static/adb.filesync_protocol.PushFailedError.CALL_GRAPH.svg + + """ class PullFailedError(Exception): - """Pulling a file failed for some reason.""" + """Pulling a file failed for some reason. + + .. image:: _static/adb.filesync_protocol.PullFailedError.CALL_GRAPH.svg + + """ -DeviceFile = collections.namedtuple('DeviceFile', [ - 'filename', 'mode', 'size', 'mtime']) +DeviceFile = collections.namedtuple('DeviceFile', ['filename', 'mode', 'size', 'mtime']) class FilesyncProtocol(object): @@ -59,30 +109,94 @@ class FilesyncProtocol(object): @staticmethod def Stat(connection, filename): + """Get file status (mode, size, and mtime). + + .. image:: _static/adb.filesync_protocol.FilesyncProtocol.Stat.CALLER_GRAPH.svg + + Parameters + ---------- + connection : adb.adb_protocol._AdbConnection + ADB connection + filename : str, bytes + The file for which we are getting info + + Returns + ------- + mode : int + The mode of the file + size : int + The size of the file + mtime : int + The time of last modification for the file + + Raises + ------ + adb.adb_protocol.InvalidResponseError + Expected STAT response to STAT, got something else + + """ cnxn = FileSyncConnection(connection, b'<4I') cnxn.Send(b'STAT', filename) command, (mode, size, mtime) = cnxn.Read((b'STAT',), read_data=False) if command != b'STAT': - raise adb_protocol.InvalidResponseError( - 'Expected STAT response to STAT, got %s' % command) + raise adb_protocol.InvalidResponseError('Expected STAT response to STAT, got %s' % command) + return mode, size, mtime @classmethod def List(cls, connection, path): + """Get a list of the files in ``path``. + + Parameters + ---------- + connection : adb.adb_protocol._AdbConnection + ADB connection + path : str, bytes + The path for which we are getting a list of files + + Returns + ------- + files : list[DeviceFile] + Information about the files in ``path`` + + """ cnxn = FileSyncConnection(connection, b'<5I') cnxn.Send(b'LIST', path) files = [] + for cmd_id, header, filename in cnxn.ReadUntil((b'DENT',), b'DONE'): if cmd_id == b'DONE': break + mode, size, mtime = header files.append(DeviceFile(filename, mode, size, mtime)) + return files @classmethod def Pull(cls, connection, filename, dest_file, progress_callback): - """Pull a file from the device into the file-like dest_file.""" + """Pull a file from the device into the file-like ``dest_file``. + + .. image:: _static/adb.filesync_protocol.FilesyncProtocol.Pull.CALL_GRAPH.svg + + Parameters + ---------- + connection : adb.adb_protocol._AdbConnection + ADB connection + filename : str + The file to be pulled + dest_file : _io.BytesIO + File-like object for writing to + progress_callback : function, None + Callback method that accepts ``filename``, ``bytes_written``, and ``total_bytes`` + + Raises + ------ + PullFailedError + Unable to pull file + + """ if progress_callback: total_bytes = cls.Stat(connection, filename)[1] progress = cls._HandleProgress(lambda current: progress_callback(filename, current, total_bytes)) @@ -94,9 +208,11 @@ def Pull(cls, connection, filename, dest_file, progress_callback): for cmd_id, _, data in cnxn.ReadUntil((b'DATA',), b'DONE'): if cmd_id == b'DONE': break + dest_file.write(data) if progress_callback: progress.send(len(data)) + except usb_exceptions.CommonUsbError as e: raise PullFailedError('Unable to pull file %s due to: %s' % (filename, e)) @@ -104,9 +220,16 @@ def Pull(cls, connection, filename, dest_file, progress_callback): def _HandleProgress(cls, progress_callback): """Calls the callback with the current progress and total bytes written/received. - Args: - progress_callback: callback method that accepts filename, bytes_written and total_bytes, - total_bytes will be -1 for file-like objects + .. image:: _static/adb.filesync_protocol.FilesyncProtocol._HandleProgress.CALL_GRAPH.svg + + .. image:: _static/adb.filesync_protocol.FilesyncProtocol._HandleProgress.CALLER_GRAPH.svg + + Parameters + ---------- + progress_callback : function + Callback method that accepts ``filename``, ``bytes_written``, and ``total_bytes``; total_bytes will be -1 for file-like + objects. + """ current = 0 while True: @@ -121,25 +244,38 @@ def Push(cls, connection, datafile, filename, st_mode=DEFAULT_PUSH_MODE, mtime=0, progress_callback=None): """Push a file-like object to the device. - Args: - connection: ADB connection - datafile: File-like object for reading from - filename: Filename to push to - st_mode: stat mode for filename - mtime: modification time - progress_callback: callback method that accepts filename, bytes_written and total_bytes + .. image:: _static/adb.filesync_protocol.FilesyncProtocol.Push.CALL_GRAPH.svg + + .. image:: _static/adb.filesync_protocol.FilesyncProtocol.Push.CALLER_GRAPH.svg + + Parameters + ---------- + connection : adb.adb_protocol._AdbConnection + ADB connection + datafile : _io.BytesIO + File-like object for reading from + filename : str + Filename to push to + st_mode : int + Stat mode for filename + mtime : int + Modification time + progress_callback : function, None + Callback method that accepts ``filename``, ``bytes_written``, and ``total_bytes`` + + Raises + ------ + PushFailedError + Raised on push failure. - Raises: - PushFailedError: Raised on push failure. """ - fileinfo = ('{},{}'.format(filename, int(st_mode))).encode('utf-8') cnxn = FileSyncConnection(connection, b'<2I') cnxn.Send(b'SEND', fileinfo) if progress_callback: - total_bytes = os.fstat(datafile.fileno()).st_size if isinstance(datafile, file) else -1 + total_bytes = os.fstat(datafile.fileno()).st_size if isinstance(datafile, file_types) else -1 progress = cls._HandleProgress(lambda current: progress_callback(filename, current, total_bytes)) next(progress) @@ -165,12 +301,35 @@ def Push(cls, connection, datafile, filename, class FileSyncConnection(object): - """Encapsulate a FileSync service connection.""" - - ids = [ - b'STAT', b'LIST', b'SEND', b'RECV', b'DENT', b'DONE', b'DATA', b'OKAY', - b'FAIL', b'QUIT', - ] + """Encapsulate a FileSync service connection. + + Parameters + ---------- + adb_connection : adb.adb_protocol._AdbConnection + ADB connection + recv_header_format : bytes + TODO + + Attributes + ---------- + adb : adb.adb_protocol._AdbConnection + ADB connection + send_buffer : byte_array + ``bytearray(adb_protocol.MAX_ADB_DATA)`` (see :const:`adb.adb_protocol.MAX_ADB_DATA`) + send_idx : int + TODO + send_header_len : int + ``struct.calcsize(b'<2I')`` + recv_buffer : bytearray + TODO + recv_header_format : bytes + TODO + recv_header_len : int + ``struct.calcsize(recv_header_format)`` + + """ + + ids = [b'STAT', b'LIST', b'SEND', b'RECV', b'DENT', b'DONE', b'DATA', b'OKAY', b'FAIL', b'QUIT'] id_to_wire, wire_to_id = adb_protocol.MakeWireIDs(ids) def __init__(self, adb_connection, recv_header_format): @@ -193,10 +352,17 @@ def Send(self, command_id, data=b'', size=0): Packets are buffered and only flushed when this connection is read from. All messages have a response from the device, so this will always get flushed. - Args: - command_id: Command to send. - data: Optional data to send, must set data or size. - size: Optionally override size from len(data). + .. image:: _static/adb.filesync_protocol.FileSyncConnection.Send.CALL_GRAPH.svg + + Parameters + ---------- + command_id : bytes + Command to send. + data : str, bytes + Optional data to send, must set data or size. + size : int + Optionally override size from len(data). + """ if data: if not isinstance(data, bytes): @@ -210,7 +376,36 @@ def Send(self, command_id, data=b'', size=0): self.send_idx += len(buf) def Read(self, expected_ids, read_data=True): - """Read ADB messages and return FileSync packets.""" + """Read ADB messages and return FileSync packets. + + .. image:: _static/adb.filesync_protocol.FileSyncConnection.Read.CALL_GRAPH.svg + + .. image:: _static/adb.filesync_protocol.FileSyncConnection.Read.CALLER_GRAPH.svg + + Parameters + ---------- + expected_ids : tuple[bytes] + If the received header ID is not in ``expected_ids``, an exception will be raised + read_data : bool + Whether to read the received data + + Returns + ------- + command_id : bytes + The received header ID + tuple + TODO + data : bytearray + The received data + + Raises + ------ + adb.usb_exceptions.AdbCommandFailureException + Command failed + adb.adb_protocol.InvalidResponseError + Received response was not in ``expected_ids`` + + """ if self.send_idx: self._Flush() @@ -225,9 +420,10 @@ def Read(self, expected_ids, read_data=True): reason = '' if self.recv_buffer: reason = self.recv_buffer.decode('utf-8', errors='ignore') + raise usb_exceptions.AdbCommandFailureException('Command failed: {}'.format(reason)) - raise adb_protocol.InvalidResponseError( - 'Expected one of %s, got %s' % (expected_ids, command_id)) + + raise adb_protocol.InvalidResponseError('Expected one of %s, got %s' % (expected_ids, command_id)) if not read_data: return command_id, header[1:] @@ -235,10 +431,31 @@ def Read(self, expected_ids, read_data=True): # Header is (ID, ..., size). size = header[-1] data = self._ReadBuffered(size) + return command_id, header[1:-1], data def ReadUntil(self, expected_ids, *finish_ids): - """Useful wrapper around Read.""" + """Useful wrapper around :meth:`FileSyncConnection.Read`. + + .. image:: _static/adb.filesync_protocol.FileSyncConnection.ReadUntil.CALL_GRAPH.svg + + Parameters + ---------- + expected_ids : tuple[bytes] + If the received header ID is not in ``expected_ids``, an exception will be raised + finish_ids : tuple[bytes] + We will read until we find a header ID that is in ``finish_ids`` + + Yields + ------ + cmd_id : bytes + The received header ID + header : tuple + TODO + data : bytearray + The received data + + """ while True: cmd_id, header, data = self.Read(expected_ids + finish_ids) yield cmd_id, header, data @@ -246,18 +463,57 @@ def ReadUntil(self, expected_ids, *finish_ids): break def _CanAddToSendBuffer(self, data_len): + """Determine whether ``data_len`` bytes of data can be added to the send buffer without exceeding :const:`adb.adb_protocol.MAX_ADB_DATA`. + + .. image:: _static/adb.filesync_protocol.FileSyncConnection._CanAddToSendBuffer.CALLER_GRAPH.svg + + Parameters + ---------- + data_len : int + The length of the data to be potentially added to the send buffer (not including the length of its header) + + Returns + ------- + bool + Whether ``data_len`` bytes of data can be added to the send buffer without exceeding :const:`adb.adb_protocol.MAX_ADB_DATA` + + """ added_len = self.send_header_len + data_len return self.send_idx + added_len < adb_protocol.MAX_ADB_DATA def _Flush(self): + """TODO + + .. image:: _static/adb.filesync_protocol.FileSyncConnection._Flush.CALLER_GRAPH.svg + + Raises + ------ + adb.usb_exceptions.WriteFailedError + Could not send data + + """ try: self.adb.Write(self.send_buffer[:self.send_idx]) except libusb1.USBError as e: - raise adb_protocol.SendFailedError( - 'Could not send data %s' % self.send_buffer, e) + raise usb_exceptions.WriteFailedError('Could not send data %s' % self.send_buffer, e) self.send_idx = 0 def _ReadBuffered(self, size): + """Read ``size`` bytes of data from ``self.recv_buffer``. + + .. image:: _static/adb.filesync_protocol.FileSyncConnection._ReadBuffered.CALLER_GRAPH.svg + + Parameters + ---------- + size : int + The amount of data to read + + Returns + ------- + result : bytearray + The read data + + """ # Ensure recv buffer has enough data. while len(self.recv_buffer) < size: _, data = self.adb.ReadUntil(b'WRTE') diff --git a/adb/sign_cryptography.py b/adb/sign_cryptography.py index b042642..9e873a5 100644 --- a/adb/sign_cryptography.py +++ b/adb/sign_cryptography.py @@ -12,7 +12,17 @@ # See the License for the specific language governing permissions and # limitations under the License. -from adb import adb_protocol +"""ADB authentication using the ``cryptography`` package. + + +.. rubric:: Contents + +* :class:`CryptographySigner` + + * :meth:`CryptographySigner.GetPublicKey` + * :meth:`CryptographySigner.Sign` + +""" from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes @@ -20,21 +30,60 @@ from cryptography.hazmat.primitives.asymmetric import padding from cryptography.hazmat.primitives.asymmetric import utils +from adb import adb_protocol + +# pylint: disable=abstract-method class CryptographySigner(adb_protocol.AuthSigner): - """AuthSigner using cryptography.io.""" + """AuthSigner using cryptography.io. + + .. warning:: This is currently broken! + .. image:: _static/adb.sign_cryptography.CryptographySigner.CALL_GRAPH.svg + + Parameters + ---------- + rsa_key_path : str + The path to the private key. + + Attributes + ---------- + public_key : str + The contents of the public key file + rsa_key : cryptography.hazmat.backends.openssl.rsa._RSAPrivateKey + The loaded private key + + """ def __init__(self, rsa_key_path): with open(rsa_key_path + '.pub') as rsa_pub_file: self.public_key = rsa_pub_file.read() with open(rsa_key_path) as rsa_prv_file: - self.rsa_key = serialization.load_pem_private_key( - rsa_prv_file.read(), None, default_backend()) + self.rsa_key = serialization.load_pem_private_key(rsa_prv_file.read(), None, default_backend()) def Sign(self, data): - return self.rsa_key.sign( - data, padding.PKCS1v15(), utils.Prehashed(hashes.SHA1())) + """Signs given data using a private key. + + Parameters + ---------- + data : TODO + TODO + + Returns + ------- + TODO + The signed ``data`` + + """ + return self.rsa_key.sign(data, padding.PKCS1v15(), utils.Prehashed(hashes.SHA1())) def GetPublicKey(self): + """Returns the public key in PEM format without headers or newlines. + + Returns + ------- + self.public_key : str + The contents of the public key file + + """ return self.public_key diff --git a/adb/sign_pycryptodome.py b/adb/sign_pycryptodome.py index 6a61ce9..19a2185 100644 --- a/adb/sign_pycryptodome.py +++ b/adb/sign_pycryptodome.py @@ -1,12 +1,54 @@ -from adb import adb_protocol +# Copyright 2014 Google Inc. All rights reserved. +# +# 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. + +"""ADB authentication using ``pycryptodome``. + + +.. rubric:: Contents + +* :class:`PycryptodomeAuthSigner` + + * :meth:`PycryptodomeAuthSigner.GetPublicKey` + * :meth:`PycryptodomeAuthSigner.Sign` + +""" from Crypto.Hash import SHA256 from Crypto.PublicKey import RSA from Crypto.Signature import pkcs1_15 +from adb import adb_protocol + class PycryptodomeAuthSigner(adb_protocol.AuthSigner): + """TODO + .. image:: _static/adb.sign_pycryptodome.PycryptodomeAuthSigner.CALL_GRAPH.svg + + Parameters + ---------- + rsa_key_path : str, None + The path to the private key + + Attributes + ---------- + public_key : str + The contents of the public key file + rsa_key : Crypto.PublicKey.RSA.RsaKey + The contents of theprivate key + + """ def __init__(self, rsa_key_path=None): super(PycryptodomeAuthSigner, self).__init__() @@ -18,8 +60,29 @@ def __init__(self, rsa_key_path=None): self.rsa_key = RSA.import_key(rsa_priv_file.read()) def Sign(self, data): + """Signs given data using a private key. + + Parameters + ---------- + data : bytes, bytearray + The data to be signed + + Returns + ------- + bytes + The signed ``data`` + + """ h = SHA256.new(data) return pkcs1_15.new(self.rsa_key).sign(h) def GetPublicKey(self): + """Returns the public key in PEM format without headers or newlines. + + Returns + ------- + self.public_key : str + The contents of the public key file + + """ return self.public_key diff --git a/adb/sign_pythonrsa.py b/adb/sign_pythonrsa.py index a401a4c..3ee58b5 100644 --- a/adb/sign_pythonrsa.py +++ b/adb/sign_pythonrsa.py @@ -12,24 +12,72 @@ # See the License for the specific language governing permissions and # limitations under the License. -import rsa +"""ADB authentication using the ``rsa`` package. + + +.. rubric:: Contents + +* :class:`_Accum` + + * :meth:`_Accum.digest` + * :meth:`_Accum.update` + +* :func:`_load_rsa_private_key` +* :class:`PythonRSASigner` + + * :meth:`PythonRSASigner.FromRSAKeyPath` + * :meth:`PythonRSASigner.GetPublicKey` + * :meth:`PythonRSASigner.Sign` + +""" + from pyasn1.codec.der import decoder from pyasn1.type import univ +import rsa from rsa import pkcs1 +from adb import adb_protocol + -# python-rsa lib hashes all messages it signs. ADB does it already, we just -# need to slap a signature on top of already hashed message. Introduce "fake" -# hashing algo for this. class _Accum(object): + """A fake hashing algorithm. + + The Python ``rsa`` lib hashes all messages it signs. ADB does it already, we just + need to slap a signature on top of already hashed message. Introduce a "fake" + hashing algo for this. + + .. image:: _static/adb.sign_pythonrsa._Accum.CALL_GRAPH.svg + + Attributes + ---------- + _buf : bytes + A buffer for storing data before it is signed + + """ def __init__(self): self._buf = b'' def update(self, msg): + """Update this hash object's state with the provided ``msg``. + + Parameters + ---------- + msg : bytes + The message to be appended to ``self._buf`` + + """ self._buf += msg def digest(self): + """Return the digest value as a string of binary data. + + Returns + ------- + self._buf : bytes + ``self._buf`` + + """ return self._buf @@ -38,40 +86,111 @@ def digest(self): def _load_rsa_private_key(pem): - """PEM encoded PKCS#8 private key -> rsa.PrivateKey.""" - # ADB uses private RSA keys in pkcs#8 format. 'rsa' library doesn't support - # them natively. Do some ASN unwrapping to extract naked RSA key - # (in der-encoded form). See https://www.ietf.org/rfc/rfc2313.txt. - # Also http://superuser.com/a/606266. + """PEM encoded PKCS#8 private key -> ``rsa.PrivateKey``. + + ADB uses private RSA keys in pkcs#8 format. The ``rsa`` library doesn't + support them natively. Do some ASN unwrapping to extract naked RSA key + (in der-encoded form). + + See: + + * https://www.ietf.org/rfc/rfc2313.txt + * http://superuser.com/a/606266 + + Parameters + ---------- + pem : str + The private key to be loaded + + Returns + ------- + rsa.key.PrivateKey + The loaded private key + + """ try: der = rsa.pem.load_pem(pem, 'PRIVATE KEY') keyinfo, _ = decoder.decode(der) - if keyinfo[1][0] != univ.ObjectIdentifier( - '1.2.840.113549.1.1.1'): # pragma: no cover + + if keyinfo[1][0] != univ.ObjectIdentifier('1.2.840.113549.1.1.1'): raise ValueError('Not a DER-encoded OpenSSL private RSA key') + private_key_der = keyinfo[2].asOctets() - except IndexError: # pragma: no cover + + except IndexError: raise ValueError('Not a DER-encoded OpenSSL private RSA key') + return rsa.PrivateKey.load_pkcs1(private_key_der, format='DER') -class PythonRSASigner(object): - """Implements adb_protocol.AuthSigner using http://stuvel.eu/rsa.""" +class PythonRSASigner(adb_protocol.AuthSigner): + """Implements :class:`adb_protocol.AuthSigner` using http://stuvel.eu/rsa. + + .. image:: _static/adb.sign_pythonrsa.PythonRSASigner.CALL_GRAPH.svg + + Parameters + ---------- + pub : str, None + The contents of the public key file + priv : str, None + The path to the private key + + Attributes + ---------- + priv_key : rsa.key.PrivateKey + The loaded private key + pub_key : str, None + The contents of the public key file + + """ + def __init__(self, pub=None, priv=None): + self.priv_key = _load_rsa_private_key(priv) + self.pub_key = pub @classmethod def FromRSAKeyPath(cls, rsa_key_path): + """Create a :class:`PythonRSASigner` instance using the provided private key. + + Parameters + ---------- + rsa_key_path : str + The path to the private key; the public key must be ``rsa_key_path + '.pub'``. + + Returns + ------- + PythonRSASigner + A :class:`PythonRSASigner` with private key ``rsa_key_path`` and public key ``rsa_key_path + '.pub'`` + + """ with open(rsa_key_path + '.pub') as f: pub = f.read() with open(rsa_key_path) as f: priv = f.read() return cls(pub, priv) - def __init__(self, pub=None, priv=None): - self.priv_key = _load_rsa_private_key(priv) - self.pub_key = pub - def Sign(self, data): + """Signs given data using a private key. + + Parameters + ---------- + data : bytes + The data to be signed + + Returns + ------- + bytes + The signed ``data`` + + """ return rsa.sign(data, self.priv_key, 'SHA-1-PREHASHED') def GetPublicKey(self): + """Returns the public key in PEM format without headers or newlines. + + Returns + ------- + self.pub_key : str, None + The contents of the public key file, or ``None`` if a public key was not provided. + + """ return self.pub_key diff --git a/adb/usb_exceptions.py b/adb/usb_exceptions.py index 54f7e0b..a0096e6 100644 --- a/adb/usb_exceptions.py +++ b/adb/usb_exceptions.py @@ -11,11 +11,32 @@ # 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. -"""Common exceptions for ADB and Fastboot.""" + +"""Common exceptions for ADB and Fastboot. + + +.. rubric:: Contents + +* :class:`AdbCommandFailureException` +* :class:`AdbOperationException` +* :class:`CommonUsbError` +* :class:`DeviceAuthError` +* :class:`DeviceNotFoundError` +* :class:`FormatMessageWithArgumentsException` +* :class:`LibusbWrappingError` +* :class:`ReadFailedError` +* :class:`TcpTimeoutException` +* :class:`WriteFailedError` + +""" class CommonUsbError(Exception): - """Base class for usb communication errors.""" + """Base class for usb communication errors. + + .. image:: _static/adb.usb_exceptions.CommonUsbError.CALL_GRAPH.svg + + """ class FormatMessageWithArgumentsException(CommonUsbError): @@ -25,52 +46,99 @@ class FormatMessageWithArgumentsException(CommonUsbError): This interpolates the message with the given arguments to make it human-readable, but keeps the arguments in case other code try-excepts it. - """ + .. image:: _static/adb.usb_exceptions.FormatMessageWithArgumentsException.CALL_GRAPH.svg + + Parameters + ---------- + message : str + The error message + args : str + Positional arguments for formatting ``message`` + + """ def __init__(self, message, *args): message %= args super(FormatMessageWithArgumentsException, self).__init__(message, *args) class DeviceNotFoundError(FormatMessageWithArgumentsException): - """Device isn't on USB.""" + """Device isn't on USB. + + .. image:: _static/adb.usb_exceptions.DeviceNotFoundError.CALL_GRAPH.svg + + """ class DeviceAuthError(FormatMessageWithArgumentsException): - """Device authentication failed.""" + """Device authentication failed. + + .. image:: _static/adb.usb_exceptions.DeviceAuthError.CALL_GRAPH.svg + + """ class LibusbWrappingError(CommonUsbError): - """Wraps libusb1 errors while keeping its original usefulness. + """Wraps ``libusb1`` errors while keeping their original usefulness. - Attributes: - usb_error: Instance of libusb1.USBError - """ + .. image:: _static/adb.usb_exceptions.LibusbWrappingError.CALL_GRAPH.svg + Parameters + ---------- + msg : str + The error message + usb_error : libusb1.USBError + An exception from ``libusb1`` + + Attributes + ---------- + usb_error : libusb1.USBError + An exception from ``libusb1`` + + """ def __init__(self, msg, usb_error): super(LibusbWrappingError, self).__init__(msg) self.usb_error = usb_error def __str__(self): - return '%s: %s' % ( - super(LibusbWrappingError, self).__str__(), str(self.usb_error)) + return '%s: %s' % (super(LibusbWrappingError, self).__str__(), str(self.usb_error)) class WriteFailedError(LibusbWrappingError): - """Raised when the device doesn't accept our command.""" + """Raised when the device doesn't accept our command. + + .. image:: _static/adb.usb_exceptions.WriteFailedError.CALL_GRAPH.svg + + """ class ReadFailedError(LibusbWrappingError): - """Raised when the device doesn't respond to our commands.""" + """Raised when the device doesn't respond to our commands. + + .. image:: _static/adb.usb_exceptions.ReadFailedError.CALL_GRAPH.svg + + """ class AdbCommandFailureException(Exception): - """ADB Command returned a FAIL.""" + """ADB Command returned a FAIL. + + .. image:: _static/adb.usb_exceptions.AdbCommandFailureException.CALL_GRAPH.svg + + """ class AdbOperationException(Exception): - """Failed to communicate over adb with device after multiple retries.""" + """Failed to communicate over adb with device after multiple retries. + + .. image:: _static/adb.usb_exceptions.AdbOperationException.CALL_GRAPH.svg + + """ class TcpTimeoutException(FormatMessageWithArgumentsException): - """TCP connection timed out in the time out given.""" + """TCP connection timed out in the time out given. + + .. image:: _static/adb.usb_exceptions.TcpTimeoutException.CALL_GRAPH.svg + + """ diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..4a11cd7 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +SPHINXPROJ = adb +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 0000000..21c0799 --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,36 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=source +set BUILDDIR=build +set SPHINXPROJ=adb + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% + +:end +popd diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000..94610a4 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1 @@ +sphinx==2.1.2 diff --git a/docs/source/_static/adb.adb_commands.AdbCommands.CALL_GRAPH.svg b/docs/source/_static/adb.adb_commands.AdbCommands.CALL_GRAPH.svg new file mode 100644 index 0000000..51a6f86 --- /dev/null +++ b/docs/source/_static/adb.adb_commands.AdbCommands.CALL_GRAPH.svg @@ -0,0 +1,28 @@ + + + + + + +adb.adb_commands.AdbCommands + + +Node1 + +adb.adb_commands.AdbCommands + + +Node2 + +object + + +Node2->Node1 + + + + + diff --git a/docs/source/_static/adb.adb_commands.AdbCommands.Close.CALLER_GRAPH.svg b/docs/source/_static/adb.adb_commands.AdbCommands.Close.CALLER_GRAPH.svg new file mode 100644 index 0000000..267225c --- /dev/null +++ b/docs/source/_static/adb.adb_commands.AdbCommands.Close.CALLER_GRAPH.svg @@ -0,0 +1,32 @@ + + + + + + +adb.adb_commands.AdbCommands.Close + + +Node1 + +adb.adb_commands.AdbCommands. +Close + + +Node2 + + +adb.common.UsbHandle.Open + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.adb_commands.AdbCommands.Close.CALL_GRAPH.svg b/docs/source/_static/adb.adb_commands.AdbCommands.Close.CALL_GRAPH.svg new file mode 100644 index 0000000..13eee9e --- /dev/null +++ b/docs/source/_static/adb.adb_commands.AdbCommands.Close.CALL_GRAPH.svg @@ -0,0 +1,47 @@ + + + + + + +adb.adb_commands.AdbCommands.Close + + +Node1 + +adb.adb_commands.AdbCommands. +Close + + +Node2 + + +adb.adb_commands.AdbCommands. +__reset + + + + +Node1->Node2 + + + + +Node3 + + +adb.adb_commands.AdbCommands. +__init__ + + + + +Node2->Node3 + + + + + diff --git a/docs/source/_static/adb.adb_commands.AdbCommands.ConnectDevice.CALL_GRAPH.svg b/docs/source/_static/adb.adb_commands.AdbCommands.ConnectDevice.CALL_GRAPH.svg new file mode 100644 index 0000000..7452f60 --- /dev/null +++ b/docs/source/_static/adb.adb_commands.AdbCommands.ConnectDevice.CALL_GRAPH.svg @@ -0,0 +1,33 @@ + + + + + + +adb.adb_commands.AdbCommands.ConnectDevice + + +Node1 + +adb.adb_commands.AdbCommands. +ConnectDevice + + +Node2 + + +adb.adb_commands.AdbCommands. +_Connect + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.adb_commands.AdbCommands.GetState.CALL_GRAPH.svg b/docs/source/_static/adb.adb_commands.AdbCommands.GetState.CALL_GRAPH.svg new file mode 100644 index 0000000..10e0609 --- /dev/null +++ b/docs/source/_static/adb.adb_commands.AdbCommands.GetState.CALL_GRAPH.svg @@ -0,0 +1,70 @@ + + + + + + +adb.adb_commands.AdbCommands.GetState + + +Node1 + +adb.adb_commands.AdbCommands. +GetState + + +Node2 + + +adb.adb_commands.AdbCommands. +Install + + + + +Node1->Node2 + + + + +Node3 + + +adb.adb_commands.AdbCommands.Push + + + + +Node2->Node3 + + + + +Node4 + + +adb.adb_commands.AdbCommands. +Shell + + + + +Node2->Node4 + + + + +Node3->Node3 + + + + +Node3->Node4 + + + + + diff --git a/docs/source/_static/adb.adb_commands.AdbCommands.Install.CALLER_GRAPH.svg b/docs/source/_static/adb.adb_commands.AdbCommands.Install.CALLER_GRAPH.svg new file mode 100644 index 0000000..0fbde81 --- /dev/null +++ b/docs/source/_static/adb.adb_commands.AdbCommands.Install.CALLER_GRAPH.svg @@ -0,0 +1,33 @@ + + + + + + +adb.adb_commands.AdbCommands.Install + + +Node1 + +adb.adb_commands.AdbCommands. +Install + + +Node2 + + +adb.adb_commands.AdbCommands. +GetState + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.adb_commands.AdbCommands.Install.CALL_GRAPH.svg b/docs/source/_static/adb.adb_commands.AdbCommands.Install.CALL_GRAPH.svg new file mode 100644 index 0000000..60043b5 --- /dev/null +++ b/docs/source/_static/adb.adb_commands.AdbCommands.Install.CALL_GRAPH.svg @@ -0,0 +1,56 @@ + + + + + + +adb.adb_commands.AdbCommands.Install + + +Node1 + +adb.adb_commands.AdbCommands. +Install + + +Node2 + + +adb.adb_commands.AdbCommands.Push + + + + +Node1->Node2 + + + + +Node3 + + +adb.adb_commands.AdbCommands. +Shell + + + + +Node1->Node3 + + + + +Node2->Node2 + + + + +Node2->Node3 + + + + + diff --git a/docs/source/_static/adb.adb_commands.AdbCommands.InteractiveShell.CALL_GRAPH.svg b/docs/source/_static/adb.adb_commands.AdbCommands.InteractiveShell.CALL_GRAPH.svg new file mode 100644 index 0000000..7cbf910 --- /dev/null +++ b/docs/source/_static/adb.adb_commands.AdbCommands.InteractiveShell.CALL_GRAPH.svg @@ -0,0 +1,33 @@ + + + + + + +adb.adb_commands.AdbCommands.InteractiveShell + + +Node1 + +adb.adb_commands.AdbCommands. +InteractiveShell + + +Node2 + + +adb.adb_commands.AdbCommands. +_get_service_connection + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.adb_commands.AdbCommands.Logcat.CALL_GRAPH.svg b/docs/source/_static/adb.adb_commands.AdbCommands.Logcat.CALL_GRAPH.svg new file mode 100644 index 0000000..f74302c --- /dev/null +++ b/docs/source/_static/adb.adb_commands.AdbCommands.Logcat.CALL_GRAPH.svg @@ -0,0 +1,33 @@ + + + + + + +adb.adb_commands.AdbCommands.Logcat + + +Node1 + +adb.adb_commands.AdbCommands. +Logcat + + +Node2 + + +adb.adb_commands.AdbCommands. +StreamingShell + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.adb_commands.AdbCommands.Push.CALLER_GRAPH.svg b/docs/source/_static/adb.adb_commands.AdbCommands.Push.CALLER_GRAPH.svg new file mode 100644 index 0000000..46c9118 --- /dev/null +++ b/docs/source/_static/adb.adb_commands.AdbCommands.Push.CALLER_GRAPH.svg @@ -0,0 +1,51 @@ + + + + + + +adb.adb_commands.AdbCommands.Push + + +Node1 + +adb.adb_commands.AdbCommands.Push + + +Node1->Node1 + + + + +Node2 + + +adb.adb_commands.AdbCommands. +Install + + + + +Node1->Node2 + + + + +Node3 + + +adb.adb_commands.AdbCommands. +GetState + + + + +Node2->Node3 + + + + + diff --git a/docs/source/_static/adb.adb_commands.AdbCommands.Push.CALL_GRAPH.svg b/docs/source/_static/adb.adb_commands.AdbCommands.Push.CALL_GRAPH.svg new file mode 100644 index 0000000..91b145b --- /dev/null +++ b/docs/source/_static/adb.adb_commands.AdbCommands.Push.CALL_GRAPH.svg @@ -0,0 +1,37 @@ + + + + + + +adb.adb_commands.AdbCommands.Push + + +Node1 + +adb.adb_commands.AdbCommands.Push + + +Node1->Node1 + + + + +Node2 + + +adb.adb_commands.AdbCommands. +Shell + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.adb_commands.AdbCommands.Reboot.CALLER_GRAPH.svg b/docs/source/_static/adb.adb_commands.AdbCommands.Reboot.CALLER_GRAPH.svg new file mode 100644 index 0000000..4fd353a --- /dev/null +++ b/docs/source/_static/adb.adb_commands.AdbCommands.Reboot.CALLER_GRAPH.svg @@ -0,0 +1,33 @@ + + + + + + +adb.adb_commands.AdbCommands.Reboot + + +Node1 + +adb.adb_commands.AdbCommands. +Reboot + + +Node2 + + +adb.adb_commands.AdbCommands. +RebootBootloader + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.adb_commands.AdbCommands.RebootBootloader.CALL_GRAPH.svg b/docs/source/_static/adb.adb_commands.AdbCommands.RebootBootloader.CALL_GRAPH.svg new file mode 100644 index 0000000..9d4785e --- /dev/null +++ b/docs/source/_static/adb.adb_commands.AdbCommands.RebootBootloader.CALL_GRAPH.svg @@ -0,0 +1,33 @@ + + + + + + +adb.adb_commands.AdbCommands.RebootBootloader + + +Node1 + +adb.adb_commands.AdbCommands. +RebootBootloader + + +Node2 + + +adb.adb_commands.AdbCommands. +Reboot + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.adb_commands.AdbCommands.Shell.CALLER_GRAPH.svg b/docs/source/_static/adb.adb_commands.AdbCommands.Shell.CALLER_GRAPH.svg new file mode 100644 index 0000000..ab0be15 --- /dev/null +++ b/docs/source/_static/adb.adb_commands.AdbCommands.Shell.CALLER_GRAPH.svg @@ -0,0 +1,84 @@ + + + + + + +adb.adb_commands.AdbCommands.Shell + + +Node1 + +adb.adb_commands.AdbCommands. +Shell + + +Node2 + + +adb.adb_commands.AdbCommands. +Install + + + + +Node1->Node2 + + + + +Node4 + + +adb.adb_commands.AdbCommands.Push + + + + +Node1->Node4 + + + + +Node5 + + +adb.adb_commands.AdbCommands. +Uninstall + + + + +Node1->Node5 + + + + +Node3 + + +adb.adb_commands.AdbCommands. +GetState + + + + +Node2->Node3 + + + + +Node4->Node2 + + + + +Node4->Node4 + + + + + diff --git a/docs/source/_static/adb.adb_commands.AdbCommands.Stat.CALLER_GRAPH.svg b/docs/source/_static/adb.adb_commands.AdbCommands.Stat.CALLER_GRAPH.svg new file mode 100644 index 0000000..d2ad899 --- /dev/null +++ b/docs/source/_static/adb.adb_commands.AdbCommands.Stat.CALLER_GRAPH.svg @@ -0,0 +1,32 @@ + + + + + + +adb.adb_commands.AdbCommands.Stat + + +Node1 + +adb.adb_commands.AdbCommands.Stat + + +Node2 + + +adb.filesync_protocol.Filesync +Protocol.Pull + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.adb_commands.AdbCommands.StreamingShell.CALLER_GRAPH.svg b/docs/source/_static/adb.adb_commands.AdbCommands.StreamingShell.CALLER_GRAPH.svg new file mode 100644 index 0000000..c754287 --- /dev/null +++ b/docs/source/_static/adb.adb_commands.AdbCommands.StreamingShell.CALLER_GRAPH.svg @@ -0,0 +1,33 @@ + + + + + + +adb.adb_commands.AdbCommands.StreamingShell + + +Node1 + +adb.adb_commands.AdbCommands. +StreamingShell + + +Node2 + + +adb.adb_commands.AdbCommands. +Logcat + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.adb_commands.AdbCommands.Uninstall.CALL_GRAPH.svg b/docs/source/_static/adb.adb_commands.AdbCommands.Uninstall.CALL_GRAPH.svg new file mode 100644 index 0000000..8955bb2 --- /dev/null +++ b/docs/source/_static/adb.adb_commands.AdbCommands.Uninstall.CALL_GRAPH.svg @@ -0,0 +1,33 @@ + + + + + + +adb.adb_commands.AdbCommands.Uninstall + + +Node1 + +adb.adb_commands.AdbCommands. +Uninstall + + +Node2 + + +adb.adb_commands.AdbCommands. +Shell + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.adb_commands.AdbCommands._Connect.CALLER_GRAPH.svg b/docs/source/_static/adb.adb_commands.AdbCommands._Connect.CALLER_GRAPH.svg new file mode 100644 index 0000000..5b46b81 --- /dev/null +++ b/docs/source/_static/adb.adb_commands.AdbCommands._Connect.CALLER_GRAPH.svg @@ -0,0 +1,33 @@ + + + + + + +adb.adb_commands.AdbCommands._Connect + + +Node1 + +adb.adb_commands.AdbCommands. +_Connect + + +Node2 + + +adb.adb_commands.AdbCommands. +ConnectDevice + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.adb_commands.AdbCommands.__init__.CALLER_GRAPH.svg b/docs/source/_static/adb.adb_commands.AdbCommands.__init__.CALLER_GRAPH.svg new file mode 100644 index 0000000..6441b7d --- /dev/null +++ b/docs/source/_static/adb.adb_commands.AdbCommands.__init__.CALLER_GRAPH.svg @@ -0,0 +1,74 @@ + + + + + + +adb.adb_commands.AdbCommands.__init__ + + +Node1 + +adb.adb_commands.AdbCommands. +__init__ + + +Node2 + + +adb.adb_commands.AdbCommands. +__reset + + + + +Node1->Node2 + + + + +Node5 + + +adb.fastboot.FastbootCommands. +__reset + + + + +Node1->Node5 + + + + +Node3 + + +adb.adb_commands.AdbCommands. +Close + + + + +Node2->Node3 + + + + +Node4 + + +adb.common.UsbHandle.Open + + + + +Node3->Node4 + + + + + diff --git a/docs/source/_static/adb.adb_commands.AdbCommands.__reset.CALLER_GRAPH.svg b/docs/source/_static/adb.adb_commands.AdbCommands.__reset.CALLER_GRAPH.svg new file mode 100644 index 0000000..2f7541a --- /dev/null +++ b/docs/source/_static/adb.adb_commands.AdbCommands.__reset.CALLER_GRAPH.svg @@ -0,0 +1,46 @@ + + + + + + +adb.adb_commands.AdbCommands.__reset + + +Node1 + +adb.adb_commands.AdbCommands. +__reset + + +Node2 + + +adb.adb_commands.AdbCommands. +Close + + + + +Node1->Node2 + + + + +Node3 + + +adb.common.UsbHandle.Open + + + + +Node2->Node3 + + + + + diff --git a/docs/source/_static/adb.adb_commands.AdbCommands.__reset.CALL_GRAPH.svg b/docs/source/_static/adb.adb_commands.AdbCommands.__reset.CALL_GRAPH.svg new file mode 100644 index 0000000..6357ff4 --- /dev/null +++ b/docs/source/_static/adb.adb_commands.AdbCommands.__reset.CALL_GRAPH.svg @@ -0,0 +1,33 @@ + + + + + + +adb.adb_commands.AdbCommands.__reset + + +Node1 + +adb.adb_commands.AdbCommands. +__reset + + +Node2 + + +adb.adb_commands.AdbCommands. +__init__ + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.adb_commands.AdbCommands._get_service_connection.CALLER_GRAPH.svg b/docs/source/_static/adb.adb_commands.AdbCommands._get_service_connection.CALLER_GRAPH.svg new file mode 100644 index 0000000..17ff06d --- /dev/null +++ b/docs/source/_static/adb.adb_commands.AdbCommands._get_service_connection.CALLER_GRAPH.svg @@ -0,0 +1,33 @@ + + + + + + +adb.adb_commands.AdbCommands._get_service_connection + + +Node1 + +adb.adb_commands.AdbCommands. +_get_service_connection + + +Node2 + + +adb.adb_commands.AdbCommands. +InteractiveShell + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.adb_debug.Devices.CALLER_GRAPH.svg b/docs/source/_static/adb.adb_debug.Devices.CALLER_GRAPH.svg new file mode 100644 index 0000000..db4fb16 --- /dev/null +++ b/docs/source/_static/adb.adb_debug.Devices.CALLER_GRAPH.svg @@ -0,0 +1,31 @@ + + + + + + +adb.adb_debug.Devices + + +Node1 + +adb.adb_debug.Devices + + +Node2 + + +adb.adb_debug.main + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.adb_debug.main.CALL_GRAPH.svg b/docs/source/_static/adb.adb_debug.main.CALL_GRAPH.svg new file mode 100644 index 0000000..7c14bd2 --- /dev/null +++ b/docs/source/_static/adb.adb_debug.main.CALL_GRAPH.svg @@ -0,0 +1,31 @@ + + + + + + +adb.adb_debug.main + + +Node1 + +adb.adb_debug.main + + +Node2 + + +adb.adb_debug.Devices + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.adb_protocol.AdbMessage.CALL_GRAPH.svg b/docs/source/_static/adb.adb_protocol.AdbMessage.CALL_GRAPH.svg new file mode 100644 index 0000000..ddb9c6b --- /dev/null +++ b/docs/source/_static/adb.adb_protocol.AdbMessage.CALL_GRAPH.svg @@ -0,0 +1,28 @@ + + + + + + +adb.adb_protocol.AdbMessage + + +Node1 + +adb.adb_protocol.AdbMessage + + +Node2 + +object + + +Node2->Node1 + + + + + diff --git a/docs/source/_static/adb.adb_protocol.AdbMessage.CalculateChecksum.CALLER_GRAPH.svg b/docs/source/_static/adb.adb_protocol.AdbMessage.CalculateChecksum.CALLER_GRAPH.svg new file mode 100644 index 0000000..4a89a24 --- /dev/null +++ b/docs/source/_static/adb.adb_protocol.AdbMessage.CalculateChecksum.CALLER_GRAPH.svg @@ -0,0 +1,140 @@ + + + + + + +adb.adb_protocol.AdbMessage.CalculateChecksum + + +Node1 + +adb.adb_protocol.AdbMessage. +CalculateChecksum + + +Node2 + + +adb.adb_protocol.AdbMessage.checksum + + + + +Node1->Node2 + + + + +Node5 + + +adb.adb_protocol.AdbMessage.Read + + + + +Node1->Node5 + + + + +Node3 + + +adb.adb_protocol.AdbMessage.Pack + + + + +Node2->Node3 + + + + +Node4 + + +adb.adb_protocol.AdbMessage.Send + + + + +Node3->Node4 + + + + +Node6 + + +adb.adb_protocol.AdbMessage. +Connect + + + + +Node5->Node6 + + + + +Node7 + + +adb.adb_protocol.AdbMessage.Open + + + + +Node5->Node7 + + + + +Node10 + + +adb.filesync_protocol.File +SyncConnection.ReadUntil + + + + +Node5->Node10 + + + + +Node8 + + +adb.adb_protocol.AdbMessage. +StreamingCommand + + + + +Node7->Node8 + + + + +Node9 + + +adb.adb_protocol.AdbMessage. +Command + + + + +Node8->Node9 + + + + + diff --git a/docs/source/_static/adb.adb_protocol.AdbMessage.Command.CALL_GRAPH.svg b/docs/source/_static/adb.adb_protocol.AdbMessage.Command.CALL_GRAPH.svg new file mode 100644 index 0000000..6d70e21 --- /dev/null +++ b/docs/source/_static/adb.adb_protocol.AdbMessage.Command.CALL_GRAPH.svg @@ -0,0 +1,87 @@ + + + + + + +adb.adb_protocol.AdbMessage.Command + + +Node1 + +adb.adb_protocol.AdbMessage. +Command + + +Node2 + + +adb.adb_protocol.AdbMessage. +StreamingCommand + + + + +Node1->Node2 + + + + +Node3 + + +adb.adb_protocol.AdbMessage.Open + + + + +Node2->Node3 + + + + +Node4 + + +adb.adb_protocol.AdbMessage.Read + + + + +Node3->Node4 + + + + +Node5 + + +adb.adb_protocol.AdbMessage. +Unpack + + + + +Node4->Node5 + + + + +Node6 + + +adb.adb_protocol.AdbMessage. +CalculateChecksum + + + + +Node4->Node6 + + + + + diff --git a/docs/source/_static/adb.adb_protocol.AdbMessage.Connect.CALL_GRAPH.svg b/docs/source/_static/adb.adb_protocol.AdbMessage.Connect.CALL_GRAPH.svg new file mode 100644 index 0000000..70e7557 --- /dev/null +++ b/docs/source/_static/adb.adb_protocol.AdbMessage.Connect.CALL_GRAPH.svg @@ -0,0 +1,60 @@ + + + + + + +adb.adb_protocol.AdbMessage.Connect + + +Node1 + +adb.adb_protocol.AdbMessage. +Connect + + +Node2 + + +adb.adb_protocol.AdbMessage.Read + + + + +Node1->Node2 + + + + +Node3 + + +adb.adb_protocol.AdbMessage. +Unpack + + + + +Node2->Node3 + + + + +Node4 + + +adb.adb_protocol.AdbMessage. +CalculateChecksum + + + + +Node2->Node4 + + + + + diff --git a/docs/source/_static/adb.adb_protocol.AdbMessage.InteractiveShellCommand.CALL_GRAPH.svg b/docs/source/_static/adb.adb_protocol.AdbMessage.InteractiveShellCommand.CALL_GRAPH.svg new file mode 100644 index 0000000..30bdc77 --- /dev/null +++ b/docs/source/_static/adb.adb_protocol.AdbMessage.InteractiveShellCommand.CALL_GRAPH.svg @@ -0,0 +1,33 @@ + + + + + + +adb.adb_protocol.AdbMessage.InteractiveShellCommand + + +Node1 + +adb.adb_protocol.AdbMessage. +InteractiveShellCommand + + +Node2 + + +adb.adb_protocol.find +_backspace_runs + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.adb_protocol.AdbMessage.Open.CALLER_GRAPH.svg b/docs/source/_static/adb.adb_protocol.AdbMessage.Open.CALLER_GRAPH.svg new file mode 100644 index 0000000..9ccb730 --- /dev/null +++ b/docs/source/_static/adb.adb_protocol.AdbMessage.Open.CALLER_GRAPH.svg @@ -0,0 +1,46 @@ + + + + + + +adb.adb_protocol.AdbMessage.Open + + +Node1 + +adb.adb_protocol.AdbMessage.Open + + +Node2 + + +adb.adb_protocol.AdbMessage. +StreamingCommand + + + + +Node1->Node2 + + + + +Node3 + + +adb.adb_protocol.AdbMessage. +Command + + + + +Node2->Node3 + + + + + diff --git a/docs/source/_static/adb.adb_protocol.AdbMessage.Open.CALL_GRAPH.svg b/docs/source/_static/adb.adb_protocol.AdbMessage.Open.CALL_GRAPH.svg new file mode 100644 index 0000000..4283b1e --- /dev/null +++ b/docs/source/_static/adb.adb_protocol.AdbMessage.Open.CALL_GRAPH.svg @@ -0,0 +1,59 @@ + + + + + + +adb.adb_protocol.AdbMessage.Open + + +Node1 + +adb.adb_protocol.AdbMessage.Open + + +Node2 + + +adb.adb_protocol.AdbMessage.Read + + + + +Node1->Node2 + + + + +Node3 + + +adb.adb_protocol.AdbMessage. +Unpack + + + + +Node2->Node3 + + + + +Node4 + + +adb.adb_protocol.AdbMessage. +CalculateChecksum + + + + +Node2->Node4 + + + + + diff --git a/docs/source/_static/adb.adb_protocol.AdbMessage.Pack.CALLER_GRAPH.svg b/docs/source/_static/adb.adb_protocol.AdbMessage.Pack.CALLER_GRAPH.svg new file mode 100644 index 0000000..fede063 --- /dev/null +++ b/docs/source/_static/adb.adb_protocol.AdbMessage.Pack.CALLER_GRAPH.svg @@ -0,0 +1,31 @@ + + + + + + +adb.adb_protocol.AdbMessage.Pack + + +Node1 + +adb.adb_protocol.AdbMessage.Pack + + +Node2 + + +adb.adb_protocol.AdbMessage.Send + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.adb_protocol.AdbMessage.Pack.CALL_GRAPH.svg b/docs/source/_static/adb.adb_protocol.AdbMessage.Pack.CALL_GRAPH.svg new file mode 100644 index 0000000..6a55f6d --- /dev/null +++ b/docs/source/_static/adb.adb_protocol.AdbMessage.Pack.CALL_GRAPH.svg @@ -0,0 +1,45 @@ + + + + + + +adb.adb_protocol.AdbMessage.Pack + + +Node1 + +adb.adb_protocol.AdbMessage.Pack + + +Node2 + + +adb.adb_protocol.AdbMessage.checksum + + + + +Node1->Node2 + + + + +Node3 + + +adb.adb_protocol.AdbMessage. +CalculateChecksum + + + + +Node2->Node3 + + + + + diff --git a/docs/source/_static/adb.adb_protocol.AdbMessage.Read.CALLER_GRAPH.svg b/docs/source/_static/adb.adb_protocol.AdbMessage.Read.CALLER_GRAPH.svg new file mode 100644 index 0000000..2c19eac --- /dev/null +++ b/docs/source/_static/adb.adb_protocol.AdbMessage.Read.CALLER_GRAPH.svg @@ -0,0 +1,87 @@ + + + + + + +adb.adb_protocol.AdbMessage.Read + + +Node1 + +adb.adb_protocol.AdbMessage.Read + + +Node2 + + +adb.adb_protocol.AdbMessage. +Connect + + + + +Node1->Node2 + + + + +Node3 + + +adb.adb_protocol.AdbMessage.Open + + + + +Node1->Node3 + + + + +Node6 + + +adb.filesync_protocol.File +SyncConnection.ReadUntil + + + + +Node1->Node6 + + + + +Node4 + + +adb.adb_protocol.AdbMessage. +StreamingCommand + + + + +Node3->Node4 + + + + +Node5 + + +adb.adb_protocol.AdbMessage. +Command + + + + +Node4->Node5 + + + + + diff --git a/docs/source/_static/adb.adb_protocol.AdbMessage.Read.CALL_GRAPH.svg b/docs/source/_static/adb.adb_protocol.AdbMessage.Read.CALL_GRAPH.svg new file mode 100644 index 0000000..c6aa34e --- /dev/null +++ b/docs/source/_static/adb.adb_protocol.AdbMessage.Read.CALL_GRAPH.svg @@ -0,0 +1,46 @@ + + + + + + +adb.adb_protocol.AdbMessage.Read + + +Node1 + +adb.adb_protocol.AdbMessage.Read + + +Node2 + + +adb.adb_protocol.AdbMessage. +Unpack + + + + +Node1->Node2 + + + + +Node3 + + +adb.adb_protocol.AdbMessage. +CalculateChecksum + + + + +Node1->Node3 + + + + + diff --git a/docs/source/_static/adb.adb_protocol.AdbMessage.Send.CALL_GRAPH.svg b/docs/source/_static/adb.adb_protocol.AdbMessage.Send.CALL_GRAPH.svg new file mode 100644 index 0000000..d8e0aeb --- /dev/null +++ b/docs/source/_static/adb.adb_protocol.AdbMessage.Send.CALL_GRAPH.svg @@ -0,0 +1,58 @@ + + + + + + +adb.adb_protocol.AdbMessage.Send + + +Node1 + +adb.adb_protocol.AdbMessage.Send + + +Node2 + + +adb.adb_protocol.AdbMessage.Pack + + + + +Node1->Node2 + + + + +Node3 + + +adb.adb_protocol.AdbMessage.checksum + + + + +Node2->Node3 + + + + +Node4 + + +adb.adb_protocol.AdbMessage. +CalculateChecksum + + + + +Node3->Node4 + + + + + diff --git a/docs/source/_static/adb.adb_protocol.AdbMessage.StreamingCommand.CALLER_GRAPH.svg b/docs/source/_static/adb.adb_protocol.AdbMessage.StreamingCommand.CALLER_GRAPH.svg new file mode 100644 index 0000000..d372912 --- /dev/null +++ b/docs/source/_static/adb.adb_protocol.AdbMessage.StreamingCommand.CALLER_GRAPH.svg @@ -0,0 +1,33 @@ + + + + + + +adb.adb_protocol.AdbMessage.StreamingCommand + + +Node1 + +adb.adb_protocol.AdbMessage. +StreamingCommand + + +Node2 + + +adb.adb_protocol.AdbMessage. +Command + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.adb_protocol.AdbMessage.StreamingCommand.CALL_GRAPH.svg b/docs/source/_static/adb.adb_protocol.AdbMessage.StreamingCommand.CALL_GRAPH.svg new file mode 100644 index 0000000..3c61c00 --- /dev/null +++ b/docs/source/_static/adb.adb_protocol.AdbMessage.StreamingCommand.CALL_GRAPH.svg @@ -0,0 +1,73 @@ + + + + + + +adb.adb_protocol.AdbMessage.StreamingCommand + + +Node1 + +adb.adb_protocol.AdbMessage. +StreamingCommand + + +Node2 + + +adb.adb_protocol.AdbMessage.Open + + + + +Node1->Node2 + + + + +Node3 + + +adb.adb_protocol.AdbMessage.Read + + + + +Node2->Node3 + + + + +Node4 + + +adb.adb_protocol.AdbMessage. +Unpack + + + + +Node3->Node4 + + + + +Node5 + + +adb.adb_protocol.AdbMessage. +CalculateChecksum + + + + +Node3->Node5 + + + + + diff --git a/docs/source/_static/adb.adb_protocol.AdbMessage.Unpack.CALLER_GRAPH.svg b/docs/source/_static/adb.adb_protocol.AdbMessage.Unpack.CALLER_GRAPH.svg new file mode 100644 index 0000000..c3a57c8 --- /dev/null +++ b/docs/source/_static/adb.adb_protocol.AdbMessage.Unpack.CALLER_GRAPH.svg @@ -0,0 +1,101 @@ + + + + + + +adb.adb_protocol.AdbMessage.Unpack + + +Node1 + +adb.adb_protocol.AdbMessage. +Unpack + + +Node2 + + +adb.adb_protocol.AdbMessage.Read + + + + +Node1->Node2 + + + + +Node3 + + +adb.adb_protocol.AdbMessage. +Connect + + + + +Node2->Node3 + + + + +Node4 + + +adb.adb_protocol.AdbMessage.Open + + + + +Node2->Node4 + + + + +Node7 + + +adb.filesync_protocol.File +SyncConnection.ReadUntil + + + + +Node2->Node7 + + + + +Node5 + + +adb.adb_protocol.AdbMessage. +StreamingCommand + + + + +Node4->Node5 + + + + +Node6 + + +adb.adb_protocol.AdbMessage. +Command + + + + +Node5->Node6 + + + + + diff --git a/docs/source/_static/adb.adb_protocol.AdbMessage.__init__.CALLER_GRAPH.svg b/docs/source/_static/adb.adb_protocol.AdbMessage.__init__.CALLER_GRAPH.svg new file mode 100644 index 0000000..60bc60c --- /dev/null +++ b/docs/source/_static/adb.adb_protocol.AdbMessage.__init__.CALLER_GRAPH.svg @@ -0,0 +1,33 @@ + + + + + + +adb.adb_protocol.AdbMessage.__init__ + + +Node1 + +adb.adb_protocol.AdbMessage. +__init__ + + +Node2 + + +adb.fastboot.FastbootCommands. +__reset + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.adb_protocol.AdbMessage.checksum.CALLER_GRAPH.svg b/docs/source/_static/adb.adb_protocol.AdbMessage.checksum.CALLER_GRAPH.svg new file mode 100644 index 0000000..33c0eb4 --- /dev/null +++ b/docs/source/_static/adb.adb_protocol.AdbMessage.checksum.CALLER_GRAPH.svg @@ -0,0 +1,44 @@ + + + + + + +adb.adb_protocol.AdbMessage.checksum + + +Node1 + +adb.adb_protocol.AdbMessage.checksum + + +Node2 + + +adb.adb_protocol.AdbMessage.Pack + + + + +Node1->Node2 + + + + +Node3 + + +adb.adb_protocol.AdbMessage.Send + + + + +Node2->Node3 + + + + + diff --git a/docs/source/_static/adb.adb_protocol.AdbMessage.checksum.CALL_GRAPH.svg b/docs/source/_static/adb.adb_protocol.AdbMessage.checksum.CALL_GRAPH.svg new file mode 100644 index 0000000..cac01ea --- /dev/null +++ b/docs/source/_static/adb.adb_protocol.AdbMessage.checksum.CALL_GRAPH.svg @@ -0,0 +1,32 @@ + + + + + + +adb.adb_protocol.AdbMessage.checksum + + +Node1 + +adb.adb_protocol.AdbMessage.checksum + + +Node2 + + +adb.adb_protocol.AdbMessage. +CalculateChecksum + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.adb_protocol.AuthSigner.CALL_GRAPH.svg b/docs/source/_static/adb.adb_protocol.AuthSigner.CALL_GRAPH.svg new file mode 100644 index 0000000..d9bb1f7 --- /dev/null +++ b/docs/source/_static/adb.adb_protocol.AuthSigner.CALL_GRAPH.svg @@ -0,0 +1,28 @@ + + + + + + +adb.adb_protocol.AuthSigner + + +Node1 + +adb.adb_protocol.AuthSigner + + +Node2 + +object + + +Node2->Node1 + + + + + diff --git a/docs/source/_static/adb.adb_protocol.InterleavedDataError.CALL_GRAPH.svg b/docs/source/_static/adb.adb_protocol.InterleavedDataError.CALL_GRAPH.svg new file mode 100644 index 0000000..b4679b3 --- /dev/null +++ b/docs/source/_static/adb.adb_protocol.InterleavedDataError.CALL_GRAPH.svg @@ -0,0 +1,29 @@ + + + + + + +adb.adb_protocol.InterleavedDataError + + +Node1 + +adb.adb_protocol.Interleaved +DataError + + +Node2 + +Exception + + +Node2->Node1 + + + + + diff --git a/docs/source/_static/adb.adb_protocol.InvalidChecksumError.CALL_GRAPH.svg b/docs/source/_static/adb.adb_protocol.InvalidChecksumError.CALL_GRAPH.svg new file mode 100644 index 0000000..7f7e499 --- /dev/null +++ b/docs/source/_static/adb.adb_protocol.InvalidChecksumError.CALL_GRAPH.svg @@ -0,0 +1,29 @@ + + + + + + +adb.adb_protocol.InvalidChecksumError + + +Node1 + +adb.adb_protocol.Invalid +ChecksumError + + +Node2 + +Exception + + +Node2->Node1 + + + + + diff --git a/docs/source/_static/adb.adb_protocol.InvalidCommandError.CALL_GRAPH.svg b/docs/source/_static/adb.adb_protocol.InvalidCommandError.CALL_GRAPH.svg new file mode 100644 index 0000000..96bd5a3 --- /dev/null +++ b/docs/source/_static/adb.adb_protocol.InvalidCommandError.CALL_GRAPH.svg @@ -0,0 +1,29 @@ + + + + + + +adb.adb_protocol.InvalidCommandError + + +Node1 + +adb.adb_protocol.Invalid +CommandError + + +Node2 + +Exception + + +Node2->Node1 + + + + + diff --git a/docs/source/_static/adb.adb_protocol.InvalidCommandError.__init__.CALLER_GRAPH.svg b/docs/source/_static/adb.adb_protocol.InvalidCommandError.__init__.CALLER_GRAPH.svg new file mode 100644 index 0000000..2a15d71 --- /dev/null +++ b/docs/source/_static/adb.adb_protocol.InvalidCommandError.__init__.CALLER_GRAPH.svg @@ -0,0 +1,33 @@ + + + + + + +adb.adb_protocol.InvalidCommandError.__init__ + + +Node1 + +adb.adb_protocol.Invalid +CommandError.__init__ + + +Node2 + + +adb.fastboot.FastbootCommands. +__reset + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.adb_protocol.InvalidResponseError.CALL_GRAPH.svg b/docs/source/_static/adb.adb_protocol.InvalidResponseError.CALL_GRAPH.svg new file mode 100644 index 0000000..78a9e64 --- /dev/null +++ b/docs/source/_static/adb.adb_protocol.InvalidResponseError.CALL_GRAPH.svg @@ -0,0 +1,29 @@ + + + + + + +adb.adb_protocol.InvalidResponseError + + +Node1 + +adb.adb_protocol.Invalid +ResponseError + + +Node2 + +Exception + + +Node2->Node1 + + + + + diff --git a/docs/source/_static/adb.adb_protocol._AdbConnection.CALL_GRAPH.svg b/docs/source/_static/adb.adb_protocol._AdbConnection.CALL_GRAPH.svg new file mode 100644 index 0000000..50b9ec9 --- /dev/null +++ b/docs/source/_static/adb.adb_protocol._AdbConnection.CALL_GRAPH.svg @@ -0,0 +1,28 @@ + + + + + + +adb.adb_protocol._AdbConnection + + +Node1 + +adb.adb_protocol._AdbConnection + + +Node2 + +object + + +Node2->Node1 + + + + + diff --git a/docs/source/_static/adb.adb_protocol._AdbConnection.Close.CALLER_GRAPH.svg b/docs/source/_static/adb.adb_protocol._AdbConnection.Close.CALLER_GRAPH.svg new file mode 100644 index 0000000..85a27ec --- /dev/null +++ b/docs/source/_static/adb.adb_protocol._AdbConnection.Close.CALLER_GRAPH.svg @@ -0,0 +1,32 @@ + + + + + + +adb.adb_protocol._AdbConnection.Close + + +Node1 + +adb.adb_protocol._AdbConnection. +Close + + +Node2 + + +adb.common.UsbHandle.Open + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.adb_protocol._AdbConnection.Close.CALL_GRAPH.svg b/docs/source/_static/adb.adb_protocol._AdbConnection.Close.CALL_GRAPH.svg new file mode 100644 index 0000000..de29bf2 --- /dev/null +++ b/docs/source/_static/adb.adb_protocol._AdbConnection.Close.CALL_GRAPH.svg @@ -0,0 +1,64 @@ + + + + + + +adb.adb_protocol._AdbConnection.Close + + +Node1 + +adb.adb_protocol._AdbConnection. +Close + + +Node2 + + +adb.adb_protocol._AdbConnection._Send + + + + +Node1->Node2 + + + + +Node3 + + +adb.adb_protocol._AdbConnection. +ReadUntil + + + + +Node1->Node3 + + + + +Node4 + + +adb.adb_protocol._AdbConnection.Okay + + + + +Node3->Node4 + + + + +Node4->Node2 + + + + + diff --git a/docs/source/_static/adb.adb_protocol._AdbConnection.Okay.CALLER_GRAPH.svg b/docs/source/_static/adb.adb_protocol._AdbConnection.Okay.CALLER_GRAPH.svg new file mode 100644 index 0000000..d94bd71 --- /dev/null +++ b/docs/source/_static/adb.adb_protocol._AdbConnection.Okay.CALLER_GRAPH.svg @@ -0,0 +1,87 @@ + + + + + + +adb.adb_protocol._AdbConnection.Okay + + +Node1 + +adb.adb_protocol._AdbConnection.Okay + + +Node2 + + +adb.adb_protocol._AdbConnection. +ReadUntil + + + + +Node1->Node2 + + + + +Node3 + + +adb.adb_protocol._AdbConnection. +Write + + + + +Node2->Node3 + + + + +Node4 + + +adb.adb_protocol._AdbConnection. +ReadUntilClose + + + + +Node2->Node4 + + + + +Node5 + + +adb.adb_protocol._AdbConnection. +Close + + + + +Node2->Node5 + + + + +Node6 + + +adb.common.UsbHandle.Open + + + + +Node5->Node6 + + + + + diff --git a/docs/source/_static/adb.adb_protocol._AdbConnection.Okay.CALL_GRAPH.svg b/docs/source/_static/adb.adb_protocol._AdbConnection.Okay.CALL_GRAPH.svg new file mode 100644 index 0000000..5d748bf --- /dev/null +++ b/docs/source/_static/adb.adb_protocol._AdbConnection.Okay.CALL_GRAPH.svg @@ -0,0 +1,31 @@ + + + + + + +adb.adb_protocol._AdbConnection.Okay + + +Node1 + +adb.adb_protocol._AdbConnection.Okay + + +Node2 + + +adb.adb_protocol._AdbConnection._Send + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.adb_protocol._AdbConnection.ReadUntil.CALLER_GRAPH.svg b/docs/source/_static/adb.adb_protocol._AdbConnection.ReadUntil.CALLER_GRAPH.svg new file mode 100644 index 0000000..0c4d024 --- /dev/null +++ b/docs/source/_static/adb.adb_protocol._AdbConnection.ReadUntil.CALLER_GRAPH.svg @@ -0,0 +1,74 @@ + + + + + + +adb.adb_protocol._AdbConnection.ReadUntil + + +Node1 + +adb.adb_protocol._AdbConnection. +ReadUntil + + +Node2 + + +adb.adb_protocol._AdbConnection. +Close + + + + +Node1->Node2 + + + + +Node4 + + +adb.adb_protocol._AdbConnection. +ReadUntilClose + + + + +Node1->Node4 + + + + +Node5 + + +adb.adb_protocol._AdbConnection. +Write + + + + +Node1->Node5 + + + + +Node3 + + +adb.common.UsbHandle.Open + + + + +Node2->Node3 + + + + + diff --git a/docs/source/_static/adb.adb_protocol._AdbConnection.ReadUntil.CALL_GRAPH.svg b/docs/source/_static/adb.adb_protocol._AdbConnection.ReadUntil.CALL_GRAPH.svg new file mode 100644 index 0000000..3c4ca0c --- /dev/null +++ b/docs/source/_static/adb.adb_protocol._AdbConnection.ReadUntil.CALL_GRAPH.svg @@ -0,0 +1,45 @@ + + + + + + +adb.adb_protocol._AdbConnection.ReadUntil + + +Node1 + +adb.adb_protocol._AdbConnection. +ReadUntil + + +Node2 + + +adb.adb_protocol._AdbConnection.Okay + + + + +Node1->Node2 + + + + +Node3 + + +adb.adb_protocol._AdbConnection._Send + + + + +Node2->Node3 + + + + + diff --git a/docs/source/_static/adb.adb_protocol._AdbConnection.ReadUntilClose.CALL_GRAPH.svg b/docs/source/_static/adb.adb_protocol._AdbConnection.ReadUntilClose.CALL_GRAPH.svg new file mode 100644 index 0000000..db806fc --- /dev/null +++ b/docs/source/_static/adb.adb_protocol._AdbConnection.ReadUntilClose.CALL_GRAPH.svg @@ -0,0 +1,64 @@ + + + + + + +adb.adb_protocol._AdbConnection.ReadUntilClose + + +Node1 + +adb.adb_protocol._AdbConnection. +ReadUntilClose + + +Node2 + + +adb.adb_protocol._AdbConnection. +ReadUntil + + + + +Node1->Node2 + + + + +Node4 + + +adb.adb_protocol._AdbConnection._Send + + + + +Node1->Node4 + + + + +Node3 + + +adb.adb_protocol._AdbConnection.Okay + + + + +Node2->Node3 + + + + +Node3->Node4 + + + + + diff --git a/docs/source/_static/adb.adb_protocol._AdbConnection.Write.CALL_GRAPH.svg b/docs/source/_static/adb.adb_protocol._AdbConnection.Write.CALL_GRAPH.svg new file mode 100644 index 0000000..030306e --- /dev/null +++ b/docs/source/_static/adb.adb_protocol._AdbConnection.Write.CALL_GRAPH.svg @@ -0,0 +1,64 @@ + + + + + + +adb.adb_protocol._AdbConnection.Write + + +Node1 + +adb.adb_protocol._AdbConnection. +Write + + +Node2 + + +adb.adb_protocol._AdbConnection._Send + + + + +Node1->Node2 + + + + +Node3 + + +adb.adb_protocol._AdbConnection. +ReadUntil + + + + +Node1->Node3 + + + + +Node4 + + +adb.adb_protocol._AdbConnection.Okay + + + + +Node3->Node4 + + + + +Node4->Node2 + + + + + diff --git a/docs/source/_static/adb.adb_protocol._AdbConnection._Send.CALLER_GRAPH.svg b/docs/source/_static/adb.adb_protocol._AdbConnection._Send.CALLER_GRAPH.svg new file mode 100644 index 0000000..17ea54a --- /dev/null +++ b/docs/source/_static/adb.adb_protocol._AdbConnection._Send.CALLER_GRAPH.svg @@ -0,0 +1,115 @@ + + + + + + +adb.adb_protocol._AdbConnection._Send + + +Node1 + +adb.adb_protocol._AdbConnection._Send + + +Node2 + + +adb.adb_protocol._AdbConnection. +Close + + + + +Node1->Node2 + + + + +Node4 + + +adb.adb_protocol._AdbConnection.Okay + + + + +Node1->Node4 + + + + +Node6 + + +adb.adb_protocol._AdbConnection. +Write + + + + +Node1->Node6 + + + + +Node7 + + +adb.adb_protocol._AdbConnection. +ReadUntilClose + + + + +Node1->Node7 + + + + +Node3 + + +adb.common.UsbHandle.Open + + + + +Node2->Node3 + + + + +Node5 + + +adb.adb_protocol._AdbConnection. +ReadUntil + + + + +Node4->Node5 + + + + +Node5->Node2 + + + + +Node5->Node6 + + + + +Node5->Node7 + + + + + diff --git a/docs/source/_static/adb.adb_protocol._AdbConnection.__init__.CALLER_GRAPH.svg b/docs/source/_static/adb.adb_protocol._AdbConnection.__init__.CALLER_GRAPH.svg new file mode 100644 index 0000000..ea8ba7e --- /dev/null +++ b/docs/source/_static/adb.adb_protocol._AdbConnection.__init__.CALLER_GRAPH.svg @@ -0,0 +1,33 @@ + + + + + + +adb.adb_protocol._AdbConnection.__init__ + + +Node1 + +adb.adb_protocol._AdbConnection. +__init__ + + +Node2 + + +adb.fastboot.FastbootCommands. +__reset + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.adb_protocol.find_backspace_runs.CALLER_GRAPH.svg b/docs/source/_static/adb.adb_protocol.find_backspace_runs.CALLER_GRAPH.svg new file mode 100644 index 0000000..6465457 --- /dev/null +++ b/docs/source/_static/adb.adb_protocol.find_backspace_runs.CALLER_GRAPH.svg @@ -0,0 +1,33 @@ + + + + + + +adb.adb_protocol.find_backspace_runs + + +Node1 + +adb.adb_protocol.find +_backspace_runs + + +Node2 + + +adb.adb_protocol.AdbMessage. +InteractiveShellCommand + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.common.GetInterface.CALLER_GRAPH.svg b/docs/source/_static/adb.common.GetInterface.CALLER_GRAPH.svg new file mode 100644 index 0000000..95f33eb --- /dev/null +++ b/docs/source/_static/adb.common.GetInterface.CALLER_GRAPH.svg @@ -0,0 +1,31 @@ + + + + + + +adb.common.GetInterface + + +Node1 + +adb.common.GetInterface + + +Node2 + + +adb.common.InterfaceMatcher + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.common.InterfaceMatcher.CALL_GRAPH.svg b/docs/source/_static/adb.common.InterfaceMatcher.CALL_GRAPH.svg new file mode 100644 index 0000000..b1f7adc --- /dev/null +++ b/docs/source/_static/adb.common.InterfaceMatcher.CALL_GRAPH.svg @@ -0,0 +1,31 @@ + + + + + + +adb.common.InterfaceMatcher + + +Node1 + +adb.common.InterfaceMatcher + + +Node2 + + +adb.common.GetInterface + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.common.TcpHandle.BulkRead.CALL_GRAPH.svg b/docs/source/_static/adb.common.TcpHandle.BulkRead.CALL_GRAPH.svg new file mode 100644 index 0000000..49dcba8 --- /dev/null +++ b/docs/source/_static/adb.common.TcpHandle.BulkRead.CALL_GRAPH.svg @@ -0,0 +1,58 @@ + + + + + + +adb.common.TcpHandle.BulkRead + + +Node1 + +adb.common.TcpHandle.BulkRead + + +Node2 + + +adb.common.TcpHandle.Timeout +Seconds + + + + +Node1->Node2 + + + + +Node3 + + +adb.common.UsbHandle.Timeout + + + + +Node2->Node3 + + + + +Node4 + + +adb.common.TcpHandle.Timeout + + + + +Node2->Node4 + + + + + diff --git a/docs/source/_static/adb.common.TcpHandle.BulkWrite.CALL_GRAPH.svg b/docs/source/_static/adb.common.TcpHandle.BulkWrite.CALL_GRAPH.svg new file mode 100644 index 0000000..114351f --- /dev/null +++ b/docs/source/_static/adb.common.TcpHandle.BulkWrite.CALL_GRAPH.svg @@ -0,0 +1,87 @@ + + + + + + +adb.common.TcpHandle.BulkWrite + + +Node1 + +adb.common.TcpHandle.Bulk +Write + + +Node2 + + +adb.common.TcpHandle.Timeout +Seconds + + + + +Node1->Node2 + + + + +Node5 + + +adb.common.UsbHandle.serial +_number + + + + +Node1->Node5 + + + + +Node6 + + +adb.common.TcpHandle.serial +_number + + + + +Node1->Node6 + + + + +Node3 + + +adb.common.UsbHandle.Timeout + + + + +Node2->Node3 + + + + +Node4 + + +adb.common.TcpHandle.Timeout + + + + +Node2->Node4 + + + + + diff --git a/docs/source/_static/adb.common.TcpHandle.CALL_GRAPH.svg b/docs/source/_static/adb.common.TcpHandle.CALL_GRAPH.svg new file mode 100644 index 0000000..cc7a211 --- /dev/null +++ b/docs/source/_static/adb.common.TcpHandle.CALL_GRAPH.svg @@ -0,0 +1,28 @@ + + + + + + +adb.common.TcpHandle + + +Node1 + +adb.common.TcpHandle + + +Node2 + +object + + +Node2->Node1 + + + + + diff --git a/docs/source/_static/adb.common.TcpHandle.Timeout.CALLER_GRAPH.svg b/docs/source/_static/adb.common.TcpHandle.Timeout.CALLER_GRAPH.svg new file mode 100644 index 0000000..4246645 --- /dev/null +++ b/docs/source/_static/adb.common.TcpHandle.Timeout.CALLER_GRAPH.svg @@ -0,0 +1,73 @@ + + + + + + +adb.common.TcpHandle.Timeout + + +Node1 + +adb.common.TcpHandle.Timeout + + +Node2 + + +adb.common.TcpHandle.Timeout +Seconds + + + + +Node1->Node2 + + + + +Node3 + + +adb.common.TcpHandle. +_connect + + + + +Node2->Node3 + + + + +Node4 + + +adb.common.TcpHandle.Bulk +Write + + + + +Node2->Node4 + + + + +Node5 + + +adb.common.TcpHandle.BulkRead + + + + +Node2->Node5 + + + + + diff --git a/docs/source/_static/adb.common.TcpHandle.TimeoutSeconds.CALLER_GRAPH.svg b/docs/source/_static/adb.common.TcpHandle.TimeoutSeconds.CALLER_GRAPH.svg new file mode 100644 index 0000000..46c573b --- /dev/null +++ b/docs/source/_static/adb.common.TcpHandle.TimeoutSeconds.CALLER_GRAPH.svg @@ -0,0 +1,60 @@ + + + + + + +adb.common.TcpHandle.TimeoutSeconds + + +Node1 + +adb.common.TcpHandle.Timeout +Seconds + + +Node2 + + +adb.common.TcpHandle. +_connect + + + + +Node1->Node2 + + + + +Node3 + + +adb.common.TcpHandle.BulkRead + + + + +Node1->Node3 + + + + +Node4 + + +adb.common.TcpHandle.Bulk +Write + + + + +Node1->Node4 + + + + + diff --git a/docs/source/_static/adb.common.TcpHandle.TimeoutSeconds.CALL_GRAPH.svg b/docs/source/_static/adb.common.TcpHandle.TimeoutSeconds.CALL_GRAPH.svg new file mode 100644 index 0000000..ef22147 --- /dev/null +++ b/docs/source/_static/adb.common.TcpHandle.TimeoutSeconds.CALL_GRAPH.svg @@ -0,0 +1,45 @@ + + + + + + +adb.common.TcpHandle.TimeoutSeconds + + +Node1 + +adb.common.TcpHandle.Timeout +Seconds + + +Node2 + + +adb.common.UsbHandle.Timeout + + + + +Node1->Node2 + + + + +Node3 + + +adb.common.TcpHandle.Timeout + + + + +Node1->Node3 + + + + + diff --git a/docs/source/_static/adb.common.TcpHandle.__init__.CALLER_GRAPH.svg b/docs/source/_static/adb.common.TcpHandle.__init__.CALLER_GRAPH.svg new file mode 100644 index 0000000..383d7ca --- /dev/null +++ b/docs/source/_static/adb.common.TcpHandle.__init__.CALLER_GRAPH.svg @@ -0,0 +1,33 @@ + + + + + + +adb.common.TcpHandle.__init__ + + +Node1 + +adb.common.TcpHandle. +__init__ + + +Node2 + + +adb.fastboot.FastbootCommands. +__reset + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.common.TcpHandle._connect.CALL_GRAPH.svg b/docs/source/_static/adb.common.TcpHandle._connect.CALL_GRAPH.svg new file mode 100644 index 0000000..b486258 --- /dev/null +++ b/docs/source/_static/adb.common.TcpHandle._connect.CALL_GRAPH.svg @@ -0,0 +1,59 @@ + + + + + + +adb.common.TcpHandle._connect + + +Node1 + +adb.common.TcpHandle. +_connect + + +Node2 + + +adb.common.TcpHandle.Timeout +Seconds + + + + +Node1->Node2 + + + + +Node3 + + +adb.common.UsbHandle.Timeout + + + + +Node2->Node3 + + + + +Node4 + + +adb.common.TcpHandle.Timeout + + + + +Node2->Node4 + + + + + diff --git a/docs/source/_static/adb.common.TcpHandle.serial_number.CALLER_GRAPH.svg b/docs/source/_static/adb.common.TcpHandle.serial_number.CALLER_GRAPH.svg new file mode 100644 index 0000000..7fb0747 --- /dev/null +++ b/docs/source/_static/adb.common.TcpHandle.serial_number.CALLER_GRAPH.svg @@ -0,0 +1,33 @@ + + + + + + +adb.common.TcpHandle.serial_number + + +Node1 + +adb.common.TcpHandle.serial +_number + + +Node2 + + +adb.common.TcpHandle.Bulk +Write + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.common.UsbHandle.BulkRead.CALLER_GRAPH.svg b/docs/source/_static/adb.common.UsbHandle.BulkRead.CALLER_GRAPH.svg new file mode 100644 index 0000000..1eec197 --- /dev/null +++ b/docs/source/_static/adb.common.UsbHandle.BulkRead.CALLER_GRAPH.svg @@ -0,0 +1,32 @@ + + + + + + +adb.common.UsbHandle.BulkRead + + +Node1 + +adb.common.UsbHandle.BulkRead + + +Node2 + + +adb.common.UsbHandle.Flush +Buffers + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.common.UsbHandle.BulkRead.CALL_GRAPH.svg b/docs/source/_static/adb.common.UsbHandle.BulkRead.CALL_GRAPH.svg new file mode 100644 index 0000000..60b1666 --- /dev/null +++ b/docs/source/_static/adb.common.UsbHandle.BulkRead.CALL_GRAPH.svg @@ -0,0 +1,58 @@ + + + + + + +adb.common.UsbHandle.BulkRead + + +Node1 + +adb.common.UsbHandle.BulkRead + + +Node2 + + +adb.common.UsbHandle.Timeout + + + + +Node1->Node2 + + + + +Node3 + + +adb.common.UsbHandle.usb_info + + + + +Node1->Node3 + + + + +Node4 + + +adb.common.UsbHandle.serial +_number + + + + +Node3->Node4 + + + + + diff --git a/docs/source/_static/adb.common.UsbHandle.BulkWrite.CALL_GRAPH.svg b/docs/source/_static/adb.common.UsbHandle.BulkWrite.CALL_GRAPH.svg new file mode 100644 index 0000000..20510d9 --- /dev/null +++ b/docs/source/_static/adb.common.UsbHandle.BulkWrite.CALL_GRAPH.svg @@ -0,0 +1,59 @@ + + + + + + +adb.common.UsbHandle.BulkWrite + + +Node1 + +adb.common.UsbHandle.Bulk +Write + + +Node2 + + +adb.common.UsbHandle.Timeout + + + + +Node1->Node2 + + + + +Node3 + + +adb.common.UsbHandle.usb_info + + + + +Node1->Node3 + + + + +Node4 + + +adb.common.UsbHandle.serial +_number + + + + +Node3->Node4 + + + + + diff --git a/docs/source/_static/adb.common.UsbHandle.CALL_GRAPH.svg b/docs/source/_static/adb.common.UsbHandle.CALL_GRAPH.svg new file mode 100644 index 0000000..5069fa9 --- /dev/null +++ b/docs/source/_static/adb.common.UsbHandle.CALL_GRAPH.svg @@ -0,0 +1,28 @@ + + + + + + +adb.common.UsbHandle + + +Node1 + +adb.common.UsbHandle + + +Node2 + +object + + +Node2->Node1 + + + + + diff --git a/docs/source/_static/adb.common.UsbHandle.Close.CALLER_GRAPH.svg b/docs/source/_static/adb.common.UsbHandle.Close.CALLER_GRAPH.svg new file mode 100644 index 0000000..e8a1bb2 --- /dev/null +++ b/docs/source/_static/adb.common.UsbHandle.Close.CALLER_GRAPH.svg @@ -0,0 +1,31 @@ + + + + + + +adb.common.UsbHandle.Close + + +Node1 + +adb.common.UsbHandle.Close + + +Node2 + + +adb.common.UsbHandle.Open + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.common.UsbHandle.Close.CALL_GRAPH.svg b/docs/source/_static/adb.common.UsbHandle.Close.CALL_GRAPH.svg new file mode 100644 index 0000000..f5a6c33 --- /dev/null +++ b/docs/source/_static/adb.common.UsbHandle.Close.CALL_GRAPH.svg @@ -0,0 +1,45 @@ + + + + + + +adb.common.UsbHandle.Close + + +Node1 + +adb.common.UsbHandle.Close + + +Node2 + + +adb.common.UsbHandle.usb_info + + + + +Node1->Node2 + + + + +Node3 + + +adb.common.UsbHandle.serial +_number + + + + +Node2->Node3 + + + + + diff --git a/docs/source/_static/adb.common.UsbHandle.Find.CALLER_GRAPH.svg b/docs/source/_static/adb.common.UsbHandle.Find.CALLER_GRAPH.svg new file mode 100644 index 0000000..9d1f1dd --- /dev/null +++ b/docs/source/_static/adb.common.UsbHandle.Find.CALLER_GRAPH.svg @@ -0,0 +1,51 @@ + + + + + + +adb.common.UsbHandle.Find + + +Node1 + +adb.common.UsbHandle.Find + + +Node2 + + +adb.common.UsbHandle.Find +AndOpen + + + + +Node1->Node2 + + + + +Node3 + + +adb.common.UsbHandle.Serial +Matcher + + + + +Node2->Node3 + + + + +Node3->Node1 + + + + + diff --git a/docs/source/_static/adb.common.UsbHandle.Find.CALL_GRAPH.svg b/docs/source/_static/adb.common.UsbHandle.Find.CALL_GRAPH.svg new file mode 100644 index 0000000..886caab --- /dev/null +++ b/docs/source/_static/adb.common.UsbHandle.Find.CALL_GRAPH.svg @@ -0,0 +1,93 @@ + + + + + + +adb.common.UsbHandle.Find + + +Node1 + +adb.common.UsbHandle.Find + + +Node2 + + +adb.common.UsbHandle.Port +PathMatcher + + + + +Node1->Node2 + + + + +Node3 + + +adb.common.UsbHandle.Serial +Matcher + + + + +Node1->Node3 + + + + +Node5 + + +adb.common.UsbHandle.Find +First + + + + +Node1->Node5 + + + + +Node4 + + +adb.common.UsbHandle.Find +AndOpen + + + + +Node3->Node4 + + + + +Node4->Node1 + + + + +Node6 + + +adb.common.UsbHandle.Find +Devices + + + + +Node5->Node6 + + + + + diff --git a/docs/source/_static/adb.common.UsbHandle.FindAndOpen.CALLER_GRAPH.svg b/docs/source/_static/adb.common.UsbHandle.FindAndOpen.CALLER_GRAPH.svg new file mode 100644 index 0000000..cd799a3 --- /dev/null +++ b/docs/source/_static/adb.common.UsbHandle.FindAndOpen.CALLER_GRAPH.svg @@ -0,0 +1,51 @@ + + + + + + +adb.common.UsbHandle.FindAndOpen + + +Node1 + +adb.common.UsbHandle.Find +AndOpen + + +Node2 + + +adb.common.UsbHandle.Serial +Matcher + + + + +Node1->Node2 + + + + +Node3 + + +adb.common.UsbHandle.Find + + + + +Node2->Node3 + + + + +Node3->Node1 + + + + + diff --git a/docs/source/_static/adb.common.UsbHandle.FindAndOpen.CALL_GRAPH.svg b/docs/source/_static/adb.common.UsbHandle.FindAndOpen.CALL_GRAPH.svg new file mode 100644 index 0000000..4f4b7e7 --- /dev/null +++ b/docs/source/_static/adb.common.UsbHandle.FindAndOpen.CALL_GRAPH.svg @@ -0,0 +1,93 @@ + + + + + + +adb.common.UsbHandle.FindAndOpen + + +Node1 + +adb.common.UsbHandle.Find +AndOpen + + +Node2 + + +adb.common.UsbHandle.Find + + + + +Node1->Node2 + + + + +Node3 + + +adb.common.UsbHandle.Port +PathMatcher + + + + +Node2->Node3 + + + + +Node4 + + +adb.common.UsbHandle.Serial +Matcher + + + + +Node2->Node4 + + + + +Node5 + + +adb.common.UsbHandle.Find +First + + + + +Node2->Node5 + + + + +Node4->Node1 + + + + +Node6 + + +adb.common.UsbHandle.Find +Devices + + + + +Node5->Node6 + + + + + diff --git a/docs/source/_static/adb.common.UsbHandle.FindDevices.CALLER_GRAPH.svg b/docs/source/_static/adb.common.UsbHandle.FindDevices.CALLER_GRAPH.svg new file mode 100644 index 0000000..9cb9419 --- /dev/null +++ b/docs/source/_static/adb.common.UsbHandle.FindDevices.CALLER_GRAPH.svg @@ -0,0 +1,79 @@ + + + + + + +adb.common.UsbHandle.FindDevices + + +Node1 + +adb.common.UsbHandle.Find +Devices + + +Node2 + + +adb.common.UsbHandle.Find +First + + + + +Node1->Node2 + + + + +Node3 + + +adb.common.UsbHandle.Find + + + + +Node2->Node3 + + + + +Node4 + + +adb.common.UsbHandle.Find +AndOpen + + + + +Node3->Node4 + + + + +Node5 + + +adb.common.UsbHandle.Serial +Matcher + + + + +Node4->Node5 + + + + +Node5->Node3 + + + + + diff --git a/docs/source/_static/adb.common.UsbHandle.FindFirst.CALLER_GRAPH.svg b/docs/source/_static/adb.common.UsbHandle.FindFirst.CALLER_GRAPH.svg new file mode 100644 index 0000000..c1bcfe4 --- /dev/null +++ b/docs/source/_static/adb.common.UsbHandle.FindFirst.CALLER_GRAPH.svg @@ -0,0 +1,65 @@ + + + + + + +adb.common.UsbHandle.FindFirst + + +Node1 + +adb.common.UsbHandle.Find +First + + +Node2 + + +adb.common.UsbHandle.Find + + + + +Node1->Node2 + + + + +Node3 + + +adb.common.UsbHandle.Find +AndOpen + + + + +Node2->Node3 + + + + +Node4 + + +adb.common.UsbHandle.Serial +Matcher + + + + +Node3->Node4 + + + + +Node4->Node2 + + + + + diff --git a/docs/source/_static/adb.common.UsbHandle.FindFirst.CALL_GRAPH.svg b/docs/source/_static/adb.common.UsbHandle.FindFirst.CALL_GRAPH.svg new file mode 100644 index 0000000..76f0250 --- /dev/null +++ b/docs/source/_static/adb.common.UsbHandle.FindFirst.CALL_GRAPH.svg @@ -0,0 +1,33 @@ + + + + + + +adb.common.UsbHandle.FindFirst + + +Node1 + +adb.common.UsbHandle.Find +First + + +Node2 + + +adb.common.UsbHandle.Find +Devices + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.common.UsbHandle.FlushBuffers.CALL_GRAPH.svg b/docs/source/_static/adb.common.UsbHandle.FlushBuffers.CALL_GRAPH.svg new file mode 100644 index 0000000..95a13f8 --- /dev/null +++ b/docs/source/_static/adb.common.UsbHandle.FlushBuffers.CALL_GRAPH.svg @@ -0,0 +1,72 @@ + + + + + + +adb.common.UsbHandle.FlushBuffers + + +Node1 + +adb.common.UsbHandle.Flush +Buffers + + +Node2 + + +adb.common.UsbHandle.BulkRead + + + + +Node1->Node2 + + + + +Node3 + + +adb.common.UsbHandle.Timeout + + + + +Node2->Node3 + + + + +Node4 + + +adb.common.UsbHandle.usb_info + + + + +Node2->Node4 + + + + +Node5 + + +adb.common.UsbHandle.serial +_number + + + + +Node4->Node5 + + + + + diff --git a/docs/source/_static/adb.common.UsbHandle.Open.CALL_GRAPH.svg b/docs/source/_static/adb.common.UsbHandle.Open.CALL_GRAPH.svg new file mode 100644 index 0000000..c918aba --- /dev/null +++ b/docs/source/_static/adb.common.UsbHandle.Open.CALL_GRAPH.svg @@ -0,0 +1,172 @@ + + + + + + +adb.common.UsbHandle.Open + + +Node1 + +adb.common.UsbHandle.Open + + +Node2 + + +adb.common.UsbHandle.port_path + + + + +Node1->Node2 + + + + +Node3 + + +adb.adb_commands.AdbCommands. +Close + + + + +Node1->Node3 + + + + +Node6 + + +adb.adb_protocol._AdbConnection. +Close + + + + +Node1->Node6 + + + + +Node10 + + +adb.common.UsbHandle.Close + + + + +Node1->Node10 + + + + +Node4 + + +adb.adb_commands.AdbCommands. +__reset + + + + +Node3->Node4 + + + + +Node5 + + +adb.adb_commands.AdbCommands. +__init__ + + + + +Node4->Node5 + + + + +Node7 + + +adb.adb_protocol._AdbConnection._Send + + + + +Node6->Node7 + + + + +Node8 + + +adb.adb_protocol._AdbConnection. +ReadUntil + + + + +Node6->Node8 + + + + +Node9 + + +adb.adb_protocol._AdbConnection.Okay + + + + +Node8->Node9 + + + + +Node9->Node7 + + + + +Node11 + + +adb.common.UsbHandle.usb_info + + + + +Node10->Node11 + + + + +Node12 + + +adb.common.UsbHandle.serial +_number + + + + +Node11->Node12 + + + + + diff --git a/docs/source/_static/adb.common.UsbHandle.PortPathMatcher.CALLER_GRAPH.svg b/docs/source/_static/adb.common.UsbHandle.PortPathMatcher.CALLER_GRAPH.svg new file mode 100644 index 0000000..e7bcb76 --- /dev/null +++ b/docs/source/_static/adb.common.UsbHandle.PortPathMatcher.CALLER_GRAPH.svg @@ -0,0 +1,65 @@ + + + + + + +adb.common.UsbHandle.PortPathMatcher + + +Node1 + +adb.common.UsbHandle.Port +PathMatcher + + +Node2 + + +adb.common.UsbHandle.Find + + + + +Node1->Node2 + + + + +Node3 + + +adb.common.UsbHandle.Find +AndOpen + + + + +Node2->Node3 + + + + +Node4 + + +adb.common.UsbHandle.Serial +Matcher + + + + +Node3->Node4 + + + + +Node4->Node2 + + + + + diff --git a/docs/source/_static/adb.common.UsbHandle.SerialMatcher.CALLER_GRAPH.svg b/docs/source/_static/adb.common.UsbHandle.SerialMatcher.CALLER_GRAPH.svg new file mode 100644 index 0000000..c43f32b --- /dev/null +++ b/docs/source/_static/adb.common.UsbHandle.SerialMatcher.CALLER_GRAPH.svg @@ -0,0 +1,51 @@ + + + + + + +adb.common.UsbHandle.SerialMatcher + + +Node1 + +adb.common.UsbHandle.Serial +Matcher + + +Node2 + + +adb.common.UsbHandle.Find + + + + +Node1->Node2 + + + + +Node3 + + +adb.common.UsbHandle.Find +AndOpen + + + + +Node2->Node3 + + + + +Node3->Node1 + + + + + diff --git a/docs/source/_static/adb.common.UsbHandle.SerialMatcher.CALL_GRAPH.svg b/docs/source/_static/adb.common.UsbHandle.SerialMatcher.CALL_GRAPH.svg new file mode 100644 index 0000000..cca6002 --- /dev/null +++ b/docs/source/_static/adb.common.UsbHandle.SerialMatcher.CALL_GRAPH.svg @@ -0,0 +1,93 @@ + + + + + + +adb.common.UsbHandle.SerialMatcher + + +Node1 + +adb.common.UsbHandle.Serial +Matcher + + +Node2 + + +adb.common.UsbHandle.Find +AndOpen + + + + +Node1->Node2 + + + + +Node3 + + +adb.common.UsbHandle.Find + + + + +Node2->Node3 + + + + +Node3->Node1 + + + + +Node4 + + +adb.common.UsbHandle.Port +PathMatcher + + + + +Node3->Node4 + + + + +Node5 + + +adb.common.UsbHandle.Find +First + + + + +Node3->Node5 + + + + +Node6 + + +adb.common.UsbHandle.Find +Devices + + + + +Node5->Node6 + + + + + diff --git a/docs/source/_static/adb.common.UsbHandle.Timeout.CALLER_GRAPH.svg b/docs/source/_static/adb.common.UsbHandle.Timeout.CALLER_GRAPH.svg new file mode 100644 index 0000000..c81c278 --- /dev/null +++ b/docs/source/_static/adb.common.UsbHandle.Timeout.CALLER_GRAPH.svg @@ -0,0 +1,114 @@ + + + + + + +adb.common.UsbHandle.Timeout + + +Node1 + +adb.common.UsbHandle.Timeout + + +Node2 + + +adb.common.UsbHandle.BulkRead + + + + +Node1->Node2 + + + + +Node4 + + +adb.common.UsbHandle.Bulk +Write + + + + +Node1->Node4 + + + + +Node5 + + +adb.common.TcpHandle.Timeout +Seconds + + + + +Node1->Node5 + + + + +Node3 + + +adb.common.UsbHandle.Flush +Buffers + + + + +Node2->Node3 + + + + +Node6 + + +adb.common.TcpHandle. +_connect + + + + +Node5->Node6 + + + + +Node7 + + +adb.common.TcpHandle.BulkRead + + + + +Node5->Node7 + + + + +Node8 + + +adb.common.TcpHandle.Bulk +Write + + + + +Node5->Node8 + + + + + diff --git a/docs/source/_static/adb.common.UsbHandle.__init__.CALLER_GRAPH.svg b/docs/source/_static/adb.common.UsbHandle.__init__.CALLER_GRAPH.svg new file mode 100644 index 0000000..d10f236 --- /dev/null +++ b/docs/source/_static/adb.common.UsbHandle.__init__.CALLER_GRAPH.svg @@ -0,0 +1,33 @@ + + + + + + +adb.common.UsbHandle.__init__ + + +Node1 + +adb.common.UsbHandle. +__init__ + + +Node2 + + +adb.fastboot.FastbootCommands. +__reset + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.common.UsbHandle.port_path.CALLER_GRAPH.svg b/docs/source/_static/adb.common.UsbHandle.port_path.CALLER_GRAPH.svg new file mode 100644 index 0000000..4ce2a32 --- /dev/null +++ b/docs/source/_static/adb.common.UsbHandle.port_path.CALLER_GRAPH.svg @@ -0,0 +1,31 @@ + + + + + + +adb.common.UsbHandle.port_path + + +Node1 + +adb.common.UsbHandle.port_path + + +Node2 + + +adb.common.UsbHandle.Open + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.common.UsbHandle.serial_number.CALLER_GRAPH.svg b/docs/source/_static/adb.common.UsbHandle.serial_number.CALLER_GRAPH.svg new file mode 100644 index 0000000..9f7f1a0 --- /dev/null +++ b/docs/source/_static/adb.common.UsbHandle.serial_number.CALLER_GRAPH.svg @@ -0,0 +1,113 @@ + + + + + + +adb.common.UsbHandle.serial_number + + +Node1 + +adb.common.UsbHandle.serial +_number + + +Node2 + + +adb.common.TcpHandle.Bulk +Write + + + + +Node1->Node2 + + + + +Node3 + + +adb.common.UsbHandle.usb_info + + + + +Node1->Node3 + + + + +Node4 + + +adb.common.UsbHandle.Close + + + + +Node3->Node4 + + + + +Node6 + + +adb.common.UsbHandle.Bulk +Write + + + + +Node3->Node6 + + + + +Node7 + + +adb.common.UsbHandle.BulkRead + + + + +Node3->Node7 + + + + +Node5 + + +adb.common.UsbHandle.Open + + + + +Node4->Node5 + + + + +Node8 + + +adb.common.UsbHandle.Flush +Buffers + + + + +Node7->Node8 + + + + + diff --git a/docs/source/_static/adb.common.UsbHandle.usb_info.CALLER_GRAPH.svg b/docs/source/_static/adb.common.UsbHandle.usb_info.CALLER_GRAPH.svg new file mode 100644 index 0000000..5f8066b --- /dev/null +++ b/docs/source/_static/adb.common.UsbHandle.usb_info.CALLER_GRAPH.svg @@ -0,0 +1,85 @@ + + + + + + +adb.common.UsbHandle.usb_info + + +Node1 + +adb.common.UsbHandle.usb_info + + +Node2 + + +adb.common.UsbHandle.BulkRead + + + + +Node1->Node2 + + + + +Node4 + + +adb.common.UsbHandle.Bulk +Write + + + + +Node1->Node4 + + + + +Node5 + + +adb.common.UsbHandle.Close + + + + +Node1->Node5 + + + + +Node3 + + +adb.common.UsbHandle.Flush +Buffers + + + + +Node2->Node3 + + + + +Node6 + + +adb.common.UsbHandle.Open + + + + +Node5->Node6 + + + + + diff --git a/docs/source/_static/adb.common.UsbHandle.usb_info.CALL_GRAPH.svg b/docs/source/_static/adb.common.UsbHandle.usb_info.CALL_GRAPH.svg new file mode 100644 index 0000000..f50a91a --- /dev/null +++ b/docs/source/_static/adb.common.UsbHandle.usb_info.CALL_GRAPH.svg @@ -0,0 +1,32 @@ + + + + + + +adb.common.UsbHandle.usb_info + + +Node1 + +adb.common.UsbHandle.usb_info + + +Node2 + + +adb.common.UsbHandle.serial +_number + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.common_cli.MakeSubparser.CALL_GRAPH.svg b/docs/source/_static/adb.common_cli.MakeSubparser.CALL_GRAPH.svg new file mode 100644 index 0000000..fa80e2a --- /dev/null +++ b/docs/source/_static/adb.common_cli.MakeSubparser.CALL_GRAPH.svg @@ -0,0 +1,31 @@ + + + + + + +adb.common_cli.MakeSubparser + + +Node1 + +adb.common_cli.MakeSubparser + + +Node2 + + +adb.common_cli._DocToArgs + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.common_cli.PositionalArg.CALL_GRAPH.svg b/docs/source/_static/adb.common_cli.PositionalArg.CALL_GRAPH.svg new file mode 100644 index 0000000..2fd33e8 --- /dev/null +++ b/docs/source/_static/adb.common_cli.PositionalArg.CALL_GRAPH.svg @@ -0,0 +1,28 @@ + + + + + + +adb.common_cli.PositionalArg + + +Node1 + +adb.common_cli.PositionalArg + + +Node2 + +Action + + +Node2->Node1 + + + + + diff --git a/docs/source/_static/adb.common_cli.StartCli.CALL_GRAPH.svg b/docs/source/_static/adb.common_cli.StartCli.CALL_GRAPH.svg new file mode 100644 index 0000000..572b56e --- /dev/null +++ b/docs/source/_static/adb.common_cli.StartCli.CALL_GRAPH.svg @@ -0,0 +1,31 @@ + + + + + + +adb.common_cli.StartCli + + +Node1 + +adb.common_cli.StartCli + + +Node2 + + +adb.common_cli._RunMethod + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.common_cli._DocToArgs.CALLER_GRAPH.svg b/docs/source/_static/adb.common_cli._DocToArgs.CALLER_GRAPH.svg new file mode 100644 index 0000000..962bd29 --- /dev/null +++ b/docs/source/_static/adb.common_cli._DocToArgs.CALLER_GRAPH.svg @@ -0,0 +1,31 @@ + + + + + + +adb.common_cli._DocToArgs + + +Node1 + +adb.common_cli._DocToArgs + + +Node2 + + +adb.common_cli.MakeSubparser + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.common_cli._PortPathAction.CALL_GRAPH.svg b/docs/source/_static/adb.common_cli._PortPathAction.CALL_GRAPH.svg new file mode 100644 index 0000000..c96367f --- /dev/null +++ b/docs/source/_static/adb.common_cli._PortPathAction.CALL_GRAPH.svg @@ -0,0 +1,29 @@ + + + + + + +adb.common_cli._PortPathAction + + +Node1 + +adb.common_cli._PortPath +Action + + +Node2 + +argparse::Action + + +Node2->Node1 + + + + + diff --git a/docs/source/_static/adb.common_cli._RunMethod.CALLER_GRAPH.svg b/docs/source/_static/adb.common_cli._RunMethod.CALLER_GRAPH.svg new file mode 100644 index 0000000..20141b6 --- /dev/null +++ b/docs/source/_static/adb.common_cli._RunMethod.CALLER_GRAPH.svg @@ -0,0 +1,31 @@ + + + + + + +adb.common_cli._RunMethod + + +Node1 + +adb.common_cli._RunMethod + + +Node2 + + +adb.common_cli.StartCli + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.fastboot.FastbootCommands.CALL_GRAPH.svg b/docs/source/_static/adb.fastboot.FastbootCommands.CALL_GRAPH.svg new file mode 100644 index 0000000..90c3d7b --- /dev/null +++ b/docs/source/_static/adb.fastboot.FastbootCommands.CALL_GRAPH.svg @@ -0,0 +1,28 @@ + + + + + + +adb.fastboot.FastbootCommands + + +Node1 + +adb.fastboot.FastbootCommands + + +Node2 + +object + + +Node2->Node1 + + + + + diff --git a/docs/source/_static/adb.fastboot.FastbootCommands.Continue.CALL_GRAPH.svg b/docs/source/_static/adb.fastboot.FastbootCommands.Continue.CALL_GRAPH.svg new file mode 100644 index 0000000..3a375f0 --- /dev/null +++ b/docs/source/_static/adb.fastboot.FastbootCommands.Continue.CALL_GRAPH.svg @@ -0,0 +1,80 @@ + + + + + + +adb.fastboot.FastbootCommands.Continue + + +Node1 + +adb.fastboot.FastbootCommands. +Continue + + +Node2 + + +adb.fastboot.FastbootCommands. +_SimpleCommand + + + + +Node1->Node2 + + + + +Node3 + + +adb.fastboot.FastbootCommands. +FlashFromFile + + + + +Node2->Node3 + + + + +Node4 + + +adb.fastboot.FastbootCommands. +Download + + + + +Node3->Node4 + + + + +Node5 + + +adb.fastboot.FastbootCommands. +Flash + + + + +Node3->Node5 + + + + +Node5->Node2 + + + + + diff --git a/docs/source/_static/adb.fastboot.FastbootCommands.Download.CALLER_GRAPH.svg b/docs/source/_static/adb.fastboot.FastbootCommands.Download.CALLER_GRAPH.svg new file mode 100644 index 0000000..bf0a5cd --- /dev/null +++ b/docs/source/_static/adb.fastboot.FastbootCommands.Download.CALLER_GRAPH.svg @@ -0,0 +1,149 @@ + + + + + + +adb.fastboot.FastbootCommands.Download + + +Node1 + +adb.fastboot.FastbootCommands. +Download + + +Node2 + + +adb.fastboot.FastbootCommands. +FlashFromFile + + + + +Node1->Node2 + + + + +Node3 + + +adb.fastboot.FastbootCommands. +_SimpleCommand + + + + +Node2->Node3 + + + + +Node4 + + +adb.fastboot.FastbootCommands. +Continue + + + + +Node3->Node4 + + + + +Node5 + + +adb.fastboot.FastbootCommands. +Erase + + + + +Node3->Node5 + + + + +Node6 + + +adb.fastboot.FastbootCommands. +Flash + + + + +Node3->Node6 + + + + +Node7 + + +adb.fastboot.FastbootCommands. +Getvar + + + + +Node3->Node7 + + + + +Node8 + + +adb.fastboot.FastbootCommands.Oem + + + + +Node3->Node8 + + + + +Node9 + + +adb.fastboot.FastbootCommands. +Reboot + + + + +Node3->Node9 + + + + +Node10 + + +adb.fastboot.FastbootCommands. +RebootBootloader + + + + +Node3->Node10 + + + + +Node6->Node2 + + + + + diff --git a/docs/source/_static/adb.fastboot.FastbootCommands.Erase.CALL_GRAPH.svg b/docs/source/_static/adb.fastboot.FastbootCommands.Erase.CALL_GRAPH.svg new file mode 100644 index 0000000..f1c8c32 --- /dev/null +++ b/docs/source/_static/adb.fastboot.FastbootCommands.Erase.CALL_GRAPH.svg @@ -0,0 +1,80 @@ + + + + + + +adb.fastboot.FastbootCommands.Erase + + +Node1 + +adb.fastboot.FastbootCommands. +Erase + + +Node2 + + +adb.fastboot.FastbootCommands. +_SimpleCommand + + + + +Node1->Node2 + + + + +Node3 + + +adb.fastboot.FastbootCommands. +FlashFromFile + + + + +Node2->Node3 + + + + +Node4 + + +adb.fastboot.FastbootCommands. +Download + + + + +Node3->Node4 + + + + +Node5 + + +adb.fastboot.FastbootCommands. +Flash + + + + +Node3->Node5 + + + + +Node5->Node2 + + + + + diff --git a/docs/source/_static/adb.fastboot.FastbootCommands.Flash.CALLER_GRAPH.svg b/docs/source/_static/adb.fastboot.FastbootCommands.Flash.CALLER_GRAPH.svg new file mode 100644 index 0000000..5bf203a --- /dev/null +++ b/docs/source/_static/adb.fastboot.FastbootCommands.Flash.CALLER_GRAPH.svg @@ -0,0 +1,135 @@ + + + + + + +adb.fastboot.FastbootCommands.Flash + + +Node1 + +adb.fastboot.FastbootCommands. +Flash + + +Node2 + + +adb.fastboot.FastbootCommands. +FlashFromFile + + + + +Node1->Node2 + + + + +Node3 + + +adb.fastboot.FastbootCommands. +_SimpleCommand + + + + +Node2->Node3 + + + + +Node3->Node1 + + + + +Node4 + + +adb.fastboot.FastbootCommands. +Continue + + + + +Node3->Node4 + + + + +Node5 + + +adb.fastboot.FastbootCommands. +Erase + + + + +Node3->Node5 + + + + +Node6 + + +adb.fastboot.FastbootCommands. +Getvar + + + + +Node3->Node6 + + + + +Node7 + + +adb.fastboot.FastbootCommands.Oem + + + + +Node3->Node7 + + + + +Node8 + + +adb.fastboot.FastbootCommands. +Reboot + + + + +Node3->Node8 + + + + +Node9 + + +adb.fastboot.FastbootCommands. +RebootBootloader + + + + +Node3->Node9 + + + + + diff --git a/docs/source/_static/adb.fastboot.FastbootCommands.Flash.CALL_GRAPH.svg b/docs/source/_static/adb.fastboot.FastbootCommands.Flash.CALL_GRAPH.svg new file mode 100644 index 0000000..ac0ed99 --- /dev/null +++ b/docs/source/_static/adb.fastboot.FastbootCommands.Flash.CALL_GRAPH.svg @@ -0,0 +1,66 @@ + + + + + + +adb.fastboot.FastbootCommands.Flash + + +Node1 + +adb.fastboot.FastbootCommands. +Flash + + +Node2 + + +adb.fastboot.FastbootCommands. +_SimpleCommand + + + + +Node1->Node2 + + + + +Node3 + + +adb.fastboot.FastbootCommands. +FlashFromFile + + + + +Node2->Node3 + + + + +Node3->Node1 + + + + +Node4 + + +adb.fastboot.FastbootCommands. +Download + + + + +Node3->Node4 + + + + + diff --git a/docs/source/_static/adb.fastboot.FastbootCommands.FlashFromFile.CALLER_GRAPH.svg b/docs/source/_static/adb.fastboot.FastbootCommands.FlashFromFile.CALLER_GRAPH.svg new file mode 100644 index 0000000..8bad89b --- /dev/null +++ b/docs/source/_static/adb.fastboot.FastbootCommands.FlashFromFile.CALLER_GRAPH.svg @@ -0,0 +1,135 @@ + + + + + + +adb.fastboot.FastbootCommands.FlashFromFile + + +Node1 + +adb.fastboot.FastbootCommands. +FlashFromFile + + +Node2 + + +adb.fastboot.FastbootCommands. +_SimpleCommand + + + + +Node1->Node2 + + + + +Node3 + + +adb.fastboot.FastbootCommands. +Continue + + + + +Node2->Node3 + + + + +Node4 + + +adb.fastboot.FastbootCommands. +Erase + + + + +Node2->Node4 + + + + +Node5 + + +adb.fastboot.FastbootCommands. +Flash + + + + +Node2->Node5 + + + + +Node6 + + +adb.fastboot.FastbootCommands. +Getvar + + + + +Node2->Node6 + + + + +Node7 + + +adb.fastboot.FastbootCommands.Oem + + + + +Node2->Node7 + + + + +Node8 + + +adb.fastboot.FastbootCommands. +Reboot + + + + +Node2->Node8 + + + + +Node9 + + +adb.fastboot.FastbootCommands. +RebootBootloader + + + + +Node2->Node9 + + + + +Node5->Node1 + + + + + diff --git a/docs/source/_static/adb.fastboot.FastbootCommands.FlashFromFile.CALL_GRAPH.svg b/docs/source/_static/adb.fastboot.FastbootCommands.FlashFromFile.CALL_GRAPH.svg new file mode 100644 index 0000000..90ada28 --- /dev/null +++ b/docs/source/_static/adb.fastboot.FastbootCommands.FlashFromFile.CALL_GRAPH.svg @@ -0,0 +1,66 @@ + + + + + + +adb.fastboot.FastbootCommands.FlashFromFile + + +Node1 + +adb.fastboot.FastbootCommands. +FlashFromFile + + +Node2 + + +adb.fastboot.FastbootCommands. +Download + + + + +Node1->Node2 + + + + +Node3 + + +adb.fastboot.FastbootCommands. +Flash + + + + +Node1->Node3 + + + + +Node4 + + +adb.fastboot.FastbootCommands. +_SimpleCommand + + + + +Node3->Node4 + + + + +Node4->Node1 + + + + + diff --git a/docs/source/_static/adb.fastboot.FastbootCommands.Getvar.CALL_GRAPH.svg b/docs/source/_static/adb.fastboot.FastbootCommands.Getvar.CALL_GRAPH.svg new file mode 100644 index 0000000..ddb60bd --- /dev/null +++ b/docs/source/_static/adb.fastboot.FastbootCommands.Getvar.CALL_GRAPH.svg @@ -0,0 +1,80 @@ + + + + + + +adb.fastboot.FastbootCommands.Getvar + + +Node1 + +adb.fastboot.FastbootCommands. +Getvar + + +Node2 + + +adb.fastboot.FastbootCommands. +_SimpleCommand + + + + +Node1->Node2 + + + + +Node3 + + +adb.fastboot.FastbootCommands. +FlashFromFile + + + + +Node2->Node3 + + + + +Node4 + + +adb.fastboot.FastbootCommands. +Download + + + + +Node3->Node4 + + + + +Node5 + + +adb.fastboot.FastbootCommands. +Flash + + + + +Node3->Node5 + + + + +Node5->Node2 + + + + + diff --git a/docs/source/_static/adb.fastboot.FastbootCommands.Oem.CALL_GRAPH.svg b/docs/source/_static/adb.fastboot.FastbootCommands.Oem.CALL_GRAPH.svg new file mode 100644 index 0000000..e28e6ef --- /dev/null +++ b/docs/source/_static/adb.fastboot.FastbootCommands.Oem.CALL_GRAPH.svg @@ -0,0 +1,79 @@ + + + + + + +adb.fastboot.FastbootCommands.Oem + + +Node1 + +adb.fastboot.FastbootCommands.Oem + + +Node2 + + +adb.fastboot.FastbootCommands. +_SimpleCommand + + + + +Node1->Node2 + + + + +Node3 + + +adb.fastboot.FastbootCommands. +FlashFromFile + + + + +Node2->Node3 + + + + +Node4 + + +adb.fastboot.FastbootCommands. +Download + + + + +Node3->Node4 + + + + +Node5 + + +adb.fastboot.FastbootCommands. +Flash + + + + +Node3->Node5 + + + + +Node5->Node2 + + + + + diff --git a/docs/source/_static/adb.fastboot.FastbootCommands.Reboot.CALL_GRAPH.svg b/docs/source/_static/adb.fastboot.FastbootCommands.Reboot.CALL_GRAPH.svg new file mode 100644 index 0000000..5946045 --- /dev/null +++ b/docs/source/_static/adb.fastboot.FastbootCommands.Reboot.CALL_GRAPH.svg @@ -0,0 +1,80 @@ + + + + + + +adb.fastboot.FastbootCommands.Reboot + + +Node1 + +adb.fastboot.FastbootCommands. +Reboot + + +Node2 + + +adb.fastboot.FastbootCommands. +_SimpleCommand + + + + +Node1->Node2 + + + + +Node3 + + +adb.fastboot.FastbootCommands. +FlashFromFile + + + + +Node2->Node3 + + + + +Node4 + + +adb.fastboot.FastbootCommands. +Download + + + + +Node3->Node4 + + + + +Node5 + + +adb.fastboot.FastbootCommands. +Flash + + + + +Node3->Node5 + + + + +Node5->Node2 + + + + + diff --git a/docs/source/_static/adb.fastboot.FastbootCommands.RebootBootloader.CALL_GRAPH.svg b/docs/source/_static/adb.fastboot.FastbootCommands.RebootBootloader.CALL_GRAPH.svg new file mode 100644 index 0000000..577eb05 --- /dev/null +++ b/docs/source/_static/adb.fastboot.FastbootCommands.RebootBootloader.CALL_GRAPH.svg @@ -0,0 +1,80 @@ + + + + + + +adb.fastboot.FastbootCommands.RebootBootloader + + +Node1 + +adb.fastboot.FastbootCommands. +RebootBootloader + + +Node2 + + +adb.fastboot.FastbootCommands. +_SimpleCommand + + + + +Node1->Node2 + + + + +Node3 + + +adb.fastboot.FastbootCommands. +FlashFromFile + + + + +Node2->Node3 + + + + +Node4 + + +adb.fastboot.FastbootCommands. +Download + + + + +Node3->Node4 + + + + +Node5 + + +adb.fastboot.FastbootCommands. +Flash + + + + +Node3->Node5 + + + + +Node5->Node2 + + + + + diff --git a/docs/source/_static/adb.fastboot.FastbootCommands._SimpleCommand.CALLER_GRAPH.svg b/docs/source/_static/adb.fastboot.FastbootCommands._SimpleCommand.CALLER_GRAPH.svg new file mode 100644 index 0000000..0d73bc2 --- /dev/null +++ b/docs/source/_static/adb.fastboot.FastbootCommands._SimpleCommand.CALLER_GRAPH.svg @@ -0,0 +1,135 @@ + + + + + + +adb.fastboot.FastbootCommands._SimpleCommand + + +Node1 + +adb.fastboot.FastbootCommands. +_SimpleCommand + + +Node2 + + +adb.fastboot.FastbootCommands. +Continue + + + + +Node1->Node2 + + + + +Node3 + + +adb.fastboot.FastbootCommands. +Erase + + + + +Node1->Node3 + + + + +Node4 + + +adb.fastboot.FastbootCommands. +Flash + + + + +Node1->Node4 + + + + +Node6 + + +adb.fastboot.FastbootCommands. +Getvar + + + + +Node1->Node6 + + + + +Node7 + + +adb.fastboot.FastbootCommands.Oem + + + + +Node1->Node7 + + + + +Node8 + + +adb.fastboot.FastbootCommands. +Reboot + + + + +Node1->Node8 + + + + +Node9 + + +adb.fastboot.FastbootCommands. +RebootBootloader + + + + +Node1->Node9 + + + + +Node5 + + +adb.fastboot.FastbootCommands. +FlashFromFile + + + + +Node4->Node5 + + + + +Node5->Node1 + + + + + diff --git a/docs/source/_static/adb.fastboot.FastbootCommands._SimpleCommand.CALL_GRAPH.svg b/docs/source/_static/adb.fastboot.FastbootCommands._SimpleCommand.CALL_GRAPH.svg new file mode 100644 index 0000000..27755db --- /dev/null +++ b/docs/source/_static/adb.fastboot.FastbootCommands._SimpleCommand.CALL_GRAPH.svg @@ -0,0 +1,66 @@ + + + + + + +adb.fastboot.FastbootCommands._SimpleCommand + + +Node1 + +adb.fastboot.FastbootCommands. +_SimpleCommand + + +Node2 + + +adb.fastboot.FastbootCommands. +FlashFromFile + + + + +Node1->Node2 + + + + +Node3 + + +adb.fastboot.FastbootCommands. +Download + + + + +Node2->Node3 + + + + +Node4 + + +adb.fastboot.FastbootCommands. +Flash + + + + +Node2->Node4 + + + + +Node4->Node1 + + + + + diff --git a/docs/source/_static/adb.fastboot.FastbootCommands.__init__.CALLER_GRAPH.svg b/docs/source/_static/adb.fastboot.FastbootCommands.__init__.CALLER_GRAPH.svg new file mode 100644 index 0000000..e0a2dbb --- /dev/null +++ b/docs/source/_static/adb.fastboot.FastbootCommands.__init__.CALLER_GRAPH.svg @@ -0,0 +1,33 @@ + + + + + + +adb.fastboot.FastbootCommands.__init__ + + +Node1 + +adb.fastboot.FastbootCommands. +__init__ + + +Node2 + + +adb.fastboot.FastbootCommands. +__reset + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.fastboot.FastbootCommands.__reset.CALL_GRAPH.svg b/docs/source/_static/adb.fastboot.FastbootCommands.__reset.CALL_GRAPH.svg new file mode 100644 index 0000000..c356d0c --- /dev/null +++ b/docs/source/_static/adb.fastboot.FastbootCommands.__reset.CALL_GRAPH.svg @@ -0,0 +1,131 @@ + + + + + + +adb.fastboot.FastbootCommands.__reset + + +Node1 + +adb.fastboot.FastbootCommands. +__reset + + +Node2 + + +adb.adb_commands.AdbCommands. +__init__ + + + + +Node1->Node2 + + + + +Node3 + + +adb.adb_protocol.Invalid +CommandError.__init__ + + + + +Node1->Node3 + + + + +Node4 + + +adb.adb_protocol._AdbConnection. +__init__ + + + + +Node1->Node4 + + + + +Node5 + + +adb.adb_protocol.AdbMessage. +__init__ + + + + +Node1->Node5 + + + + +Node6 + + +adb.common.UsbHandle. +__init__ + + + + +Node1->Node6 + + + + +Node7 + + +adb.common.TcpHandle. +__init__ + + + + +Node1->Node7 + + + + +Node8 + + +adb.fastboot.FastbootProtocol. +__init__ + + + + +Node1->Node8 + + + + +Node9 + + +adb.fastboot.FastbootCommands. +__init__ + + + + +Node1->Node9 + + + + + diff --git a/docs/source/_static/adb.fastboot.FastbootInvalidResponse.CALL_GRAPH.svg b/docs/source/_static/adb.fastboot.FastbootInvalidResponse.CALL_GRAPH.svg new file mode 100644 index 0000000..deb9605 --- /dev/null +++ b/docs/source/_static/adb.fastboot.FastbootInvalidResponse.CALL_GRAPH.svg @@ -0,0 +1,51 @@ + + + + + + +adb.fastboot.FastbootInvalidResponse + + +Node1 + +adb.fastboot.FastbootInvalid +Response + + +Node2 + +adb.usb_exceptions.Format +MessageWithArgumentsException + + +Node2->Node1 + + + + +Node3 + +adb.usb_exceptions.Common +UsbError + + +Node3->Node2 + + + + +Node4 + +Exception + + +Node4->Node3 + + + + + diff --git a/docs/source/_static/adb.fastboot.FastbootProtocol.CALL_GRAPH.svg b/docs/source/_static/adb.fastboot.FastbootProtocol.CALL_GRAPH.svg new file mode 100644 index 0000000..d7bb348 --- /dev/null +++ b/docs/source/_static/adb.fastboot.FastbootProtocol.CALL_GRAPH.svg @@ -0,0 +1,28 @@ + + + + + + +adb.fastboot.FastbootProtocol + + +Node1 + +adb.fastboot.FastbootProtocol + + +Node2 + +object + + +Node2->Node1 + + + + + diff --git a/docs/source/_static/adb.fastboot.FastbootProtocol.HandleDataSending.CALLER_GRAPH.svg b/docs/source/_static/adb.fastboot.FastbootProtocol.HandleDataSending.CALLER_GRAPH.svg new file mode 100644 index 0000000..4955d2e --- /dev/null +++ b/docs/source/_static/adb.fastboot.FastbootProtocol.HandleDataSending.CALLER_GRAPH.svg @@ -0,0 +1,47 @@ + + + + + + +adb.fastboot.FastbootProtocol.HandleDataSending + + +Node1 + +adb.fastboot.FastbootProtocol. +HandleDataSending + + +Node2 + + +adb.fastboot.FastbootProtocol. +HandleSimpleResponses + + + + +Node1->Node2 + + + + +Node3 + + +adb.fastboot.FastbootProtocol. +SendCommand + + + + +Node2->Node3 + + + + + diff --git a/docs/source/_static/adb.fastboot.FastbootProtocol.HandleDataSending.CALL_GRAPH.svg b/docs/source/_static/adb.fastboot.FastbootProtocol.HandleDataSending.CALL_GRAPH.svg new file mode 100644 index 0000000..664c518 --- /dev/null +++ b/docs/source/_static/adb.fastboot.FastbootProtocol.HandleDataSending.CALL_GRAPH.svg @@ -0,0 +1,61 @@ + + + + + + +adb.fastboot.FastbootProtocol.HandleDataSending + + +Node1 + +adb.fastboot.FastbootProtocol. +HandleDataSending + + +Node2 + + +adb.fastboot.FastbootProtocol. +_AcceptResponses + + + + +Node1->Node2 + + + + +Node3 + + +adb.fastboot.FastbootProtocol. +_Write + + + + +Node1->Node3 + + + + +Node4 + + +adb.fastboot.FastbootProtocol. +_HandleProgress + + + + +Node3->Node4 + + + + + diff --git a/docs/source/_static/adb.fastboot.FastbootProtocol.HandleSimpleResponses.CALLER_GRAPH.svg b/docs/source/_static/adb.fastboot.FastbootProtocol.HandleSimpleResponses.CALLER_GRAPH.svg new file mode 100644 index 0000000..43ad3cb --- /dev/null +++ b/docs/source/_static/adb.fastboot.FastbootProtocol.HandleSimpleResponses.CALLER_GRAPH.svg @@ -0,0 +1,33 @@ + + + + + + +adb.fastboot.FastbootProtocol.HandleSimpleResponses + + +Node1 + +adb.fastboot.FastbootProtocol. +HandleSimpleResponses + + +Node2 + + +adb.fastboot.FastbootProtocol. +SendCommand + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.fastboot.FastbootProtocol.HandleSimpleResponses.CALL_GRAPH.svg b/docs/source/_static/adb.fastboot.FastbootProtocol.HandleSimpleResponses.CALL_GRAPH.svg new file mode 100644 index 0000000..4d54d73 --- /dev/null +++ b/docs/source/_static/adb.fastboot.FastbootProtocol.HandleSimpleResponses.CALL_GRAPH.svg @@ -0,0 +1,80 @@ + + + + + + +adb.fastboot.FastbootProtocol.HandleSimpleResponses + + +Node1 + +adb.fastboot.FastbootProtocol. +HandleSimpleResponses + + +Node2 + + +adb.fastboot.FastbootProtocol. +_AcceptResponses + + + + +Node1->Node2 + + + + +Node3 + + +adb.fastboot.FastbootProtocol. +HandleDataSending + + + + +Node1->Node3 + + + + +Node3->Node2 + + + + +Node4 + + +adb.fastboot.FastbootProtocol. +_Write + + + + +Node3->Node4 + + + + +Node5 + + +adb.fastboot.FastbootProtocol. +_HandleProgress + + + + +Node4->Node5 + + + + + diff --git a/docs/source/_static/adb.fastboot.FastbootProtocol.SendCommand.CALL_GRAPH.svg b/docs/source/_static/adb.fastboot.FastbootProtocol.SendCommand.CALL_GRAPH.svg new file mode 100644 index 0000000..ba93cc7 --- /dev/null +++ b/docs/source/_static/adb.fastboot.FastbootProtocol.SendCommand.CALL_GRAPH.svg @@ -0,0 +1,99 @@ + + + + + + +adb.fastboot.FastbootProtocol.SendCommand + + +Node1 + +adb.fastboot.FastbootProtocol. +SendCommand + + +Node2 + + +adb.fastboot.FastbootProtocol. +_Write + + + + +Node1->Node2 + + + + +Node4 + + +adb.fastboot.FastbootProtocol. +HandleSimpleResponses + + + + +Node1->Node4 + + + + +Node3 + + +adb.fastboot.FastbootProtocol. +_HandleProgress + + + + +Node2->Node3 + + + + +Node5 + + +adb.fastboot.FastbootProtocol. +_AcceptResponses + + + + +Node4->Node5 + + + + +Node6 + + +adb.fastboot.FastbootProtocol. +HandleDataSending + + + + +Node4->Node6 + + + + +Node6->Node2 + + + + +Node6->Node5 + + + + + diff --git a/docs/source/_static/adb.fastboot.FastbootProtocol._AcceptResponses.CALLER_GRAPH.svg b/docs/source/_static/adb.fastboot.FastbootProtocol._AcceptResponses.CALLER_GRAPH.svg new file mode 100644 index 0000000..cdd28d2 --- /dev/null +++ b/docs/source/_static/adb.fastboot.FastbootProtocol._AcceptResponses.CALLER_GRAPH.svg @@ -0,0 +1,66 @@ + + + + + + +adb.fastboot.FastbootProtocol._AcceptResponses + + +Node1 + +adb.fastboot.FastbootProtocol. +_AcceptResponses + + +Node2 + + +adb.fastboot.FastbootProtocol. +HandleDataSending + + + + +Node1->Node2 + + + + +Node3 + + +adb.fastboot.FastbootProtocol. +HandleSimpleResponses + + + + +Node1->Node3 + + + + +Node2->Node3 + + + + +Node4 + + +adb.fastboot.FastbootProtocol. +SendCommand + + + + +Node3->Node4 + + + + + diff --git a/docs/source/_static/adb.fastboot.FastbootProtocol._HandleProgress.CALLER_GRAPH.svg b/docs/source/_static/adb.fastboot.FastbootProtocol._HandleProgress.CALLER_GRAPH.svg new file mode 100644 index 0000000..cf9f984 --- /dev/null +++ b/docs/source/_static/adb.fastboot.FastbootProtocol._HandleProgress.CALLER_GRAPH.svg @@ -0,0 +1,132 @@ + + + + + + +adb.fastboot.FastbootProtocol._HandleProgress + + +Node1 + +adb.fastboot.FastbootProtocol. +_HandleProgress + + +Node2 + + +adb.fastboot.FastbootProtocol. +_Write + + + + +Node1->Node2 + + + + +Node6 + + +adb.filesync_protocol.Filesync +Protocol.Pull + + + + +Node1->Node6 + + + + +Node7 + + +adb.filesync_protocol.Filesync +Protocol.Push + + + + +Node1->Node7 + + + + +Node3 + + +adb.fastboot.FastbootProtocol. +SendCommand + + + + +Node2->Node3 + + + + +Node4 + + +adb.fastboot.FastbootProtocol. +HandleDataSending + + + + +Node2->Node4 + + + + +Node5 + + +adb.fastboot.FastbootProtocol. +HandleSimpleResponses + + + + +Node4->Node5 + + + + +Node5->Node3 + + + + +Node8 + + +adb.filesync_protocol.Filesync +Protocol._HandleProgress + + + + +Node7->Node8 + + + + +Node8->Node6 + + + + +Node8->Node7 + + + + + diff --git a/docs/source/_static/adb.fastboot.FastbootProtocol._Write.CALLER_GRAPH.svg b/docs/source/_static/adb.fastboot.FastbootProtocol._Write.CALLER_GRAPH.svg new file mode 100644 index 0000000..1a0aa10 --- /dev/null +++ b/docs/source/_static/adb.fastboot.FastbootProtocol._Write.CALLER_GRAPH.svg @@ -0,0 +1,66 @@ + + + + + + +adb.fastboot.FastbootProtocol._Write + + +Node1 + +adb.fastboot.FastbootProtocol. +_Write + + +Node2 + + +adb.fastboot.FastbootProtocol. +HandleDataSending + + + + +Node1->Node2 + + + + +Node4 + + +adb.fastboot.FastbootProtocol. +SendCommand + + + + +Node1->Node4 + + + + +Node3 + + +adb.fastboot.FastbootProtocol. +HandleSimpleResponses + + + + +Node2->Node3 + + + + +Node3->Node4 + + + + + diff --git a/docs/source/_static/adb.fastboot.FastbootProtocol._Write.CALL_GRAPH.svg b/docs/source/_static/adb.fastboot.FastbootProtocol._Write.CALL_GRAPH.svg new file mode 100644 index 0000000..6dbc007 --- /dev/null +++ b/docs/source/_static/adb.fastboot.FastbootProtocol._Write.CALL_GRAPH.svg @@ -0,0 +1,33 @@ + + + + + + +adb.fastboot.FastbootProtocol._Write + + +Node1 + +adb.fastboot.FastbootProtocol. +_Write + + +Node2 + + +adb.fastboot.FastbootProtocol. +_HandleProgress + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.fastboot.FastbootProtocol.__init__.CALLER_GRAPH.svg b/docs/source/_static/adb.fastboot.FastbootProtocol.__init__.CALLER_GRAPH.svg new file mode 100644 index 0000000..264de64 --- /dev/null +++ b/docs/source/_static/adb.fastboot.FastbootProtocol.__init__.CALLER_GRAPH.svg @@ -0,0 +1,33 @@ + + + + + + +adb.fastboot.FastbootProtocol.__init__ + + +Node1 + +adb.fastboot.FastbootProtocol. +__init__ + + +Node2 + + +adb.fastboot.FastbootCommands. +__reset + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.fastboot.FastbootRemoteFailure.CALL_GRAPH.svg b/docs/source/_static/adb.fastboot.FastbootRemoteFailure.CALL_GRAPH.svg new file mode 100644 index 0000000..1207988 --- /dev/null +++ b/docs/source/_static/adb.fastboot.FastbootRemoteFailure.CALL_GRAPH.svg @@ -0,0 +1,51 @@ + + + + + + +adb.fastboot.FastbootRemoteFailure + + +Node1 + +adb.fastboot.FastbootRemote +Failure + + +Node2 + +adb.usb_exceptions.Format +MessageWithArgumentsException + + +Node2->Node1 + + + + +Node3 + +adb.usb_exceptions.Common +UsbError + + +Node3->Node2 + + + + +Node4 + +Exception + + +Node4->Node3 + + + + + diff --git a/docs/source/_static/adb.fastboot.FastbootStateMismatch.CALL_GRAPH.svg b/docs/source/_static/adb.fastboot.FastbootStateMismatch.CALL_GRAPH.svg new file mode 100644 index 0000000..1d08c22 --- /dev/null +++ b/docs/source/_static/adb.fastboot.FastbootStateMismatch.CALL_GRAPH.svg @@ -0,0 +1,51 @@ + + + + + + +adb.fastboot.FastbootStateMismatch + + +Node1 + +adb.fastboot.FastbootState +Mismatch + + +Node2 + +adb.usb_exceptions.Format +MessageWithArgumentsException + + +Node2->Node1 + + + + +Node3 + +adb.usb_exceptions.Common +UsbError + + +Node3->Node2 + + + + +Node4 + +Exception + + +Node4->Node3 + + + + + diff --git a/docs/source/_static/adb.fastboot.FastbootTransferError.CALL_GRAPH.svg b/docs/source/_static/adb.fastboot.FastbootTransferError.CALL_GRAPH.svg new file mode 100644 index 0000000..17792f9 --- /dev/null +++ b/docs/source/_static/adb.fastboot.FastbootTransferError.CALL_GRAPH.svg @@ -0,0 +1,51 @@ + + + + + + +adb.fastboot.FastbootTransferError + + +Node1 + +adb.fastboot.FastbootTransfer +Error + + +Node2 + +adb.usb_exceptions.Format +MessageWithArgumentsException + + +Node2->Node1 + + + + +Node3 + +adb.usb_exceptions.Common +UsbError + + +Node3->Node2 + + + + +Node4 + +Exception + + +Node4->Node3 + + + + + diff --git a/docs/source/_static/adb.fastboot_debug.Devices.CALLER_GRAPH.svg b/docs/source/_static/adb.fastboot_debug.Devices.CALLER_GRAPH.svg new file mode 100644 index 0000000..eae9f7a --- /dev/null +++ b/docs/source/_static/adb.fastboot_debug.Devices.CALLER_GRAPH.svg @@ -0,0 +1,31 @@ + + + + + + +adb.fastboot_debug.Devices + + +Node1 + +adb.fastboot_debug.Devices + + +Node2 + + +adb.fastboot_debug.main + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.fastboot_debug.main.CALL_GRAPH.svg b/docs/source/_static/adb.fastboot_debug.main.CALL_GRAPH.svg new file mode 100644 index 0000000..34cf10a --- /dev/null +++ b/docs/source/_static/adb.fastboot_debug.main.CALL_GRAPH.svg @@ -0,0 +1,31 @@ + + + + + + +adb.fastboot_debug.main + + +Node1 + +adb.fastboot_debug.main + + +Node2 + + +adb.fastboot_debug.Devices + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.filesync_protocol.FileSyncConnection.CALL_GRAPH.svg b/docs/source/_static/adb.filesync_protocol.FileSyncConnection.CALL_GRAPH.svg new file mode 100644 index 0000000..0fcaab7 --- /dev/null +++ b/docs/source/_static/adb.filesync_protocol.FileSyncConnection.CALL_GRAPH.svg @@ -0,0 +1,29 @@ + + + + + + +adb.filesync_protocol.FileSyncConnection + + +Node1 + +adb.filesync_protocol.File +SyncConnection + + +Node2 + +object + + +Node2->Node1 + + + + + diff --git a/docs/source/_static/adb.filesync_protocol.FileSyncConnection.Read.CALLER_GRAPH.svg b/docs/source/_static/adb.filesync_protocol.FileSyncConnection.Read.CALLER_GRAPH.svg new file mode 100644 index 0000000..9ded3c1 --- /dev/null +++ b/docs/source/_static/adb.filesync_protocol.FileSyncConnection.Read.CALLER_GRAPH.svg @@ -0,0 +1,33 @@ + + + + + + +adb.filesync_protocol.FileSyncConnection.Read + + +Node1 + +adb.filesync_protocol.File +SyncConnection.Read + + +Node2 + + +adb.filesync_protocol.File +SyncConnection.ReadUntil + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.filesync_protocol.FileSyncConnection.Read.CALL_GRAPH.svg b/docs/source/_static/adb.filesync_protocol.FileSyncConnection.Read.CALL_GRAPH.svg new file mode 100644 index 0000000..fa1630c --- /dev/null +++ b/docs/source/_static/adb.filesync_protocol.FileSyncConnection.Read.CALL_GRAPH.svg @@ -0,0 +1,47 @@ + + + + + + +adb.filesync_protocol.FileSyncConnection.Read + + +Node1 + +adb.filesync_protocol.File +SyncConnection.Read + + +Node2 + + +adb.filesync_protocol.File +SyncConnection._Flush + + + + +Node1->Node2 + + + + +Node3 + + +adb.filesync_protocol.File +SyncConnection._ReadBuffered + + + + +Node1->Node3 + + + + + diff --git a/docs/source/_static/adb.filesync_protocol.FileSyncConnection.ReadUntil.CALL_GRAPH.svg b/docs/source/_static/adb.filesync_protocol.FileSyncConnection.ReadUntil.CALL_GRAPH.svg new file mode 100644 index 0000000..6757958 --- /dev/null +++ b/docs/source/_static/adb.filesync_protocol.FileSyncConnection.ReadUntil.CALL_GRAPH.svg @@ -0,0 +1,102 @@ + + + + + + +adb.filesync_protocol.FileSyncConnection.ReadUntil + + +Node1 + +adb.filesync_protocol.File +SyncConnection.ReadUntil + + +Node2 + + +adb.adb_protocol.AdbMessage.Read + + + + +Node1->Node2 + + + + +Node5 + + +adb.filesync_protocol.File +SyncConnection.Read + + + + +Node1->Node5 + + + + +Node3 + + +adb.adb_protocol.AdbMessage. +Unpack + + + + +Node2->Node3 + + + + +Node4 + + +adb.adb_protocol.AdbMessage. +CalculateChecksum + + + + +Node2->Node4 + + + + +Node6 + + +adb.filesync_protocol.File +SyncConnection._Flush + + + + +Node5->Node6 + + + + +Node7 + + +adb.filesync_protocol.File +SyncConnection._ReadBuffered + + + + +Node5->Node7 + + + + + diff --git a/docs/source/_static/adb.filesync_protocol.FileSyncConnection.Send.CALL_GRAPH.svg b/docs/source/_static/adb.filesync_protocol.FileSyncConnection.Send.CALL_GRAPH.svg new file mode 100644 index 0000000..ebefd03 --- /dev/null +++ b/docs/source/_static/adb.filesync_protocol.FileSyncConnection.Send.CALL_GRAPH.svg @@ -0,0 +1,47 @@ + + + + + + +adb.filesync_protocol.FileSyncConnection.Send + + +Node1 + +adb.filesync_protocol.File +SyncConnection.Send + + +Node2 + + +adb.filesync_protocol.File +SyncConnection._CanAddToSendBuffer + + + + +Node1->Node2 + + + + +Node3 + + +adb.filesync_protocol.File +SyncConnection._Flush + + + + +Node1->Node3 + + + + + diff --git a/docs/source/_static/adb.filesync_protocol.FileSyncConnection._CanAddToSendBuffer.CALLER_GRAPH.svg b/docs/source/_static/adb.filesync_protocol.FileSyncConnection._CanAddToSendBuffer.CALLER_GRAPH.svg new file mode 100644 index 0000000..1ac46ee --- /dev/null +++ b/docs/source/_static/adb.filesync_protocol.FileSyncConnection._CanAddToSendBuffer.CALLER_GRAPH.svg @@ -0,0 +1,33 @@ + + + + + + +adb.filesync_protocol.FileSyncConnection._CanAddToSendBuffer + + +Node1 + +adb.filesync_protocol.File +SyncConnection._CanAddToSendBuffer + + +Node2 + + +adb.filesync_protocol.File +SyncConnection.Send + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.filesync_protocol.FileSyncConnection._Flush.CALLER_GRAPH.svg b/docs/source/_static/adb.filesync_protocol.FileSyncConnection._Flush.CALLER_GRAPH.svg new file mode 100644 index 0000000..db8faa2 --- /dev/null +++ b/docs/source/_static/adb.filesync_protocol.FileSyncConnection._Flush.CALLER_GRAPH.svg @@ -0,0 +1,61 @@ + + + + + + +adb.filesync_protocol.FileSyncConnection._Flush + + +Node1 + +adb.filesync_protocol.File +SyncConnection._Flush + + +Node2 + + +adb.filesync_protocol.File +SyncConnection.Read + + + + +Node1->Node2 + + + + +Node4 + + +adb.filesync_protocol.File +SyncConnection.Send + + + + +Node1->Node4 + + + + +Node3 + + +adb.filesync_protocol.File +SyncConnection.ReadUntil + + + + +Node2->Node3 + + + + + diff --git a/docs/source/_static/adb.filesync_protocol.FileSyncConnection._ReadBuffered.CALLER_GRAPH.svg b/docs/source/_static/adb.filesync_protocol.FileSyncConnection._ReadBuffered.CALLER_GRAPH.svg new file mode 100644 index 0000000..eeda0ba --- /dev/null +++ b/docs/source/_static/adb.filesync_protocol.FileSyncConnection._ReadBuffered.CALLER_GRAPH.svg @@ -0,0 +1,47 @@ + + + + + + +adb.filesync_protocol.FileSyncConnection._ReadBuffered + + +Node1 + +adb.filesync_protocol.File +SyncConnection._ReadBuffered + + +Node2 + + +adb.filesync_protocol.File +SyncConnection.Read + + + + +Node1->Node2 + + + + +Node3 + + +adb.filesync_protocol.File +SyncConnection.ReadUntil + + + + +Node2->Node3 + + + + + diff --git a/docs/source/_static/adb.filesync_protocol.FilesyncProtocol.CALL_GRAPH.svg b/docs/source/_static/adb.filesync_protocol.FilesyncProtocol.CALL_GRAPH.svg new file mode 100644 index 0000000..f8fe785 --- /dev/null +++ b/docs/source/_static/adb.filesync_protocol.FilesyncProtocol.CALL_GRAPH.svg @@ -0,0 +1,29 @@ + + + + + + +adb.filesync_protocol.FilesyncProtocol + + +Node1 + +adb.filesync_protocol.Filesync +Protocol + + +Node2 + +object + + +Node2->Node1 + + + + + diff --git a/docs/source/_static/adb.filesync_protocol.FilesyncProtocol.Pull.CALL_GRAPH.svg b/docs/source/_static/adb.filesync_protocol.FilesyncProtocol.Pull.CALL_GRAPH.svg new file mode 100644 index 0000000..31beb6f --- /dev/null +++ b/docs/source/_static/adb.filesync_protocol.FilesyncProtocol.Pull.CALL_GRAPH.svg @@ -0,0 +1,98 @@ + + + + + + +adb.filesync_protocol.FilesyncProtocol.Pull + + +Node1 + +adb.filesync_protocol.Filesync +Protocol.Pull + + +Node2 + + +adb.adb_commands.AdbCommands.Stat + + + + +Node1->Node2 + + + + +Node3 + + +adb.filesync_protocol.Filesync +Protocol.Stat + + + + +Node1->Node3 + + + + +Node4 + + +adb.fastboot.FastbootProtocol. +_HandleProgress + + + + +Node1->Node4 + + + + +Node5 + + +adb.filesync_protocol.Filesync +Protocol._HandleProgress + + + + +Node1->Node5 + + + + +Node6 + + +adb.filesync_protocol.Filesync +Protocol.Push + + + + +Node5->Node6 + + + + +Node6->Node4 + + + + +Node6->Node5 + + + + + diff --git a/docs/source/_static/adb.filesync_protocol.FilesyncProtocol.Push.CALLER_GRAPH.svg b/docs/source/_static/adb.filesync_protocol.FilesyncProtocol.Push.CALLER_GRAPH.svg new file mode 100644 index 0000000..75ef6f7 --- /dev/null +++ b/docs/source/_static/adb.filesync_protocol.FilesyncProtocol.Push.CALLER_GRAPH.svg @@ -0,0 +1,52 @@ + + + + + + +adb.filesync_protocol.FilesyncProtocol.Push + + +Node1 + +adb.filesync_protocol.Filesync +Protocol.Push + + +Node2 + + +adb.filesync_protocol.Filesync +Protocol._HandleProgress + + + + +Node1->Node2 + + + + +Node2->Node1 + + + + +Node3 + + +adb.filesync_protocol.Filesync +Protocol.Pull + + + + +Node2->Node3 + + + + + diff --git a/docs/source/_static/adb.filesync_protocol.FilesyncProtocol.Push.CALL_GRAPH.svg b/docs/source/_static/adb.filesync_protocol.FilesyncProtocol.Push.CALL_GRAPH.svg new file mode 100644 index 0000000..eccfdb8 --- /dev/null +++ b/docs/source/_static/adb.filesync_protocol.FilesyncProtocol.Push.CALL_GRAPH.svg @@ -0,0 +1,52 @@ + + + + + + +adb.filesync_protocol.FilesyncProtocol.Push + + +Node1 + +adb.filesync_protocol.Filesync +Protocol.Push + + +Node2 + + +adb.fastboot.FastbootProtocol. +_HandleProgress + + + + +Node1->Node2 + + + + +Node3 + + +adb.filesync_protocol.Filesync +Protocol._HandleProgress + + + + +Node1->Node3 + + + + +Node3->Node1 + + + + + diff --git a/docs/source/_static/adb.filesync_protocol.FilesyncProtocol.Stat.CALLER_GRAPH.svg b/docs/source/_static/adb.filesync_protocol.FilesyncProtocol.Stat.CALLER_GRAPH.svg new file mode 100644 index 0000000..224a476 --- /dev/null +++ b/docs/source/_static/adb.filesync_protocol.FilesyncProtocol.Stat.CALLER_GRAPH.svg @@ -0,0 +1,33 @@ + + + + + + +adb.filesync_protocol.FilesyncProtocol.Stat + + +Node1 + +adb.filesync_protocol.Filesync +Protocol.Stat + + +Node2 + + +adb.filesync_protocol.Filesync +Protocol.Pull + + + + +Node1->Node2 + + + + + diff --git a/docs/source/_static/adb.filesync_protocol.FilesyncProtocol._HandleProgress.CALLER_GRAPH.svg b/docs/source/_static/adb.filesync_protocol.FilesyncProtocol._HandleProgress.CALLER_GRAPH.svg new file mode 100644 index 0000000..81b75e2 --- /dev/null +++ b/docs/source/_static/adb.filesync_protocol.FilesyncProtocol._HandleProgress.CALLER_GRAPH.svg @@ -0,0 +1,52 @@ + + + + + + +adb.filesync_protocol.FilesyncProtocol._HandleProgress + + +Node1 + +adb.filesync_protocol.Filesync +Protocol._HandleProgress + + +Node2 + + +adb.filesync_protocol.Filesync +Protocol.Pull + + + + +Node1->Node2 + + + + +Node3 + + +adb.filesync_protocol.Filesync +Protocol.Push + + + + +Node1->Node3 + + + + +Node3->Node1 + + + + + diff --git a/docs/source/_static/adb.filesync_protocol.FilesyncProtocol._HandleProgress.CALL_GRAPH.svg b/docs/source/_static/adb.filesync_protocol.FilesyncProtocol._HandleProgress.CALL_GRAPH.svg new file mode 100644 index 0000000..2bed025 --- /dev/null +++ b/docs/source/_static/adb.filesync_protocol.FilesyncProtocol._HandleProgress.CALL_GRAPH.svg @@ -0,0 +1,52 @@ + + + + + + +adb.filesync_protocol.FilesyncProtocol._HandleProgress + + +Node1 + +adb.filesync_protocol.Filesync +Protocol._HandleProgress + + +Node2 + + +adb.filesync_protocol.Filesync +Protocol.Push + + + + +Node1->Node2 + + + + +Node2->Node1 + + + + +Node3 + + +adb.fastboot.FastbootProtocol. +_HandleProgress + + + + +Node2->Node3 + + + + + diff --git a/docs/source/_static/adb.filesync_protocol.InterleavedDataError.CALL_GRAPH.svg b/docs/source/_static/adb.filesync_protocol.InterleavedDataError.CALL_GRAPH.svg new file mode 100644 index 0000000..48b49d3 --- /dev/null +++ b/docs/source/_static/adb.filesync_protocol.InterleavedDataError.CALL_GRAPH.svg @@ -0,0 +1,29 @@ + + + + + + +adb.filesync_protocol.InterleavedDataError + + +Node1 + +adb.filesync_protocol.Interleaved +DataError + + +Node2 + +Exception + + +Node2->Node1 + + + + + diff --git a/docs/source/_static/adb.filesync_protocol.InvalidChecksumError.CALL_GRAPH.svg b/docs/source/_static/adb.filesync_protocol.InvalidChecksumError.CALL_GRAPH.svg new file mode 100644 index 0000000..bead790 --- /dev/null +++ b/docs/source/_static/adb.filesync_protocol.InvalidChecksumError.CALL_GRAPH.svg @@ -0,0 +1,29 @@ + + + + + + +adb.filesync_protocol.InvalidChecksumError + + +Node1 + +adb.filesync_protocol.Invalid +ChecksumError + + +Node2 + +Exception + + +Node2->Node1 + + + + + diff --git a/docs/source/_static/adb.filesync_protocol.PullFailedError.CALL_GRAPH.svg b/docs/source/_static/adb.filesync_protocol.PullFailedError.CALL_GRAPH.svg new file mode 100644 index 0000000..0440412 --- /dev/null +++ b/docs/source/_static/adb.filesync_protocol.PullFailedError.CALL_GRAPH.svg @@ -0,0 +1,29 @@ + + + + + + +adb.filesync_protocol.PullFailedError + + +Node1 + +adb.filesync_protocol.Pull +FailedError + + +Node2 + +Exception + + +Node2->Node1 + + + + + diff --git a/docs/source/_static/adb.filesync_protocol.PushFailedError.CALL_GRAPH.svg b/docs/source/_static/adb.filesync_protocol.PushFailedError.CALL_GRAPH.svg new file mode 100644 index 0000000..62567fb --- /dev/null +++ b/docs/source/_static/adb.filesync_protocol.PushFailedError.CALL_GRAPH.svg @@ -0,0 +1,29 @@ + + + + + + +adb.filesync_protocol.PushFailedError + + +Node1 + +adb.filesync_protocol.Push +FailedError + + +Node2 + +Exception + + +Node2->Node1 + + + + + diff --git a/docs/source/_static/adb.sign_cryptography.CryptographySigner.CALL_GRAPH.svg b/docs/source/_static/adb.sign_cryptography.CryptographySigner.CALL_GRAPH.svg new file mode 100644 index 0000000..33dd444 --- /dev/null +++ b/docs/source/_static/adb.sign_cryptography.CryptographySigner.CALL_GRAPH.svg @@ -0,0 +1,39 @@ + + + + + + +adb.sign_cryptography.CryptographySigner + + +Node1 + +adb.sign_cryptography.Cryptography +Signer + + +Node2 + +adb.adb_protocol.AuthSigner + + +Node2->Node1 + + + + +Node3 + +object + + +Node3->Node2 + + + + + diff --git a/docs/source/_static/adb.sign_pycryptodome.PycryptodomeAuthSigner.CALL_GRAPH.svg b/docs/source/_static/adb.sign_pycryptodome.PycryptodomeAuthSigner.CALL_GRAPH.svg new file mode 100644 index 0000000..ec42279 --- /dev/null +++ b/docs/source/_static/adb.sign_pycryptodome.PycryptodomeAuthSigner.CALL_GRAPH.svg @@ -0,0 +1,39 @@ + + + + + + +adb.sign_pycryptodome.PycryptodomeAuthSigner + + +Node1 + +adb.sign_pycryptodome.Pycryptodome +AuthSigner + + +Node2 + +adb.adb_protocol.AuthSigner + + +Node2->Node1 + + + + +Node3 + +object + + +Node3->Node2 + + + + + diff --git a/docs/source/_static/adb.sign_pythonrsa.PythonRSASigner.CALL_GRAPH.svg b/docs/source/_static/adb.sign_pythonrsa.PythonRSASigner.CALL_GRAPH.svg new file mode 100644 index 0000000..bb5f8be --- /dev/null +++ b/docs/source/_static/adb.sign_pythonrsa.PythonRSASigner.CALL_GRAPH.svg @@ -0,0 +1,39 @@ + + + + + + +adb.sign_pythonrsa.PythonRSASigner + + +Node1 + +adb.sign_pythonrsa.Python +RSASigner + + +Node2 + +adb.adb_protocol.AuthSigner + + +Node2->Node1 + + + + +Node3 + +object + + +Node3->Node2 + + + + + diff --git a/docs/source/_static/adb.sign_pythonrsa._Accum.CALL_GRAPH.svg b/docs/source/_static/adb.sign_pythonrsa._Accum.CALL_GRAPH.svg new file mode 100644 index 0000000..3dcc80f --- /dev/null +++ b/docs/source/_static/adb.sign_pythonrsa._Accum.CALL_GRAPH.svg @@ -0,0 +1,29 @@ + + + + + + +adb.sign_pythonrsa._Accum + + +Node1 + +adb.sign_pythonrsa. +_Accum + + +Node2 + +object + + +Node2->Node1 + + + + + diff --git a/docs/source/_static/adb.usb_exceptions.AdbCommandFailureException.CALL_GRAPH.svg b/docs/source/_static/adb.usb_exceptions.AdbCommandFailureException.CALL_GRAPH.svg new file mode 100644 index 0000000..04bda64 --- /dev/null +++ b/docs/source/_static/adb.usb_exceptions.AdbCommandFailureException.CALL_GRAPH.svg @@ -0,0 +1,29 @@ + + + + + + +adb.usb_exceptions.AdbCommandFailureException + + +Node1 + +adb.usb_exceptions.AdbCommand +FailureException + + +Node2 + +Exception + + +Node2->Node1 + + + + + diff --git a/docs/source/_static/adb.usb_exceptions.AdbOperationException.CALL_GRAPH.svg b/docs/source/_static/adb.usb_exceptions.AdbOperationException.CALL_GRAPH.svg new file mode 100644 index 0000000..f5d89d0 --- /dev/null +++ b/docs/source/_static/adb.usb_exceptions.AdbOperationException.CALL_GRAPH.svg @@ -0,0 +1,29 @@ + + + + + + +adb.usb_exceptions.AdbOperationException + + +Node1 + +adb.usb_exceptions.AdbOperation +Exception + + +Node2 + +Exception + + +Node2->Node1 + + + + + diff --git a/docs/source/_static/adb.usb_exceptions.CommonUsbError.CALL_GRAPH.svg b/docs/source/_static/adb.usb_exceptions.CommonUsbError.CALL_GRAPH.svg new file mode 100644 index 0000000..998e6ce --- /dev/null +++ b/docs/source/_static/adb.usb_exceptions.CommonUsbError.CALL_GRAPH.svg @@ -0,0 +1,29 @@ + + + + + + +adb.usb_exceptions.CommonUsbError + + +Node1 + +adb.usb_exceptions.Common +UsbError + + +Node2 + +Exception + + +Node2->Node1 + + + + + diff --git a/docs/source/_static/adb.usb_exceptions.DeviceAuthError.CALL_GRAPH.svg b/docs/source/_static/adb.usb_exceptions.DeviceAuthError.CALL_GRAPH.svg new file mode 100644 index 0000000..36dd87a --- /dev/null +++ b/docs/source/_static/adb.usb_exceptions.DeviceAuthError.CALL_GRAPH.svg @@ -0,0 +1,51 @@ + + + + + + +adb.usb_exceptions.DeviceAuthError + + +Node1 + +adb.usb_exceptions.Device +AuthError + + +Node2 + +adb.usb_exceptions.Format +MessageWithArgumentsException + + +Node2->Node1 + + + + +Node3 + +adb.usb_exceptions.Common +UsbError + + +Node3->Node2 + + + + +Node4 + +Exception + + +Node4->Node3 + + + + + diff --git a/docs/source/_static/adb.usb_exceptions.DeviceNotFoundError.CALL_GRAPH.svg b/docs/source/_static/adb.usb_exceptions.DeviceNotFoundError.CALL_GRAPH.svg new file mode 100644 index 0000000..ded8fc8 --- /dev/null +++ b/docs/source/_static/adb.usb_exceptions.DeviceNotFoundError.CALL_GRAPH.svg @@ -0,0 +1,51 @@ + + + + + + +adb.usb_exceptions.DeviceNotFoundError + + +Node1 + +adb.usb_exceptions.Device +NotFoundError + + +Node2 + +adb.usb_exceptions.Format +MessageWithArgumentsException + + +Node2->Node1 + + + + +Node3 + +adb.usb_exceptions.Common +UsbError + + +Node3->Node2 + + + + +Node4 + +Exception + + +Node4->Node3 + + + + + diff --git a/docs/source/_static/adb.usb_exceptions.FormatMessageWithArgumentsException.CALL_GRAPH.svg b/docs/source/_static/adb.usb_exceptions.FormatMessageWithArgumentsException.CALL_GRAPH.svg new file mode 100644 index 0000000..d19a6da --- /dev/null +++ b/docs/source/_static/adb.usb_exceptions.FormatMessageWithArgumentsException.CALL_GRAPH.svg @@ -0,0 +1,117 @@ + + + + + + +adb.usb_exceptions.FormatMessageWithArgumentsException + + +Node1 + +adb.usb_exceptions.Format +MessageWithArgumentsException + + +Node4 + +adb.fastboot.FastbootInvalid +Response + + +Node1->Node4 + + + + +Node5 + +adb.fastboot.FastbootRemote +Failure + + +Node1->Node5 + + + + +Node6 + +adb.fastboot.FastbootState +Mismatch + + +Node1->Node6 + + + + +Node7 + +adb.fastboot.FastbootTransfer +Error + + +Node1->Node7 + + + + +Node8 + +adb.usb_exceptions.Device +AuthError + + +Node1->Node8 + + + + +Node9 + +adb.usb_exceptions.Device +NotFoundError + + +Node1->Node9 + + + + +Node10 + +adb.usb_exceptions.TcpTimeout +Exception + + +Node1->Node10 + + + + +Node2 + +adb.usb_exceptions.Common +UsbError + + +Node2->Node1 + + + + +Node3 + +Exception + + +Node3->Node2 + + + + + diff --git a/docs/source/_static/adb.usb_exceptions.LibusbWrappingError.CALL_GRAPH.svg b/docs/source/_static/adb.usb_exceptions.LibusbWrappingError.CALL_GRAPH.svg new file mode 100644 index 0000000..ff38d86 --- /dev/null +++ b/docs/source/_static/adb.usb_exceptions.LibusbWrappingError.CALL_GRAPH.svg @@ -0,0 +1,62 @@ + + + + + + +adb.usb_exceptions.LibusbWrappingError + + +Node1 + +adb.usb_exceptions.Libusb +WrappingError + + +Node4 + +adb.usb_exceptions.ReadFailed +Error + + +Node1->Node4 + + + + +Node5 + +adb.usb_exceptions.Write +FailedError + + +Node1->Node5 + + + + +Node2 + +adb.usb_exceptions.Common +UsbError + + +Node2->Node1 + + + + +Node3 + +Exception + + +Node3->Node2 + + + + + diff --git a/docs/source/_static/adb.usb_exceptions.ReadFailedError.CALL_GRAPH.svg b/docs/source/_static/adb.usb_exceptions.ReadFailedError.CALL_GRAPH.svg new file mode 100644 index 0000000..843b695 --- /dev/null +++ b/docs/source/_static/adb.usb_exceptions.ReadFailedError.CALL_GRAPH.svg @@ -0,0 +1,51 @@ + + + + + + +adb.usb_exceptions.ReadFailedError + + +Node1 + +adb.usb_exceptions.ReadFailed +Error + + +Node2 + +adb.usb_exceptions.Libusb +WrappingError + + +Node2->Node1 + + + + +Node3 + +adb.usb_exceptions.Common +UsbError + + +Node3->Node2 + + + + +Node4 + +Exception + + +Node4->Node3 + + + + + diff --git a/docs/source/_static/adb.usb_exceptions.TcpTimeoutException.CALL_GRAPH.svg b/docs/source/_static/adb.usb_exceptions.TcpTimeoutException.CALL_GRAPH.svg new file mode 100644 index 0000000..17f75a6 --- /dev/null +++ b/docs/source/_static/adb.usb_exceptions.TcpTimeoutException.CALL_GRAPH.svg @@ -0,0 +1,51 @@ + + + + + + +adb.usb_exceptions.TcpTimeoutException + + +Node1 + +adb.usb_exceptions.TcpTimeout +Exception + + +Node2 + +adb.usb_exceptions.Format +MessageWithArgumentsException + + +Node2->Node1 + + + + +Node3 + +adb.usb_exceptions.Common +UsbError + + +Node3->Node2 + + + + +Node4 + +Exception + + +Node4->Node3 + + + + + diff --git a/docs/source/_static/adb.usb_exceptions.WriteFailedError.CALL_GRAPH.svg b/docs/source/_static/adb.usb_exceptions.WriteFailedError.CALL_GRAPH.svg new file mode 100644 index 0000000..6ba6cb3 --- /dev/null +++ b/docs/source/_static/adb.usb_exceptions.WriteFailedError.CALL_GRAPH.svg @@ -0,0 +1,51 @@ + + + + + + +adb.usb_exceptions.WriteFailedError + + +Node1 + +adb.usb_exceptions.Write +FailedError + + +Node2 + +adb.usb_exceptions.Libusb +WrappingError + + +Node2->Node1 + + + + +Node3 + +adb.usb_exceptions.Common +UsbError + + +Node3->Node2 + + + + +Node4 + +Exception + + +Node4->Node3 + + + + + diff --git a/docs/source/adb.adb_commands.rst b/docs/source/adb.adb_commands.rst new file mode 100644 index 0000000..021a69d --- /dev/null +++ b/docs/source/adb.adb_commands.rst @@ -0,0 +1,7 @@ +adb.adb\_commands module +======================== + +.. automodule:: adb.adb_commands + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/adb.adb_debug.rst b/docs/source/adb.adb_debug.rst new file mode 100644 index 0000000..d412a7f --- /dev/null +++ b/docs/source/adb.adb_debug.rst @@ -0,0 +1,7 @@ +adb.adb\_debug module +===================== + +.. automodule:: adb.adb_debug + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/adb.adb_keygen.rst b/docs/source/adb.adb_keygen.rst new file mode 100644 index 0000000..39f422b --- /dev/null +++ b/docs/source/adb.adb_keygen.rst @@ -0,0 +1,7 @@ +adb.adb\_keygen module +====================== + +.. automodule:: adb.adb_keygen + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/adb.adb_protocol.rst b/docs/source/adb.adb_protocol.rst new file mode 100644 index 0000000..9ea9695 --- /dev/null +++ b/docs/source/adb.adb_protocol.rst @@ -0,0 +1,7 @@ +adb.adb\_protocol module +======================== + +.. automodule:: adb.adb_protocol + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/adb.common.rst b/docs/source/adb.common.rst new file mode 100644 index 0000000..19b26bd --- /dev/null +++ b/docs/source/adb.common.rst @@ -0,0 +1,7 @@ +adb.common module +================= + +.. automodule:: adb.common + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/adb.common_cli.rst b/docs/source/adb.common_cli.rst new file mode 100644 index 0000000..1e217c7 --- /dev/null +++ b/docs/source/adb.common_cli.rst @@ -0,0 +1,7 @@ +adb.common\_cli module +====================== + +.. automodule:: adb.common_cli + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/adb.debug.rst b/docs/source/adb.debug.rst new file mode 100644 index 0000000..2ba2f2f --- /dev/null +++ b/docs/source/adb.debug.rst @@ -0,0 +1,7 @@ +adb.debug module +================ + +.. automodule:: adb.debug + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/adb.fastboot.rst b/docs/source/adb.fastboot.rst new file mode 100644 index 0000000..de980b6 --- /dev/null +++ b/docs/source/adb.fastboot.rst @@ -0,0 +1,7 @@ +adb.fastboot module +=================== + +.. automodule:: adb.fastboot + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/adb.fastboot_debug.rst b/docs/source/adb.fastboot_debug.rst new file mode 100644 index 0000000..da21ba5 --- /dev/null +++ b/docs/source/adb.fastboot_debug.rst @@ -0,0 +1,7 @@ +adb.fastboot\_debug module +========================== + +.. automodule:: adb.fastboot_debug + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/adb.filesync_protocol.rst b/docs/source/adb.filesync_protocol.rst new file mode 100644 index 0000000..9fa26fa --- /dev/null +++ b/docs/source/adb.filesync_protocol.rst @@ -0,0 +1,7 @@ +adb.filesync\_protocol module +============================= + +.. automodule:: adb.filesync_protocol + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/adb.rst b/docs/source/adb.rst new file mode 100644 index 0000000..76c8691 --- /dev/null +++ b/docs/source/adb.rst @@ -0,0 +1,30 @@ +adb package +=========== + +Submodules +---------- + +.. toctree:: + + adb.adb_commands + adb.adb_debug + adb.adb_keygen + adb.adb_protocol + adb.common + adb.common_cli + adb.debug + adb.fastboot + adb.fastboot_debug + adb.filesync_protocol + adb.sign_cryptography + adb.sign_pycryptodome + adb.sign_pythonrsa + adb.usb_exceptions + +Module contents +--------------- + +.. automodule:: adb + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/adb.sign_cryptography.rst b/docs/source/adb.sign_cryptography.rst new file mode 100644 index 0000000..c5b7211 --- /dev/null +++ b/docs/source/adb.sign_cryptography.rst @@ -0,0 +1,7 @@ +adb.sign\_cryptography module +============================= + +.. automodule:: adb.sign_cryptography + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/adb.sign_pycryptodome.rst b/docs/source/adb.sign_pycryptodome.rst new file mode 100644 index 0000000..4a33df4 --- /dev/null +++ b/docs/source/adb.sign_pycryptodome.rst @@ -0,0 +1,7 @@ +adb.sign\_pycryptodome module +============================= + +.. automodule:: adb.sign_pycryptodome + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/adb.sign_pythonrsa.rst b/docs/source/adb.sign_pythonrsa.rst new file mode 100644 index 0000000..1f3bf48 --- /dev/null +++ b/docs/source/adb.sign_pythonrsa.rst @@ -0,0 +1,7 @@ +adb.sign\_pythonrsa module +========================== + +.. automodule:: adb.sign_pythonrsa + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/adb.usb_exceptions.rst b/docs/source/adb.usb_exceptions.rst new file mode 100644 index 0000000..addb15a --- /dev/null +++ b/docs/source/adb.usb_exceptions.rst @@ -0,0 +1,7 @@ +adb.usb\_exceptions module +========================== + +.. automodule:: adb.usb_exceptions + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 0000000..33a382b --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,182 @@ +# -*- coding: utf-8 -*- +# +# Configuration file for the Sphinx documentation builder. +# +# This file does only contain a selection of the most common options. For a +# full list see the documentation: +# http://www.sphinx-doc.org/en/master/config + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +import os +import sys +sys.path.insert(0, os.path.abspath('../..')) + +import sphinx_rtd_theme + + +# -- Project information ----------------------------------------------------- + +project = 'adb' +copyright = '2019, Google' +author = 'Fahrzin Hemmati' + +# The short X.Y version +version = '1.3.0' +# The full version, including alpha/beta/rc tags +release = '1.3.0' + + +# -- General configuration --------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.todo', + 'sphinx.ext.mathjax', + 'sphinx.ext.viewcode', + 'sphinx.ext.autodoc', + 'sphinx.ext.napoleon' +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path . +exclude_patterns = [] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +autodoc_mock_imports = ['Crypto', 'cryptography', 'libusb1', 'pyasn1', 'usb1'] + +autodoc_default_options = {'members': True, 'undoc-members': True, 'private-members': True, 'show-inheritance': True} + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'sphinx_rtd_theme' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +# html_theme_options = {} + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Custom sidebar templates, must be a dictionary that maps document names +# to template names. +# +# The default sidebars (for documents that don't match any pattern) are +# defined by theme itself. Builtin themes are using these templates by +# default: ``['localtoc.html', 'relations.html', 'sourcelink.html', +# 'searchbox.html']``. +# +# html_sidebars = {} + + +# -- Options for HTMLHelp output --------------------------------------------- + +# Output file base name for HTML help builder. +htmlhelp_basename = 'adbdoc' + + +# -- Options for LaTeX output ------------------------------------------------ + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'adb.tex', 'adb Documentation', + 'Fahrzin Hemmati', 'manual'), +] + + +# -- Options for manual page output ------------------------------------------ + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'adb', 'adb Documentation', + [author], 1) +] + + +# -- Options for Texinfo output ---------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'adb', 'adb Documentation', + author, 'adb', 'One line description of project.', + 'Miscellaneous'), +] + + +# -- Extension configuration ------------------------------------------------- + +# -- Options for todo extension ---------------------------------------------- + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = True + + +def autodoc_skip_member(app, what, name, obj, skip, options): + exclusions = ('_asdict', '_fields', '_make', '_replace', '_source', 'header', 'message') + exclude = name in exclusions + return skip or exclude + +def setup(app): + app.connect('autodoc-skip-member', autodoc_skip_member) diff --git a/docs/source/index.rst b/docs/source/index.rst new file mode 100644 index 0000000..eb33752 --- /dev/null +++ b/docs/source/index.rst @@ -0,0 +1,25 @@ +.. ADB documentation master file, created by + sphinx-quickstart on Mon Sep 05 22:06:10 2016. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +adb Documentation +================= + +.. toctree:: + :hidden: + + self + modules.rst + + +.. include:: ../../README.rst + :start-line: 15 + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/docs/source/modules.rst b/docs/source/modules.rst new file mode 100644 index 0000000..1dedc85 --- /dev/null +++ b/docs/source/modules.rst @@ -0,0 +1,7 @@ +adb +=== + +.. toctree:: + :maxdepth: 4 + + adb diff --git a/setup.py b/setup.py index fbcdb81..d782040 100644 --- a/setup.py +++ b/setup.py @@ -65,10 +65,12 @@ rsa_signer_library ], - extra_requires = { + extras_require = { 'fastboot': 'progressbar>=2.3' }, + tests_require = ['cryptography', 'pycryptodome', 'rsa'], + ## classifier list https://pypi.python.org/pypi?:action=list_classifiers classifiers = [ 'Development Status :: 4 - Beta', diff --git a/test/__init__.py b/test/__init__.py new file mode 100644 index 0000000..e669d95 --- /dev/null +++ b/test/__init__.py @@ -0,0 +1,4 @@ +import os +import sys + +sys.path.insert(0, os.path.dirname(__file__)) diff --git a/test/adb_keygen_stub.py b/test/adb_keygen_stub.py new file mode 100644 index 0000000..a19fbfa --- /dev/null +++ b/test/adb_keygen_stub.py @@ -0,0 +1,29 @@ +from contextlib import contextmanager +from mock import patch + + +class FileReadWrite(object): + """Mock an opened file that can be read and written to.""" + def __init__(self): + self._content = b'' + + def read(self): + return self._content + + def write(self, content): + self._content = content + + +PRIVATE_KEY = FileReadWrite() +PUBLIC_KEY = FileReadWrite() + + +@contextmanager +def open_priv_pub(infile, mode='r'): + try: + if infile.endswith('.pub'): + yield PUBLIC_KEY + else: + yield PRIVATE_KEY + finally: + pass diff --git a/test/test_adb_protocol.py b/test/test_adb_protocol.py new file mode 100755 index 0000000..0ce1ead --- /dev/null +++ b/test/test_adb_protocol.py @@ -0,0 +1,315 @@ +#!/usr/bin/env python +# Copyright 2014 Google Inc. All rights reserved. +# +# 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. +"""Tests for adb.""" + +from io import BytesIO +import struct +import unittest +from mock import mock + + +from adb import common +from adb import adb_commands +from adb import adb_protocol +from adb.usb_exceptions import TcpTimeoutException, DeviceNotFoundError +import common_stub + + +BANNER = b'blazetest' +LOCAL_ID = 1 +REMOTE_ID = 2 + + +class BaseAdbTest(unittest.TestCase): + + @classmethod + def _ExpectWrite(cls, usb, command, arg0, arg1, data): + usb.ExpectWrite(cls._MakeHeader(command, arg0, arg1, data)) + usb.ExpectWrite(data) + if command == b'WRTE': + cls._ExpectRead(usb, b'OKAY', 0, 0) + + @classmethod + def _ExpectRead(cls, usb, command, arg0, arg1, data=b''): + usb.ExpectRead(cls._MakeHeader(command, arg0, arg1, data)) + if data: + usb.ExpectRead(data) + if command == b'WRTE': + cls._ExpectWrite(usb, b'OKAY', LOCAL_ID, REMOTE_ID, b'') + + @classmethod + def _ConvertCommand(cls, command): + return sum(c << (i * 8) for i, c in enumerate(bytearray(command))) + + @classmethod + def _MakeHeader(cls, command, arg0, arg1, data): + command = cls._ConvertCommand(command) + magic = command ^ 0xFFFFFFFF + checksum = adb_protocol.AdbMessage.CalculateChecksum(data) + return struct.pack(b'<6I', command, arg0, arg1, len(data), checksum, magic) + + @classmethod + def _ExpectConnection(cls, usb): + cls._ExpectWrite(usb, b'CNXN', 0x01000000, 4096, b'host::%s\0' % BANNER) + cls._ExpectRead(usb, b'CNXN', 0, 0, b'device::\0') + + @classmethod + def _ExpectOpen(cls, usb, service): + cls._ExpectWrite(usb, b'OPEN', LOCAL_ID, 0, service) + cls._ExpectRead(usb, b'OKAY', REMOTE_ID, LOCAL_ID) + + @classmethod + def _ExpectClose(cls, usb): + cls._ExpectRead(usb, b'CLSE', REMOTE_ID, 0) + cls._ExpectWrite(usb, b'CLSE', LOCAL_ID, REMOTE_ID, b'') + + @classmethod + def _Connect(cls, usb): + return adb_commands.AdbCommands.Connect(usb, BANNER) + + +class AdbTest(BaseAdbTest): + @classmethod + def _ExpectCommand(cls, service, command, *responses): + usb = common_stub.StubUsb(device=None, setting=None) + cls._ExpectConnection(usb) + cls._ExpectOpen(usb, b'%s:%s\0' % (service, command)) + + for response in responses: + cls._ExpectRead(usb, b'WRTE', REMOTE_ID, 0, response) + cls._ExpectClose(usb) + return usb + + def testConnect(self): + usb = common_stub.StubUsb(device=None, setting=None) + self._ExpectConnection(usb) + + dev = adb_commands.AdbCommands() + dev.ConnectDevice(handle=usb, banner=BANNER) + + def testConnectSerialString(self): + dev = adb_commands.AdbCommands() + + with mock.patch.object(common.UsbHandle, 'FindAndOpen', return_value=None): + with mock.patch.object(adb_commands.AdbCommands, '_Connect', return_value=None): + dev.ConnectDevice(serial='/dev/invalidHandle') + + def testSmallResponseShell(self): + command = b'keepin it real' + response = 'word.' + usb = self._ExpectCommand(b'shell', command, response) + + dev = adb_commands.AdbCommands() + dev.ConnectDevice(handle=usb, banner=BANNER) + self.assertEqual(response, dev.Shell(command)) + + def testBigResponseShell(self): + command = b'keepin it real big' + # The data doesn't have to be big, the point is that it just concatenates + # the data from different WRTEs together. + responses = [b'other stuff, ', b'and some words.'] + + usb = self._ExpectCommand(b'shell', command, *responses) + + dev = adb_commands.AdbCommands() + dev.ConnectDevice(handle=usb, banner=BANNER) + self.assertEqual(b''.join(responses).decode('utf8'), + dev.Shell(command)) + + def testUninstall(self): + package_name = "com.test.package" + response = 'Success' + + usb = self._ExpectCommand(b'shell', ('pm uninstall "%s"' % package_name).encode('utf8'), response) + + dev = adb_commands.AdbCommands() + dev.ConnectDevice(handle=usb, banner=BANNER) + self.assertEqual(response, dev.Uninstall(package_name)) + + def testStreamingResponseShell(self): + command = b'keepin it real big' + # expect multiple lines + + responses = ['other stuff, ', 'and some words.'] + + usb = self._ExpectCommand(b'shell', command, *responses) + + dev = adb_commands.AdbCommands() + dev.ConnectDevice(handle=usb, banner=BANNER) + response_count = 0 + for (expected,actual) in zip(responses, dev.StreamingShell(command)): + self.assertEqual(expected, actual) + response_count = response_count + 1 + self.assertEqual(len(responses), response_count) + + def testReboot(self): + usb = self._ExpectCommand(b'reboot', b'', b'') + dev = adb_commands.AdbCommands() + dev.ConnectDevice(handle=usb, banner=BANNER) + dev.Reboot() + + def testRebootBootloader(self): + usb = self._ExpectCommand(b'reboot', b'bootloader', b'') + dev = adb_commands.AdbCommands() + dev.ConnectDevice(handle=usb, banner=BANNER) + dev.RebootBootloader() + + def testRemount(self): + usb = self._ExpectCommand(b'remount', b'', b'') + dev = adb_commands.AdbCommands() + dev.ConnectDevice(handle=usb, banner=BANNER) + dev.Remount() + + def testRoot(self): + usb = self._ExpectCommand(b'root', b'', b'') + dev = adb_commands.AdbCommands() + dev.ConnectDevice(handle=usb, banner=BANNER) + dev.Root() + + def testEnableVerity(self): + usb = self._ExpectCommand(b'enable-verity', b'', b'') + dev = adb_commands.AdbCommands() + dev.ConnectDevice(handle=usb, banner=BANNER) + dev.EnableVerity() + + def testDisableVerity(self): + usb = self._ExpectCommand(b'disable-verity', b'', b'') + dev = adb_commands.AdbCommands() + dev.ConnectDevice(handle=usb, banner=BANNER) + dev.DisableVerity() + +class FilesyncAdbTest(BaseAdbTest): + + @classmethod + def _MakeSyncHeader(cls, command, *int_parts): + command = cls._ConvertCommand(command) + return struct.pack(b'<%dI' % (len(int_parts) + 1), command, *int_parts) + + @classmethod + def _MakeWriteSyncPacket(cls, command, data=b'', size=None): + if not isinstance(data, bytes): + data = data.encode('utf8') + return cls._MakeSyncHeader(command, size or len(data)) + data + + @classmethod + def _ExpectSyncCommand(cls, write_commands, read_commands): + usb = common_stub.StubUsb(device=None, setting=None) + cls._ExpectConnection(usb) + cls._ExpectOpen(usb, b'sync:\0') + + while write_commands or read_commands: + if write_commands: + command = write_commands.pop(0) + cls._ExpectWrite(usb, b'WRTE', LOCAL_ID, REMOTE_ID, command) + + if read_commands: + command = read_commands.pop(0) + cls._ExpectRead(usb, b'WRTE', REMOTE_ID, LOCAL_ID, command) + + cls._ExpectClose(usb) + return usb + + def testPush(self): + filedata = b'alo there, govnah' + mtime = 100 + + send = [ + self._MakeWriteSyncPacket(b'SEND', b'/data,33272'), + self._MakeWriteSyncPacket(b'DATA', filedata), + self._MakeWriteSyncPacket(b'DONE', size=mtime), + ] + data = b'OKAY\0\0\0\0' + usb = self._ExpectSyncCommand([b''.join(send)], [data]) + + dev = adb_commands.AdbCommands() + dev.ConnectDevice(handle=usb, banner=BANNER) + dev.Push(BytesIO(filedata), '/data', mtime=mtime) + + def testPull(self): + filedata = b"g'ddayta, govnah" + + recv = self._MakeWriteSyncPacket(b'RECV', b'/data') + data = [ + self._MakeWriteSyncPacket(b'DATA', filedata), + self._MakeWriteSyncPacket(b'DONE'), + ] + usb = self._ExpectSyncCommand([recv], [b''.join(data)]) + dev = adb_commands.AdbCommands() + dev.ConnectDevice(handle=usb, banner=BANNER) + self.assertEqual(filedata, dev.Pull('/data')) + + +class TcpTimeoutAdbTest(BaseAdbTest): + + @classmethod + def _ExpectCommand(cls, service, command, *responses): + tcp = common_stub.StubTcp('10.0.0.123') + cls._ExpectConnection(tcp) + cls._ExpectOpen(tcp, b'%s:%s\0' % (service, command)) + + for response in responses: + cls._ExpectRead(tcp, b'WRTE', REMOTE_ID, 0, response) + cls._ExpectClose(tcp) + return tcp + + def _run_shell(self, cmd, timeout_ms=None): + tcp = self._ExpectCommand(b'shell', cmd) + dev = adb_commands.AdbCommands() + dev.ConnectDevice(handle=tcp, banner=BANNER) + dev.Shell(cmd, timeout_ms=timeout_ms) + + def testConnect(self): + tcp = common_stub.StubTcp('10.0.0.123') + self._ExpectConnection(tcp) + dev = adb_commands.AdbCommands() + dev.ConnectDevice(handle=tcp, banner=BANNER) + + def testTcpTimeout(self): + timeout_ms = 1 + command = b'i_need_a_timeout' + self.assertRaises( + TcpTimeoutException, + self._run_shell, + command, + timeout_ms=timeout_ms) + + +class TcpHandleTest(unittest.TestCase): + def testInitWithHost(self): + tcp = common_stub.StubTcp('10.11.12.13') + + self.assertEqual('10.11.12.13:5555', tcp._serial_number) + self.assertEqual(None, tcp._timeout_ms) + + def testInitWithHostAndPort(self): + tcp = common_stub.StubTcp('10.11.12.13:5678') + + self.assertEqual('10.11.12.13:5678', tcp._serial_number) + self.assertEqual(None, tcp._timeout_ms) + + def testInitWithTimeout(self): + tcp = common_stub.StubTcp('10.0.0.2', timeout_ms=234.5) + + self.assertEqual('10.0.0.2:5555', tcp._serial_number) + self.assertEqual(234.5, tcp._timeout_ms) + + def testInitWithTimeoutInt(self): + tcp = common_stub.StubTcp('10.0.0.2', timeout_ms=234) + + self.assertEqual('10.0.0.2:5555', tcp._serial_number) + self.assertEqual(234.0, tcp._timeout_ms) + +if __name__ == '__main__': + unittest.main() diff --git a/test/test_sign_cryptography.py b/test/test_sign_cryptography.py new file mode 100644 index 0000000..fc0f9c8 --- /dev/null +++ b/test/test_sign_cryptography.py @@ -0,0 +1,29 @@ +from mock import patch +import os +import unittest + +from adb.adb_keygen import keygen +from adb.sign_cryptography import CryptographySigner + +from adb_keygen_stub import open_priv_pub + + +class TestCryptographySigner(unittest.TestCase): + def setUp(self): + with patch('adb.sign_cryptography.open', open_priv_pub), patch('adb.adb_keygen.open', open_priv_pub): + keygen('test/adbkey') + self.signer = CryptographySigner('test/adbkey') + + def test_sign(self): + """Test that the ``Sign`` method does not raise an exception.""" + with self.assertRaises(ValueError): + self.signer.Sign(b'notadb') + self.assertTrue(True) + + def test_get_public_key(self): + """Test that the ``GetPublicKey`` method works correctly.""" + with patch('{}.open'.format(__name__), open_priv_pub): + with open('test/adbkey.pub') as f: + pub = f.read() + + self.assertEqual(pub, self.signer.GetPublicKey()) diff --git a/test/test_sign_pycryptodome.py b/test/test_sign_pycryptodome.py new file mode 100644 index 0000000..2de1509 --- /dev/null +++ b/test/test_sign_pycryptodome.py @@ -0,0 +1,28 @@ +from mock import patch +import os +import unittest + +from adb.adb_keygen import keygen +from adb.sign_pycryptodome import PycryptodomeAuthSigner + +from adb_keygen_stub import open_priv_pub + + +class TestPycryptodomeAuthSigner(unittest.TestCase): + def setUp(self): + with patch('adb.sign_pycryptodome.open', open_priv_pub), patch('adb.adb_keygen.open', open_priv_pub): + keygen('test/adbkey') + self.signer = PycryptodomeAuthSigner('test/adbkey') + + def test_sign(self): + """Test that the ``Sign`` method does not raise an exception.""" + self.signer.Sign(b'notadb') + self.assertTrue(True) + + def test_get_public_key(self): + """Test that the ``GetPublicKey`` method works correctly.""" + with patch('{}.open'.format(__name__), open_priv_pub): + with open('test/adbkey.pub') as f: + pub = f.read() + + self.assertEqual(pub, self.signer.GetPublicKey()) diff --git a/test/test_sign_pythonrsa.py b/test/test_sign_pythonrsa.py new file mode 100644 index 0000000..2137388 --- /dev/null +++ b/test/test_sign_pythonrsa.py @@ -0,0 +1,28 @@ +from mock import patch +import os +import unittest + +from adb.adb_keygen import keygen +from adb.sign_pythonrsa import PythonRSASigner + +from adb_keygen_stub import open_priv_pub + + +class TestPythonRSASigner(unittest.TestCase): + def setUp(self): + with patch('adb.sign_pythonrsa.open', open_priv_pub), patch('adb.adb_keygen.open', open_priv_pub): + keygen('test/adbkey') + self.signer = PythonRSASigner.FromRSAKeyPath('test/adbkey') + + def test_sign(self): + """Test that the ``Sign`` method does not raise an exception.""" + self.signer.Sign(b'notadb') + self.assertTrue(True) + + def test_get_public_key(self): + """Test that the ``GetPublicKey`` method works correctly.""" + with patch('{}.open'.format(__name__), open_priv_pub): + with open('test/adbkey.pub') as f: + pub = f.read() + + self.assertEqual(pub, self.signer.GetPublicKey()) diff --git a/tox.ini b/tox.ini index 0f9881a..9cb1435 100644 --- a/tox.ini +++ b/tox.ini @@ -13,5 +13,8 @@ deps = pytest pytest-cov mock + cryptography + pycryptodome + rsa usedevelop = True commands = py.test --cov adb test