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 = None | |
300 | 301 |
301 @property | 302 @property |
302 def system_properties(self): | 303 def system_properties(self): |
303 return self._system_properties | 304 return self._system_properties |
304 | 305 |
305 def _LogShell(self, cmd): | 306 def _LogShell(self, cmd): |
306 """Logs the adb shell command.""" | 307 """Logs the adb shell command.""" |
307 if self._device: | 308 if self._device: |
308 device_repr = self._device[-4:] | 309 device_repr = self._device[-4:] |
309 else: | 310 else: |
(...skipping 786 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1096 def _GetDeviceTempFileName(self, base_name): | 1097 def _GetDeviceTempFileName(self, base_name): |
1097 i = 0 | 1098 i = 0 |
1098 while self.FileExistsOnDevice( | 1099 while self.FileExistsOnDevice( |
1099 self.GetExternalStorage() + '/' + base_name % i): | 1100 self.GetExternalStorage() + '/' + base_name % i): |
1100 i += 1 | 1101 i += 1 |
1101 return self.GetExternalStorage() + '/' + base_name % i | 1102 return self.GetExternalStorage() + '/' + base_name % i |
1102 | 1103 |
1103 def RunShellCommandWithSU(self, command, timeout_time=20, log_result=False): | 1104 def RunShellCommandWithSU(self, command, timeout_time=20, log_result=False): |
1104 return self.RunShellCommand('su -c %s' % command, timeout_time, log_result) | 1105 return self.RunShellCommand('su -c %s' % command, timeout_time, log_result) |
1105 | 1106 |
1107 ACCESS_METHOD_NO_ACCESS = "no access" | |
Sami
2014/04/28 12:55:49
nit: Start with underscore since these probably do
jbudorick
2014/04/28 14:22:52
+1 for using numeric constants.
pasko
2014/04/29 09:42:32
Renaming: Done. Most votes are for numeric constan
pasko
2014/04/29 09:42:32
Done.
| |
1108 ACCESS_METHOD_AS_ROOT = "as root" | |
1109 ACCESS_METHOD_WITH_SU = "with su" | |
bulach
2014/04/28 12:21:48
nit: use single quotes
pasko
2014/04/29 09:42:32
thanks, changed to numeric constants
| |
1110 | |
1106 def CanAccessProtectedFileContents(self): | 1111 def CanAccessProtectedFileContents(self): |
1107 """Returns True if Get/SetProtectedFileContents would work via "su". | 1112 """Returns True if Get/SetProtectedFileContents would work via "su" or adb |
1113 shell running as root. | |
1108 | 1114 |
1109 Devices running user builds don't have adb root, but may provide "su" which | 1115 Devices running user builds don't have adb root, but may provide "su" which |
1110 can be used for accessing protected files. | 1116 can be used for accessing protected files. |
1111 """ | 1117 """ |
1112 r = self.RunShellCommandWithSU('cat /dev/null') | 1118 return (self._ProtectedFileAccessMethod() != |
1113 return r == [] or r[0].strip() == '' | 1119 AndroidCommands.ACCESS_METHOD_NO_ACCESS) |
1120 | |
1121 def _ProtectedFileAccessMethod(self): | |
1122 """Tests for the best method to access protected files on the device. | |
1123 | |
1124 Returns: | |
1125 ACCESS_METHOD_NO_ACCESS: if protected files cannot be accessed | |
1126 ACCESS_METHOD_AS_ROOT: if the adb shell has root privileges | |
1127 ACCESS_METHOD_WITH_SU: if the 'su' command properly works on the device | |
1128 """ | |
1129 if self._protected_file_access_method is not None: | |
bulach
2014/04/28 12:21:48
nit: s/is not None//
pasko
2014/04/29 09:42:32
I changed this to numeric constants, so to disting
| |
1130 return self._protected_file_access_method | |
1131 | |
1132 def AuxContentsLookReal(contents): | |
bulach
2014/04/28 12:21:48
nit: how about "_IsValidContents" ?
jbudorick
2014/04/28 14:22:52
Why check the output rather than the return code?
pasko
2014/04/29 09:42:32
I changed this to IsValidAuxContents(). Since the
pasko
2014/04/29 09:42:32
This is mainly because RunShellCommand() and RunSh
| |
1133 # The leading 4 or 8-bytes of auxv vector is a_type. There are not many | |
1134 # reserved a_type values, hence byte 2 must always be '\0' for a realistic | |
1135 # auxv. See /usr/include/elf.h. | |
1136 return len(contents) > 0 and (contents[0][2] == '\0') | |
1137 | |
1138 self._protected_file_access_method = AndroidCommands.ACCESS_METHOD_NO_ACCESS | |
1139 | |
1140 # Get contents of the auxv vector for the init(8) process from a small | |
1141 # binary file that always exists on a linux and is always read-protected. | |
1142 contents = self.RunShellCommand('cat /proc/1/auxv') | |
Sami
2014/04/28 12:55:49
Neat trick :)
pasko
2014/04/29 09:42:32
thnx)
| |
1143 if AuxContentsLookReal(contents): | |
1144 # Protected data is available without SU, hence adb is running as root. | |
1145 self._protected_file_access_method = AndroidCommands.ACCESS_METHOD_AS_ROOT | |
jbudorick
2014/04/28 14:22:52
FWIW, I've been toying with doing the as_root chec
pasko
2014/04/29 09:42:32
I did not know about this property :)
| |
1146 else: | |
1147 contents = self.RunShellCommandWithSU('cat /proc/1/auxv') | |
1148 if AuxContentsLookReal(contents): | |
1149 # Protected data is available when asked with SU. | |
1150 self._protected_file_access_method = ( | |
1151 AndroidCommands.ACCESS_METHOD_WITH_SU) | |
1152 return self._protected_file_access_method | |
Sami
2014/04/28 12:55:49
Set access method to ACCESS_METHOD_NO_ACCESS here?
pasko
2014/04/29 09:42:32
I've set it above. If I wanted to move it here fro
| |
1114 | 1153 |
1115 def GetProtectedFileContents(self, filename): | 1154 def GetProtectedFileContents(self, filename): |
1116 """Gets contents from the protected file specified by |filename|. | 1155 """Gets contents from the protected file specified by |filename|. |
1117 | 1156 |
1118 This is less efficient than GetFileContents, but will work for protected | 1157 This is potentially less efficient than GetFileContents. |
1119 files and device files. | |
1120 """ | 1158 """ |
1121 # Run the script as root | 1159 command = 'cat "%s" 2> /dev/null' % filename |
1122 return self.RunShellCommandWithSU('cat "%s" 2> /dev/null' % filename) | 1160 access_method = self._ProtectedFileAccessMethod() |
1161 if access_method == AndroidCommands.ACCESS_METHOD_WITH_SU: | |
1162 return self.RunShellCommandWithSU(command) | |
1163 elif access_method == AndroidCommands.ACCESS_METHOD_AS_ROOT: | |
1164 return self.RunShellCommand(command) | |
1165 else: | |
1166 logging.warning('Could not access protected file: %s' % filename) | |
1167 return [] | |
bulach
2014/04/28 12:21:48
now, if we're going to fix this once and for all :
jbudorick
2014/04/28 14:22:52
I'm ok with this idea in general. I think implemen
pasko
2014/04/29 09:42:32
I'm +1 to jbudorick@ here: it will likely break in
| |
1123 | 1168 |
1124 def SetProtectedFileContents(self, filename, contents): | 1169 def SetProtectedFileContents(self, filename, contents): |
1125 """Writes |contents| to the protected file specified by |filename|. | 1170 """Writes |contents| to the protected file specified by |filename|. |
1126 | 1171 |
1127 This is less efficient than SetFileContents, but will work for protected | 1172 This is less efficient than SetFileContents. |
1128 files and device files. | |
1129 """ | 1173 """ |
1130 temp_file = self._GetDeviceTempFileName(AndroidCommands._TEMP_FILE_BASE_FMT) | 1174 temp_file = self._GetDeviceTempFileName(AndroidCommands._TEMP_FILE_BASE_FMT) |
1131 temp_script = self._GetDeviceTempFileName( | 1175 temp_script = self._GetDeviceTempFileName( |
1132 AndroidCommands._TEMP_SCRIPT_FILE_BASE_FMT) | 1176 AndroidCommands._TEMP_SCRIPT_FILE_BASE_FMT) |
1133 | 1177 |
1134 # Put the contents in a temporary file | 1178 # Put the contents in a temporary file |
1135 self.SetFileContents(temp_file, contents) | 1179 self.SetFileContents(temp_file, contents) |
1136 # Create a script to copy the file contents to its final destination | 1180 # Create a script to copy the file contents to its final destination |
1137 self.SetFileContents(temp_script, 'cat %s > %s' % (temp_file, filename)) | 1181 self.SetFileContents(temp_script, 'cat %s > %s' % (temp_file, filename)) |
1138 # Run the script as root | 1182 |
1139 self.RunShellCommandWithSU('sh %s' % temp_script) | 1183 command = 'sh %s' % temp_script |
1184 access_method = self._ProtectedFileAccessMethod() | |
Sami
2014/04/28 12:55:49
This could be a little cleaner if access_method wa
pasko
2014/04/29 09:42:32
Do you suggest to check for None and call otherwis
| |
1185 if access_method == AndroidCommands.ACCESS_METHOD_WITH_SU: | |
1186 return self.RunShellCommandWithSU(command) | |
1187 elif access_method == AndroidCommands.ACCESS_METHOD_AS_ROOT: | |
1188 return self.RunShellCommand(command) | |
1189 else: | |
1190 logging.warning('Could not set contents of protected file: %s' % filename) | |
bulach
2014/04/28 12:21:48
ditto.
| |
1191 | |
1140 # And remove the temporary files | 1192 # And remove the temporary files |
1141 self.RunShellCommand('rm ' + temp_file) | 1193 self.RunShellCommand('rm ' + temp_file) |
1142 self.RunShellCommand('rm ' + temp_script) | 1194 self.RunShellCommand('rm ' + temp_script) |
1143 | 1195 |
1144 def RemovePushedFiles(self): | 1196 def RemovePushedFiles(self): |
1145 """Removes all files pushed with PushIfNeeded() from the device.""" | 1197 """Removes all files pushed with PushIfNeeded() from the device.""" |
1146 for p in self._pushed_files: | 1198 for p in self._pushed_files: |
1147 self.RunShellCommand('rm -r %s' % p, timeout_time=2 * 60) | 1199 self.RunShellCommand('rm -r %s' % p, timeout_time=2 * 60) |
1148 | 1200 |
1149 def ListPathContents(self, path): | 1201 def ListPathContents(self, path): |
(...skipping 774 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1924 """ | 1976 """ |
1925 def __init__(self, output): | 1977 def __init__(self, output): |
1926 self._output = output | 1978 self._output = output |
1927 | 1979 |
1928 def write(self, data): | 1980 def write(self, data): |
1929 data = data.replace('\r\r\n', '\n') | 1981 data = data.replace('\r\r\n', '\n') |
1930 self._output.write(data) | 1982 self._output.write(data) |
1931 | 1983 |
1932 def flush(self): | 1984 def flush(self): |
1933 self._output.flush() | 1985 self._output.flush() |
OLD | NEW |