telemetry: android: use both methods to access protected files

Currently when telemetry asks to read/write a protected file, it attempts doing
so with the 'su' command, but not all devices have the 'su' command installed.
In this case telemetry ignores all errors and continues silently.

This change:
1. chooses the best method to access protected files: 'adb root' or 'su'
2. caches the choice
3. throws warnings each time a protected file cannot be accessed

BUG=366640

Review URL: https://codereview.chromium.org/251743003

git-svn-id: http://src.chromium.org/svn/trunk/src/build@267137 4ff67af0-8c30-449e-8e8b-ad334ec8d88c
This commit is contained in:
pasko@chromium.org 2014-04-30 08:41:06 +00:00
Родитель ee91d0b771
Коммит b7d2edf238
1 изменённых файлов: 49 добавлений и 11 удалений

Просмотреть файл

@ -297,6 +297,8 @@ class AndroidCommands(object):
'command': None,
'cached': False,
}
self._protected_file_access_method_initialized = None
self._privileged_command_runner = None
@property
def system_properties(self):
@ -1105,28 +1107,58 @@ class AndroidCommands(object):
return self.RunShellCommand('su -c %s' % command, timeout_time, log_result)
def CanAccessProtectedFileContents(self):
"""Returns True if Get/SetProtectedFileContents would work via "su".
"""Returns True if Get/SetProtectedFileContents would work via "su" or adb
shell running as root.
Devices running user builds don't have adb root, but may provide "su" which
can be used for accessing protected files.
"""
r = self.RunShellCommandWithSU('cat /dev/null')
return r == [] or r[0].strip() == ''
return (self._GetProtectedFileCommandRunner() != None)
def _GetProtectedFileCommandRunner(self):
"""Finds the best method to access protected files on the device.
Returns:
1. None when privileged files cannot be accessed on the device.
2. Otherwise: A function taking a single parameter: a string with command
line arguments. Running that function executes the command with
the appropriate method.
"""
if self._protected_file_access_method_initialized:
return self._privileged_command_runner
self._privileged_command_runner = None
self._protected_file_access_method_initialized = True
for cmd in [self.RunShellCommand, self.RunShellCommandWithSU]:
# Get contents of the auxv vector for the init(8) process from a small
# binary file that always exists on linux and is always read-protected.
contents = cmd('cat /proc/1/auxv')
# The leading 4 or 8-bytes of auxv vector is a_type. There are not many
# reserved a_type values, hence byte 2 must always be '\0' for a realistic
# auxv. See /usr/include/elf.h.
if len(contents) > 0 and (contents[0][2] == '\0'):
self._privileged_command_runner = cmd
break
return self._privileged_command_runner
def GetProtectedFileContents(self, filename):
"""Gets contents from the protected file specified by |filename|.
This is less efficient than GetFileContents, but will work for protected
files and device files.
This is potentially less efficient than GetFileContents.
"""
# Run the script as root
return self.RunShellCommandWithSU('cat "%s" 2> /dev/null' % filename)
command = 'cat "%s" 2> /dev/null' % filename
command_runner = self._GetProtectedFileCommandRunner()
if command_runner:
return command_runner(command)
else:
logging.warning('Could not access protected file: %s' % filename)
return []
def SetProtectedFileContents(self, filename, contents):
"""Writes |contents| to the protected file specified by |filename|.
This is less efficient than SetFileContents, but will work for protected
files and device files.
This is less efficient than SetFileContents.
"""
temp_file = self._GetDeviceTempFileName(AndroidCommands._TEMP_FILE_BASE_FMT)
temp_script = self._GetDeviceTempFileName(
@ -1136,8 +1168,14 @@ class AndroidCommands(object):
self.SetFileContents(temp_file, contents)
# Create a script to copy the file contents to its final destination
self.SetFileContents(temp_script, 'cat %s > %s' % (temp_file, filename))
# Run the script as root
self.RunShellCommandWithSU('sh %s' % temp_script)
command = 'sh %s' % temp_script
command_runner = self._GetProtectedFileCommandRunner()
if command_runner:
return command_runner(command)
else:
logging.warning('Could not set contents of protected file: %s' % filename)
# And remove the temporary files
self.RunShellCommand('rm ' + temp_file)
self.RunShellCommand('rm ' + temp_script)