csmartdalton | 0262b5c | 2016-09-19 12:04:56 -0700 | [diff] [blame] | 1 | # Copyright 2016 Google Inc. |
| 2 | # |
| 3 | # Use of this source code is governed by a BSD-style license that can be |
| 4 | # found in the LICENSE file. |
| 5 | |
csmartdalton | e4fd078 | 2016-11-09 08:41:23 -0800 | [diff] [blame] | 6 | from __future__ import print_function |
csmartdalton | d7a9db6 | 2016-09-22 05:10:02 -0700 | [diff] [blame] | 7 | import re |
Chris Dalton | 34d9055 | 2017-10-20 09:58:32 -0600 | [diff] [blame] | 8 | import time |
csmartdalton | 0262b5c | 2016-09-19 12:04:56 -0700 | [diff] [blame] | 9 | import subprocess |
csmartdalton | 310d72c | 2016-10-18 09:19:50 -0700 | [diff] [blame] | 10 | import sys |
csmartdalton | 0262b5c | 2016-09-19 12:04:56 -0700 | [diff] [blame] | 11 | |
csmartdalton | d7a9db6 | 2016-09-22 05:10:02 -0700 | [diff] [blame] | 12 | class Adb: |
Kevin Lubick | cccaef1 | 2017-10-13 08:15:09 -0400 | [diff] [blame] | 13 | def __init__(self, device_serial=None, adb_binary=None, echo=False): |
| 14 | self.__invocation = [adb_binary] |
csmartdalton | d7a9db6 | 2016-09-22 05:10:02 -0700 | [diff] [blame] | 15 | if device_serial: |
| 16 | self.__invocation.extend(['-s', device_serial]) |
csmartdalton | a115129 | 2016-11-09 15:37:48 -0500 | [diff] [blame] | 17 | self.__echo = echo |
csmartdalton | e4fd078 | 2016-11-09 08:41:23 -0800 | [diff] [blame] | 18 | self.__is_root = None |
Chris Dalton | 88b448a | 2019-07-26 16:20:04 -0400 | [diff] [blame^] | 19 | self.__has_established_connection = False |
csmartdalton | 0262b5c | 2016-09-19 12:04:56 -0700 | [diff] [blame] | 20 | |
csmartdalton | d7a9db6 | 2016-09-22 05:10:02 -0700 | [diff] [blame] | 21 | def shell(self, cmd): |
csmartdalton | a115129 | 2016-11-09 15:37:48 -0500 | [diff] [blame] | 22 | if self.__echo: |
| 23 | self.__echo_shell_cmd(cmd) |
| 24 | self.__invoke('shell', cmd) |
csmartdalton | d7a9db6 | 2016-09-22 05:10:02 -0700 | [diff] [blame] | 25 | |
| 26 | def check(self, cmd): |
csmartdalton | a115129 | 2016-11-09 15:37:48 -0500 | [diff] [blame] | 27 | if self.__echo: |
| 28 | self.__echo_shell_cmd(cmd) |
Chris Dalton | 88b448a | 2019-07-26 16:20:04 -0400 | [diff] [blame^] | 29 | self.__establish_connection() |
csmartdalton | d7a9db6 | 2016-09-22 05:10:02 -0700 | [diff] [blame] | 30 | result = subprocess.check_output(self.__invocation + ['shell', cmd]) |
csmartdalton | a115129 | 2016-11-09 15:37:48 -0500 | [diff] [blame] | 31 | if self.__echo: |
| 32 | print(result, file=sys.stderr) |
csmartdalton | e4fd078 | 2016-11-09 08:41:23 -0800 | [diff] [blame] | 33 | return result |
csmartdalton | d7a9db6 | 2016-09-22 05:10:02 -0700 | [diff] [blame] | 34 | |
csmartdalton | e4fd078 | 2016-11-09 08:41:23 -0800 | [diff] [blame] | 35 | def root(self): |
| 36 | if not self.is_root(): |
csmartdalton | a115129 | 2016-11-09 15:37:48 -0500 | [diff] [blame] | 37 | self.__invoke('root') |
Chris Dalton | 88b448a | 2019-07-26 16:20:04 -0400 | [diff] [blame^] | 38 | self.__has_established_connection = False |
csmartdalton | e4fd078 | 2016-11-09 08:41:23 -0800 | [diff] [blame] | 39 | self.__is_root = None |
| 40 | return self.is_root() |
csmartdalton | d7a9db6 | 2016-09-22 05:10:02 -0700 | [diff] [blame] | 41 | |
| 42 | def is_root(self): |
csmartdalton | e4fd078 | 2016-11-09 08:41:23 -0800 | [diff] [blame] | 43 | if self.__is_root is None: |
| 44 | self.__is_root = ('root' == self.check('whoami').strip()) |
| 45 | return self.__is_root |
csmartdalton | d7a9db6 | 2016-09-22 05:10:02 -0700 | [diff] [blame] | 46 | |
| 47 | def remount(self): |
csmartdalton | a115129 | 2016-11-09 15:37:48 -0500 | [diff] [blame] | 48 | self.__invoke('remount') |
csmartdalton | e4fd078 | 2016-11-09 08:41:23 -0800 | [diff] [blame] | 49 | |
Chris Dalton | 34d9055 | 2017-10-20 09:58:32 -0600 | [diff] [blame] | 50 | def reboot(self): |
| 51 | self.__is_root = None |
| 52 | self.shell('reboot') |
Chris Dalton | 88b448a | 2019-07-26 16:20:04 -0400 | [diff] [blame^] | 53 | self.__has_established_connection = False |
Chris Dalton | 34d9055 | 2017-10-20 09:58:32 -0600 | [diff] [blame] | 54 | |
csmartdalton | a115129 | 2016-11-09 15:37:48 -0500 | [diff] [blame] | 55 | def __echo_shell_cmd(self, cmd): |
csmartdalton | e4fd078 | 2016-11-09 08:41:23 -0800 | [diff] [blame] | 56 | escaped = [re.sub(r'([^a-zA-Z0-9])', r'\\\1', x) |
| 57 | for x in cmd.strip().splitlines()] |
csmartdalton | a115129 | 2016-11-09 15:37:48 -0500 | [diff] [blame] | 58 | self.__invoke('shell', 'echo', '$(whoami)@$(getprop ro.serialno)$', |
| 59 | " '\n>' ".join(escaped)) |
| 60 | |
| 61 | def __invoke(self, *args): |
Chris Dalton | 88b448a | 2019-07-26 16:20:04 -0400 | [diff] [blame^] | 62 | self.__establish_connection() |
csmartdalton | a115129 | 2016-11-09 15:37:48 -0500 | [diff] [blame] | 63 | subprocess.call(self.__invocation + list(args), stdout=sys.stderr) |
Chris Dalton | 88b448a | 2019-07-26 16:20:04 -0400 | [diff] [blame^] | 64 | |
| 65 | def __establish_connection(self): |
| 66 | if self.__has_established_connection: |
| 67 | return |
| 68 | self.__has_established_connection = True |
| 69 | self.__invoke('wait-for-device') |
| 70 | while True: |
| 71 | time.sleep(1) |
| 72 | if '1' == self.check('getprop sys.boot_completed').strip(): |
| 73 | break |