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 |
(...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
290 self._potential_push_size = 0 | 290 self._potential_push_size = 0 |
291 self._actual_push_size = 0 | 291 self._actual_push_size = 0 |
292 self._external_storage = '' | 292 self._external_storage = '' |
293 self._util_wrapper = '' | 293 self._util_wrapper = '' |
294 self._system_properties = system_properties.SystemProperties(self.Adb()) | 294 self._system_properties = system_properties.SystemProperties(self.Adb()) |
295 self._push_if_needed_cache = {} | 295 self._push_if_needed_cache = {} |
296 self._control_usb_charging_command = { | 296 self._control_usb_charging_command = { |
297 'command': None, | 297 'command': None, |
298 'cached': False, | 298 'cached': False, |
299 } | 299 } |
300 self._protected_file_access_method_initialized = None | |
301 self._privileged_command_runner = None | |
300 | 302 |
301 @property | 303 @property |
302 def system_properties(self): | 304 def system_properties(self): |
303 return self._system_properties | 305 return self._system_properties |
304 | 306 |
305 def _LogShell(self, cmd): | 307 def _LogShell(self, cmd): |
306 """Logs the adb shell command.""" | 308 """Logs the adb shell command.""" |
307 if self._device: | 309 if self._device: |
308 device_repr = self._device[-4:] | 310 device_repr = self._device[-4:] |
309 else: | 311 else: |
(...skipping 787 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1097 i = 0 | 1099 i = 0 |
1098 while self.FileExistsOnDevice( | 1100 while self.FileExistsOnDevice( |
1099 self.GetExternalStorage() + '/' + base_name % i): | 1101 self.GetExternalStorage() + '/' + base_name % i): |
1100 i += 1 | 1102 i += 1 |
1101 return self.GetExternalStorage() + '/' + base_name % i | 1103 return self.GetExternalStorage() + '/' + base_name % i |
1102 | 1104 |
1103 def RunShellCommandWithSU(self, command, timeout_time=20, log_result=False): | 1105 def RunShellCommandWithSU(self, command, timeout_time=20, log_result=False): |
1104 return self.RunShellCommand('su -c %s' % command, timeout_time, log_result) | 1106 return self.RunShellCommand('su -c %s' % command, timeout_time, log_result) |
1105 | 1107 |
1106 def CanAccessProtectedFileContents(self): | 1108 def CanAccessProtectedFileContents(self): |
1107 """Returns True if Get/SetProtectedFileContents would work via "su". | 1109 """Returns True if Get/SetProtectedFileContents would work via "su" or adb |
1110 shell running as root. | |
1108 | 1111 |
1109 Devices running user builds don't have adb root, but may provide "su" which | 1112 Devices running user builds don't have adb root, but may provide "su" which |
1110 can be used for accessing protected files. | 1113 can be used for accessing protected files. |
1111 """ | 1114 """ |
1112 r = self.RunShellCommandWithSU('cat /dev/null') | 1115 return (self._GetProtectedFileCommandRunner() != None) |
1113 return r == [] or r[0].strip() == '' | 1116 |
1117 def _GetProtectedFileCommandRunner(self): | |
1118 """Finds the best method to access protected files on the device. | |
1119 | |
1120 Returns: | |
1121 1. None when privileged files cannot be accessed on the device. | |
1122 2. Otherwise: A function taking a single parameter: a string with command | |
1123 line arguments. Running that function executes the command with | |
1124 the appropriate method. | |
1125 """ | |
1126 if self._protected_file_access_method_initialized: | |
1127 return self._privileged_command_runner | |
1128 | |
1129 def IsValidAuxContents(contents): | |
1130 # The leading 4 or 8-bytes of auxv vector is a_type. There are not many | |
1131 # reserved a_type values, hence byte 2 must always be '\0' for a realistic | |
1132 # auxv. See /usr/include/elf.h. | |
1133 return len(contents) > 0 and (contents[0][2] == '\0') | |
1134 | |
1135 self._privileged_command_runner = None | |
1136 self._protected_file_access_method_initialized = True | |
1137 | |
1138 # Get contents of the auxv vector for the init(8) process from a small | |
1139 # binary file that always exists on linux and is always read-protected. | |
1140 contents = self.RunShellCommand('cat /proc/1/auxv') | |
1141 if IsValidAuxContents(contents): | |
1142 # Protected data is available without SU, hence adb is running as root. | |
1143 self._privileged_command_runner = self.RunShellCommand | |
1144 return self._privileged_command_runner | |
1145 contents = self.RunShellCommandWithSU('cat /proc/1/auxv') | |
1146 if IsValidAuxContents(contents): | |
1147 # Protected data is available when asked with SU. | |
1148 self._privileged_command_runner = self.RunShellCommandWithSU | |
1149 return self._privileged_command_runner | |
bulach
2014/04/29 13:42:02
well, there's some small duplication here, we coul
pasko
2014/04/29 14:02:56
oh, that's more elegant than I thought it would be
| |
1114 | 1150 |
1115 def GetProtectedFileContents(self, filename): | 1151 def GetProtectedFileContents(self, filename): |
1116 """Gets contents from the protected file specified by |filename|. | 1152 """Gets contents from the protected file specified by |filename|. |
1117 | 1153 |
1118 This is less efficient than GetFileContents, but will work for protected | 1154 This is potentially less efficient than GetFileContents. |
1119 files and device files. | |
1120 """ | 1155 """ |
1121 # Run the script as root | 1156 command = 'cat "%s" 2> /dev/null' % filename |
1122 return self.RunShellCommandWithSU('cat "%s" 2> /dev/null' % filename) | 1157 command_runner = self._GetProtectedFileCommandRunner() |
1158 if command_runner: | |
1159 return command_runner(command) | |
1160 else: | |
1161 logging.warning('Could not access protected file: %s' % filename) | |
1162 return [] | |
1123 | 1163 |
1124 def SetProtectedFileContents(self, filename, contents): | 1164 def SetProtectedFileContents(self, filename, contents): |
1125 """Writes |contents| to the protected file specified by |filename|. | 1165 """Writes |contents| to the protected file specified by |filename|. |
1126 | 1166 |
1127 This is less efficient than SetFileContents, but will work for protected | 1167 This is less efficient than SetFileContents. |
1128 files and device files. | |
1129 """ | 1168 """ |
1130 temp_file = self._GetDeviceTempFileName(AndroidCommands._TEMP_FILE_BASE_FMT) | 1169 temp_file = self._GetDeviceTempFileName(AndroidCommands._TEMP_FILE_BASE_FMT) |
1131 temp_script = self._GetDeviceTempFileName( | 1170 temp_script = self._GetDeviceTempFileName( |
1132 AndroidCommands._TEMP_SCRIPT_FILE_BASE_FMT) | 1171 AndroidCommands._TEMP_SCRIPT_FILE_BASE_FMT) |
1133 | 1172 |
1134 # Put the contents in a temporary file | 1173 # Put the contents in a temporary file |
1135 self.SetFileContents(temp_file, contents) | 1174 self.SetFileContents(temp_file, contents) |
1136 # Create a script to copy the file contents to its final destination | 1175 # Create a script to copy the file contents to its final destination |
1137 self.SetFileContents(temp_script, 'cat %s > %s' % (temp_file, filename)) | 1176 self.SetFileContents(temp_script, 'cat %s > %s' % (temp_file, filename)) |
1138 # Run the script as root | 1177 |
1139 self.RunShellCommandWithSU('sh %s' % temp_script) | 1178 command = 'sh %s' % temp_script |
1179 command_runner = self._GetProtectedFileCommandRunner() | |
1180 if command_runner: | |
1181 return command_runner(command) | |
1182 else: | |
1183 logging.warning('Could not set contents of protected file: %s' % filename) | |
1184 | |
1140 # And remove the temporary files | 1185 # And remove the temporary files |
1141 self.RunShellCommand('rm ' + temp_file) | 1186 self.RunShellCommand('rm ' + temp_file) |
1142 self.RunShellCommand('rm ' + temp_script) | 1187 self.RunShellCommand('rm ' + temp_script) |
1143 | 1188 |
1144 def RemovePushedFiles(self): | 1189 def RemovePushedFiles(self): |
1145 """Removes all files pushed with PushIfNeeded() from the device.""" | 1190 """Removes all files pushed with PushIfNeeded() from the device.""" |
1146 for p in self._pushed_files: | 1191 for p in self._pushed_files: |
1147 self.RunShellCommand('rm -r %s' % p, timeout_time=2 * 60) | 1192 self.RunShellCommand('rm -r %s' % p, timeout_time=2 * 60) |
1148 | 1193 |
1149 def ListPathContents(self, path): | 1194 def ListPathContents(self, path): |
(...skipping 774 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1924 """ | 1969 """ |
1925 def __init__(self, output): | 1970 def __init__(self, output): |
1926 self._output = output | 1971 self._output = output |
1927 | 1972 |
1928 def write(self, data): | 1973 def write(self, data): |
1929 data = data.replace('\r\r\n', '\n') | 1974 data = data.replace('\r\r\n', '\n') |
1930 self._output.write(data) | 1975 self._output.write(data) |
1931 | 1976 |
1932 def flush(self): | 1977 def flush(self): |
1933 self._output.flush() | 1978 self._output.flush() |
OLD | NEW |