123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211 |
- #!/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.
- """Daemon-less ADB client in python."""
- import argparse
- import functools
- import logging
- import os
- import stat
- import sys
- import time
- from adb import adb_commands
- from adb import common_cli
- try:
- from adb import sign_m2crypto
- rsa_signer = sign_m2crypto.M2CryptoSigner
- except ImportError:
- try:
- from adb import sign_pythonrsa
- rsa_signer = sign_pythonrsa.PythonRSASigner.FromRSAKeyPath
- except ImportError:
- try:
- from adb import sign_pycryptodome
- rsa_signer = sign_pycryptodome.PycryptodomeAuthSigner
- except ImportError:
- rsa_signer = None
- def Devices(args):
- """Lists the available devices.
- Mimics 'adb devices' output:
- List of devices attached
- 015DB7591102001A device 1,2
- """
- 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)))
- else:
- print('%s\tdevice' % d.serial_number)
- return 0
- def List(device, device_path):
- """Prints a directory listing.
- Args:
- device_path: Directory to list.
- """
- 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 '-') +
- ('r' if f.mode & stat.S_IRUSR else '-') +
- ('w' if f.mode & stat.S_IWUSR else '-') +
- ('x' if f.mode & stat.S_IXUSR else '-') +
- ('r' if f.mode & stat.S_IRGRP else '-') +
- ('w' if f.mode & stat.S_IWGRP else '-') +
- ('x' if f.mode & stat.S_IXGRP else '-') +
- ('r' if f.mode & stat.S_IROTH else '-') +
- ('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,
- maxname, f.filename)
- @functools.wraps(adb_commands.AdbCommands.Logcat)
- def Logcat(device, *options):
- 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.
- """
- 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()
- def main():
- 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.')
- device = common_cli.GetDeviceArguments()
- parents = [common, device]
- 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')
- 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.Root)
- common_cli.MakeSubparser(subparsers, parents, adb_commands.AdbCommands.EnableVerity)
- common_cli.MakeSubparser(subparsers, parents, adb_commands.AdbCommands.DisableVerity)
- common_cli.MakeSubparser(subparsers, parents, Shell)
- if len(sys.argv) == 1:
- parser.print_help()
- return 2
- 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 M2Crypto, 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])
- if __name__ == '__main__':
- sys.exit(main())
|