Chromium Code Reviews| 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 |