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 6from __future__ import print_function 7import re 8import time 9import subprocess 10import sys 11 12class Adb: 13 def __init__(self, device_serial=None, adb_binary=None, echo=False): 14 self.__invocation = [adb_binary] 15 if device_serial: 16 self.__invocation.extend(['-s', device_serial]) 17 self.__echo = echo 18 self.__is_root = None 19 self.__has_established_connection = False 20 21 def shell(self, cmd): 22 if self.__echo: 23 self.__echo_shell_cmd(cmd) 24 self.__invoke('shell', cmd) 25 26 def check(self, cmd): 27 if self.__echo: 28 self.__echo_shell_cmd(cmd) 29 self.__establish_connection() 30 result = subprocess.check_output(self.__invocation + ['shell', cmd], encoding='utf-8') 31 if self.__echo: 32 print(result, file=sys.stderr) 33 return result 34 35 def root(self): 36 if not self.is_root(): 37 self.__invoke('root') 38 self.__has_established_connection = False 39 self.__is_root = None 40 return self.is_root() 41 42 def is_root(self): 43 if self.__is_root is None: 44 self.__is_root = ('root' == self.check('whoami').strip()) 45 return self.__is_root 46 47 def remount(self): 48 self.__invoke('remount') 49 50 def reboot(self): 51 self.__is_root = None 52 self.shell('reboot') 53 self.__has_established_connection = False 54 55 def __echo_shell_cmd(self, cmd): 56 escaped = [re.sub(r'([^a-zA-Z0-9])', r'\\\1', x) 57 for x in cmd.strip().splitlines()] 58 self.__invoke('shell', 'echo', '$(whoami)@$(getprop ro.serialno)$', 59 " '\n>' ".join(escaped)) 60 61 def __invoke(self, *args): 62 self.__establish_connection() 63 subprocess.call(self.__invocation + list(args), stdout=sys.stderr) 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 74