OLD | NEW |
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 """Provides an interface to communicate with the device via the adb command. | 5 """Provides an interface to communicate with the device via the adb command. |
6 | 6 |
7 Assumes adb binary is currently on system path. | 7 Assumes adb binary is currently on system path. |
8 """ | 8 """ |
9 # pylint: disable-all | 9 # pylint: disable-all |
10 | 10 |
11 import collections | 11 import collections |
12 import datetime | 12 import datetime |
13 import inspect | 13 import inspect |
14 import logging | 14 import logging |
15 import os | 15 import os |
| 16 import random |
16 import re | 17 import re |
17 import shlex | 18 import shlex |
18 import signal | 19 import signal |
19 import subprocess | 20 import subprocess |
20 import sys | 21 import sys |
21 import tempfile | 22 import tempfile |
22 import time | 23 import time |
23 | 24 |
24 import cmd_helper | 25 import cmd_helper |
25 import constants | 26 import constants |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
71 CONTROL_USB_CHARGING_COMMANDS = [ | 72 CONTROL_USB_CHARGING_COMMANDS = [ |
72 { | 73 { |
73 # Nexus 4 | 74 # Nexus 4 |
74 'witness_file': '/sys/module/pm8921_charger/parameters/disabled', | 75 'witness_file': '/sys/module/pm8921_charger/parameters/disabled', |
75 'enable_command': 'echo 0 > /sys/module/pm8921_charger/parameters/disabled', | 76 'enable_command': 'echo 0 > /sys/module/pm8921_charger/parameters/disabled', |
76 'disable_command': | 77 'disable_command': |
77 'echo 1 > /sys/module/pm8921_charger/parameters/disabled', | 78 'echo 1 > /sys/module/pm8921_charger/parameters/disabled', |
78 }, | 79 }, |
79 ] | 80 ] |
80 | 81 |
| 82 class DeviceTempFile(object): |
| 83 def __init__(self, android_commands, prefix='temp_file', suffix=''): |
| 84 """Find an unused temporary file path in the devices external directory. |
| 85 |
| 86 When this object is closed, the file will be deleted on the device. |
| 87 """ |
| 88 self.android_commands = android_commands |
| 89 while True: |
| 90 # TODO(cjhopman): This could actually return the same file in multiple |
| 91 # calls if the caller doesn't write to the files immediately. This is |
| 92 # expected to never happen. |
| 93 i = random.randint(0, 1000000) |
| 94 self.name = '%s/%s-%d-%010d%s' % ( |
| 95 android_commands.GetExternalStorage(), |
| 96 prefix, int(time.time()), i, suffix) |
| 97 if not android_commands.FileExistsOnDevice(self.name): |
| 98 break |
| 99 |
| 100 def __enter__(self): |
| 101 return self |
| 102 |
| 103 def __exit__(self, type, value, traceback): |
| 104 self.close() |
| 105 |
| 106 def close(self): |
| 107 self.android_commands.RunShellCommand('rm ' + self.name) |
| 108 |
| 109 |
81 def GetAVDs(): | 110 def GetAVDs(): |
82 """Returns a list of AVDs.""" | 111 """Returns a list of AVDs.""" |
83 re_avd = re.compile('^[ ]+Name: ([a-zA-Z0-9_:.-]+)', re.MULTILINE) | 112 re_avd = re.compile('^[ ]+Name: ([a-zA-Z0-9_:.-]+)', re.MULTILINE) |
84 avds = re_avd.findall(cmd_helper.GetCmdOutput(['android', 'list', 'avd'])) | 113 avds = re_avd.findall(cmd_helper.GetCmdOutput(['android', 'list', 'avd'])) |
85 return avds | 114 return avds |
86 | 115 |
87 def ResetBadDevices(): | 116 def ResetBadDevices(): |
88 """Removes the blacklist that keeps track of bad devices for a current | 117 """Removes the blacklist that keeps track of bad devices for a current |
89 build. | 118 build. |
90 """ | 119 """ |
(...skipping 1027 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1118 return self.RunShellCommand('cat "%s" 2>/dev/null' % filename, | 1147 return self.RunShellCommand('cat "%s" 2>/dev/null' % filename, |
1119 log_result=log_result) | 1148 log_result=log_result) |
1120 | 1149 |
1121 def SetFileContents(self, filename, contents): | 1150 def SetFileContents(self, filename, contents): |
1122 """Writes |contents| to the file specified by |filename|.""" | 1151 """Writes |contents| to the file specified by |filename|.""" |
1123 with tempfile.NamedTemporaryFile() as f: | 1152 with tempfile.NamedTemporaryFile() as f: |
1124 f.write(contents) | 1153 f.write(contents) |
1125 f.flush() | 1154 f.flush() |
1126 self._adb.Push(f.name, filename) | 1155 self._adb.Push(f.name, filename) |
1127 | 1156 |
1128 _TEMP_FILE_BASE_FMT = 'temp_file_%d' | |
1129 _TEMP_SCRIPT_FILE_BASE_FMT = 'temp_script_file_%d.sh' | |
1130 | |
1131 def _GetDeviceTempFileName(self, base_name): | |
1132 i = 0 | |
1133 while self.FileExistsOnDevice( | |
1134 self.GetExternalStorage() + '/' + base_name % i): | |
1135 i += 1 | |
1136 return self.GetExternalStorage() + '/' + base_name % i | |
1137 | |
1138 def RunShellCommandWithSU(self, command, timeout_time=20, log_result=False): | 1157 def RunShellCommandWithSU(self, command, timeout_time=20, log_result=False): |
1139 return self.RunShellCommand('su -c %s' % command, timeout_time, log_result) | 1158 return self.RunShellCommand('su -c %s' % command, timeout_time, log_result) |
1140 | 1159 |
1141 def CanAccessProtectedFileContents(self): | 1160 def CanAccessProtectedFileContents(self): |
1142 """Returns True if Get/SetProtectedFileContents would work via "su" or adb | 1161 """Returns True if Get/SetProtectedFileContents would work via "su" or adb |
1143 shell running as root. | 1162 shell running as root. |
1144 | 1163 |
1145 Devices running user builds don't have adb root, but may provide "su" which | 1164 Devices running user builds don't have adb root, but may provide "su" which |
1146 can be used for accessing protected files. | 1165 can be used for accessing protected files. |
1147 """ | 1166 """ |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1185 return command_runner(command) | 1204 return command_runner(command) |
1186 else: | 1205 else: |
1187 logging.warning('Could not access protected file: %s' % filename) | 1206 logging.warning('Could not access protected file: %s' % filename) |
1188 return [] | 1207 return [] |
1189 | 1208 |
1190 def SetProtectedFileContents(self, filename, contents): | 1209 def SetProtectedFileContents(self, filename, contents): |
1191 """Writes |contents| to the protected file specified by |filename|. | 1210 """Writes |contents| to the protected file specified by |filename|. |
1192 | 1211 |
1193 This is less efficient than SetFileContents. | 1212 This is less efficient than SetFileContents. |
1194 """ | 1213 """ |
1195 temp_file = self._GetDeviceTempFileName(AndroidCommands._TEMP_FILE_BASE_FMT) | 1214 with DeviceTempFile(self) as temp_file: |
1196 temp_script = self._GetDeviceTempFileName( | 1215 with DeviceTempFile(self, suffix=".sh") as temp_script: |
1197 AndroidCommands._TEMP_SCRIPT_FILE_BASE_FMT) | 1216 # Put the contents in a temporary file |
| 1217 self.SetFileContents(temp_file.name, contents) |
| 1218 # Create a script to copy the file contents to its final destination |
| 1219 self.SetFileContents(temp_script.name, |
| 1220 'cat %s > %s' % (temp_file.name, filename)) |
1198 | 1221 |
1199 try: | 1222 command = 'sh %s' % temp_script.name |
1200 # Put the contents in a temporary file | 1223 command_runner = self._GetProtectedFileCommandRunner() |
1201 self.SetFileContents(temp_file, contents) | 1224 if command_runner: |
1202 # Create a script to copy the file contents to its final destination | 1225 return command_runner(command) |
1203 self.SetFileContents(temp_script, 'cat %s > %s' % (temp_file, filename)) | 1226 else: |
| 1227 logging.warning( |
| 1228 'Could not set contents of protected file: %s' % filename) |
1204 | 1229 |
1205 command = 'sh %s' % temp_script | |
1206 command_runner = self._GetProtectedFileCommandRunner() | |
1207 if command_runner: | |
1208 return command_runner(command) | |
1209 else: | |
1210 logging.warning( | |
1211 'Could not set contents of protected file: %s' % filename) | |
1212 finally: | |
1213 # And remove the temporary files | |
1214 self.RunShellCommand('rm ' + temp_file) | |
1215 self.RunShellCommand('rm ' + temp_script) | |
1216 | 1230 |
1217 def RemovePushedFiles(self): | 1231 def RemovePushedFiles(self): |
1218 """Removes all files pushed with PushIfNeeded() from the device.""" | 1232 """Removes all files pushed with PushIfNeeded() from the device.""" |
1219 for p in self._pushed_files: | 1233 for p in self._pushed_files: |
1220 self.RunShellCommand('rm -r %s' % p, timeout_time=2 * 60) | 1234 self.RunShellCommand('rm -r %s' % p, timeout_time=2 * 60) |
1221 | 1235 |
1222 def ListPathContents(self, path): | 1236 def ListPathContents(self, path): |
1223 """Lists files in all subdirectories of |path|. | 1237 """Lists files in all subdirectories of |path|. |
1224 | 1238 |
1225 Args: | 1239 Args: |
(...skipping 644 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1870 | 1884 |
1871 Uses a shell script running on the target to copy new and changed files the | 1885 Uses a shell script running on the target to copy new and changed files the |
1872 source directory to the destination directory and remove added files. This | 1886 source directory to the destination directory and remove added files. This |
1873 is in some cases much faster than cp -r. | 1887 is in some cases much faster than cp -r. |
1874 | 1888 |
1875 Args: | 1889 Args: |
1876 source: absolute path of source directory | 1890 source: absolute path of source directory |
1877 dest: absolute path of destination directory | 1891 dest: absolute path of destination directory |
1878 """ | 1892 """ |
1879 logging.info('In EfficientDeviceDirectoryCopy %s %s', source, dest) | 1893 logging.info('In EfficientDeviceDirectoryCopy %s %s', source, dest) |
1880 temp_script_file = self._GetDeviceTempFileName( | 1894 with DeviceTempFile(self, suffix=".sh") as temp_script_file: |
1881 AndroidCommands._TEMP_SCRIPT_FILE_BASE_FMT) | 1895 host_script_path = os.path.join(constants.DIR_SOURCE_ROOT, |
1882 host_script_path = os.path.join(constants.DIR_SOURCE_ROOT, | 1896 'build', |
1883 'build', | 1897 'android', |
1884 'android', | 1898 'pylib', |
1885 'pylib', | 1899 'efficient_android_directory_copy.sh') |
1886 'efficient_android_directory_copy.sh') | 1900 self._adb.Push(host_script_path, temp_script_file.name) |
1887 try: | 1901 self.EnableAdbRoot |
1888 self._adb.Push(host_script_path, temp_script_file) | 1902 out = self.RunShellCommand( |
1889 self.EnableAdbRoot() | 1903 'sh %s %s %s' % (temp_script_file.name, source, dest), |
1890 out = self.RunShellCommand('sh %s %s %s' % (temp_script_file, | 1904 timeout_time=120) |
1891 source, | |
1892 dest), | |
1893 timeout_time=120) | |
1894 if self._device: | 1905 if self._device: |
1895 device_repr = self._device[-4:] | 1906 device_repr = self._device[-4:] |
1896 else: | 1907 else: |
1897 device_repr = '????' | 1908 device_repr = '????' |
1898 for line in out: | 1909 for line in out: |
1899 logging.info('[%s]> %s', device_repr, line) | 1910 logging.info('[%s]> %s', device_repr, line) |
1900 finally: | |
1901 self.RunShellCommand('rm %s' % temp_script_file) | |
1902 | 1911 |
1903 def _GetControlUsbChargingCommand(self): | 1912 def _GetControlUsbChargingCommand(self): |
1904 if self._control_usb_charging_command['cached']: | 1913 if self._control_usb_charging_command['cached']: |
1905 return self._control_usb_charging_command['command'] | 1914 return self._control_usb_charging_command['command'] |
1906 self._control_usb_charging_command['cached'] = True | 1915 self._control_usb_charging_command['cached'] = True |
1907 for command in CONTROL_USB_CHARGING_COMMANDS: | 1916 for command in CONTROL_USB_CHARGING_COMMANDS: |
1908 # Assert command is valid. | 1917 # Assert command is valid. |
1909 assert 'disable_command' in command | 1918 assert 'disable_command' in command |
1910 assert 'enable_command' in command | 1919 assert 'enable_command' in command |
1911 assert 'witness_file' in command | 1920 assert 'witness_file' in command |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1960 """ | 1969 """ |
1961 def __init__(self, output): | 1970 def __init__(self, output): |
1962 self._output = output | 1971 self._output = output |
1963 | 1972 |
1964 def write(self, data): | 1973 def write(self, data): |
1965 data = data.replace('\r\r\n', '\n') | 1974 data = data.replace('\r\r\n', '\n') |
1966 self._output.write(data) | 1975 self._output.write(data) |
1967 | 1976 |
1968 def flush(self): | 1977 def flush(self): |
1969 self._output.flush() | 1978 self._output.flush() |
OLD | NEW |