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 json | 14 import json |
15 import logging | 15 import logging |
16 import os | 16 import os |
17 import random | |
17 import re | 18 import re |
18 import shlex | 19 import shlex |
19 import signal | 20 import signal |
20 import subprocess | 21 import subprocess |
21 import sys | 22 import sys |
22 import tempfile | 23 import tempfile |
23 import time | 24 import time |
24 | 25 |
25 import cmd_helper | 26 import cmd_helper |
26 import constants | 27 import constants |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
75 CONTROL_USB_CHARGING_COMMANDS = [ | 76 CONTROL_USB_CHARGING_COMMANDS = [ |
76 { | 77 { |
77 # Nexus 4 | 78 # Nexus 4 |
78 'witness_file': '/sys/module/pm8921_charger/parameters/disabled', | 79 'witness_file': '/sys/module/pm8921_charger/parameters/disabled', |
79 'enable_command': 'echo 0 > /sys/module/pm8921_charger/parameters/disabled', | 80 'enable_command': 'echo 0 > /sys/module/pm8921_charger/parameters/disabled', |
80 'disable_command': | 81 'disable_command': |
81 'echo 1 > /sys/module/pm8921_charger/parameters/disabled', | 82 'echo 1 > /sys/module/pm8921_charger/parameters/disabled', |
82 }, | 83 }, |
83 ] | 84 ] |
84 | 85 |
86 class DeviceTempFile(object): | |
87 def __init__(self, android_commands, prefix='temp_file', suffix=''): | |
88 """Find an unused temporary file path in the devices external directory. | |
89 | |
90 When this object is closed, the file will be deleted on the device. | |
91 """ | |
92 self.android_commands = android_commands | |
93 while True: | |
94 # TODO(cjhopman): This could actually return the same file in multiple | |
95 # calls if the caller doesn't write to the files immediately. | |
96 i = random.randint(0, 1000000) | |
97 self.name = '%s/%s-%010d%s' % ( | |
craigdh
2014/05/09 20:18:25
optional nit: it might not hurt to throw time().ti
cjhopman
2014/05/09 20:51:03
Done. Rounded to an int so that we don't put a '.'
| |
98 android_commands.GetExternalStorage(), prefix, i, suffix) | |
99 if not android_commands.FileExistsOnDevice(self.name): | |
100 break | |
101 | |
102 def __enter__(self): | |
103 return self | |
104 | |
105 def __exit__(self, type, value, traceback): | |
106 self.close() | |
107 | |
108 def close(self): | |
109 self.android_commands.RunShellCommand('rm ' + self.name) | |
110 | |
111 | |
85 def GetAVDs(): | 112 def GetAVDs(): |
86 """Returns a list of AVDs.""" | 113 """Returns a list of AVDs.""" |
87 re_avd = re.compile('^[ ]+Name: ([a-zA-Z0-9_:.-]+)', re.MULTILINE) | 114 re_avd = re.compile('^[ ]+Name: ([a-zA-Z0-9_:.-]+)', re.MULTILINE) |
88 avds = re_avd.findall(cmd_helper.GetCmdOutput(['android', 'list', 'avd'])) | 115 avds = re_avd.findall(cmd_helper.GetCmdOutput(['android', 'list', 'avd'])) |
89 return avds | 116 return avds |
90 | 117 |
91 def ResetBadDevices(): | 118 def ResetBadDevices(): |
92 """Removes the blacklist that keeps track of bad devices for a current | 119 """Removes the blacklist that keeps track of bad devices for a current |
93 build. | 120 build. |
94 """ | 121 """ |
(...skipping 991 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1086 return self.RunShellCommand('cat "%s" 2>/dev/null' % filename, | 1113 return self.RunShellCommand('cat "%s" 2>/dev/null' % filename, |
1087 log_result=log_result) | 1114 log_result=log_result) |
1088 | 1115 |
1089 def SetFileContents(self, filename, contents): | 1116 def SetFileContents(self, filename, contents): |
1090 """Writes |contents| to the file specified by |filename|.""" | 1117 """Writes |contents| to the file specified by |filename|.""" |
1091 with tempfile.NamedTemporaryFile() as f: | 1118 with tempfile.NamedTemporaryFile() as f: |
1092 f.write(contents) | 1119 f.write(contents) |
1093 f.flush() | 1120 f.flush() |
1094 self._adb.Push(f.name, filename) | 1121 self._adb.Push(f.name, filename) |
1095 | 1122 |
1096 _TEMP_FILE_BASE_FMT = 'temp_file_%d' | |
1097 _TEMP_SCRIPT_FILE_BASE_FMT = 'temp_script_file_%d.sh' | |
1098 | |
1099 def _GetDeviceTempFileName(self, base_name): | |
1100 i = 0 | |
1101 while self.FileExistsOnDevice( | |
1102 self.GetExternalStorage() + '/' + base_name % i): | |
1103 i += 1 | |
1104 return self.GetExternalStorage() + '/' + base_name % i | |
1105 | |
1106 def RunShellCommandWithSU(self, command, timeout_time=20, log_result=False): | 1123 def RunShellCommandWithSU(self, command, timeout_time=20, log_result=False): |
1107 return self.RunShellCommand('su -c %s' % command, timeout_time, log_result) | 1124 return self.RunShellCommand('su -c %s' % command, timeout_time, log_result) |
1108 | 1125 |
1109 def CanAccessProtectedFileContents(self): | 1126 def CanAccessProtectedFileContents(self): |
1110 """Returns True if Get/SetProtectedFileContents would work via "su" or adb | 1127 """Returns True if Get/SetProtectedFileContents would work via "su" or adb |
1111 shell running as root. | 1128 shell running as root. |
1112 | 1129 |
1113 Devices running user builds don't have adb root, but may provide "su" which | 1130 Devices running user builds don't have adb root, but may provide "su" which |
1114 can be used for accessing protected files. | 1131 can be used for accessing protected files. |
1115 """ | 1132 """ |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1153 return command_runner(command) | 1170 return command_runner(command) |
1154 else: | 1171 else: |
1155 logging.warning('Could not access protected file: %s' % filename) | 1172 logging.warning('Could not access protected file: %s' % filename) |
1156 return [] | 1173 return [] |
1157 | 1174 |
1158 def SetProtectedFileContents(self, filename, contents): | 1175 def SetProtectedFileContents(self, filename, contents): |
1159 """Writes |contents| to the protected file specified by |filename|. | 1176 """Writes |contents| to the protected file specified by |filename|. |
1160 | 1177 |
1161 This is less efficient than SetFileContents. | 1178 This is less efficient than SetFileContents. |
1162 """ | 1179 """ |
1163 temp_file = self._GetDeviceTempFileName(AndroidCommands._TEMP_FILE_BASE_FMT) | 1180 with DeviceTempFile(self), DeviceTempFile(self, suffix=".sh") as ( |
1164 temp_script = self._GetDeviceTempFileName( | 1181 temp_file, temp_script): |
1165 AndroidCommands._TEMP_SCRIPT_FILE_BASE_FMT) | 1182 # Put the contents in a temporary file |
1183 self.SetFileContents(temp_file.name, contents) | |
1184 # Create a script to copy the file contents to its final destination | |
1185 self.SetFileContents(temp_script.name, | |
1186 'cat %s > %s' % (temp_file.name, filename)) | |
1166 | 1187 |
1167 # Put the contents in a temporary file | 1188 command = 'sh %s' % temp_script.name |
1168 self.SetFileContents(temp_file, contents) | 1189 command_runner = self._GetProtectedFileCommandRunner() |
1169 # Create a script to copy the file contents to its final destination | 1190 if command_runner: |
1170 self.SetFileContents(temp_script, 'cat %s > %s' % (temp_file, filename)) | 1191 return command_runner(command) |
1192 else: | |
1193 logging.warning( | |
1194 'Could not set contents of protected file: %s' % filename) | |
1171 | 1195 |
1172 command = 'sh %s' % temp_script | |
1173 command_runner = self._GetProtectedFileCommandRunner() | |
1174 if command_runner: | |
1175 return command_runner(command) | |
1176 else: | |
1177 logging.warning('Could not set contents of protected file: %s' % filename) | |
1178 | |
1179 # And remove the temporary files | |
1180 self.RunShellCommand('rm ' + temp_file) | |
1181 self.RunShellCommand('rm ' + temp_script) | |
1182 | 1196 |
1183 def RemovePushedFiles(self): | 1197 def RemovePushedFiles(self): |
1184 """Removes all files pushed with PushIfNeeded() from the device.""" | 1198 """Removes all files pushed with PushIfNeeded() from the device.""" |
1185 for p in self._pushed_files: | 1199 for p in self._pushed_files: |
1186 self.RunShellCommand('rm -r %s' % p, timeout_time=2 * 60) | 1200 self.RunShellCommand('rm -r %s' % p, timeout_time=2 * 60) |
1187 | 1201 |
1188 def ListPathContents(self, path): | 1202 def ListPathContents(self, path): |
1189 """Lists files in all subdirectories of |path|. | 1203 """Lists files in all subdirectories of |path|. |
1190 | 1204 |
1191 Args: | 1205 Args: |
(...skipping 685 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1877 | 1891 |
1878 Uses a shell script running on the target to copy new and changed files the | 1892 Uses a shell script running on the target to copy new and changed files the |
1879 source directory to the destination directory and remove added files. This | 1893 source directory to the destination directory and remove added files. This |
1880 is in some cases much faster than cp -r. | 1894 is in some cases much faster than cp -r. |
1881 | 1895 |
1882 Args: | 1896 Args: |
1883 source: absolute path of source directory | 1897 source: absolute path of source directory |
1884 dest: absolute path of destination directory | 1898 dest: absolute path of destination directory |
1885 """ | 1899 """ |
1886 logging.info('In EfficientDeviceDirectoryCopy %s %s', source, dest) | 1900 logging.info('In EfficientDeviceDirectoryCopy %s %s', source, dest) |
1887 temp_script_file = self._GetDeviceTempFileName( | 1901 with DeviceTempFile(self, suffix=".sh") as temp_script_file: |
1888 AndroidCommands._TEMP_SCRIPT_FILE_BASE_FMT) | 1902 host_script_path = os.path.join(constants.DIR_SOURCE_ROOT, |
1889 host_script_path = os.path.join(constants.DIR_SOURCE_ROOT, | 1903 'build', |
1890 'build', | 1904 'android', |
1891 'android', | 1905 'pylib', |
1892 'pylib', | 1906 'efficient_android_directory_copy.sh') |
1893 'efficient_android_directory_copy.sh') | 1907 self._adb.Push(host_script_path, temp_script_file.name) |
1894 self._adb.Push(host_script_path, temp_script_file) | 1908 self.EnableAdbRoot |
1895 self.EnableAdbRoot | 1909 out = self.RunShellCommand( |
1896 out = self.RunShellCommand('sh %s %s %s' % (temp_script_file, source, dest), | 1910 'sh %s %s %s' % (temp_script_file.name, source, dest), |
1897 timeout_time=120) | 1911 timeout_time=120) |
1898 if self._device: | 1912 if self._device: |
1899 device_repr = self._device[-4:] | 1913 device_repr = self._device[-4:] |
1900 else: | 1914 else: |
1901 device_repr = '????' | 1915 device_repr = '????' |
1902 for line in out: | 1916 for line in out: |
1903 logging.info('[%s]> %s', device_repr, line) | 1917 logging.info('[%s]> %s', device_repr, line) |
1904 self.RunShellCommand('rm %s' % temp_script_file) | |
1905 | 1918 |
1906 def _GetControlUsbChargingCommand(self): | 1919 def _GetControlUsbChargingCommand(self): |
1907 if self._control_usb_charging_command['cached']: | 1920 if self._control_usb_charging_command['cached']: |
1908 return self._control_usb_charging_command['command'] | 1921 return self._control_usb_charging_command['command'] |
1909 self._control_usb_charging_command['cached'] = True | 1922 self._control_usb_charging_command['cached'] = True |
1910 for command in CONTROL_USB_CHARGING_COMMANDS: | 1923 for command in CONTROL_USB_CHARGING_COMMANDS: |
1911 # Assert command is valid. | 1924 # Assert command is valid. |
1912 assert 'disable_command' in command | 1925 assert 'disable_command' in command |
1913 assert 'enable_command' in command | 1926 assert 'enable_command' in command |
1914 assert 'witness_file' in command | 1927 assert 'witness_file' in command |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1963 """ | 1976 """ |
1964 def __init__(self, output): | 1977 def __init__(self, output): |
1965 self._output = output | 1978 self._output = output |
1966 | 1979 |
1967 def write(self, data): | 1980 def write(self, data): |
1968 data = data.replace('\r\r\n', '\n') | 1981 data = data.replace('\r\r\n', '\n') |
1969 self._output.write(data) | 1982 self._output.write(data) |
1970 | 1983 |
1971 def flush(self): | 1984 def flush(self): |
1972 self._output.flush() | 1985 self._output.flush() |
OLD | NEW |