Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(300)

Side by Side Diff: build/android/pylib/android_commands.py

Issue 276813002: Make it harder to leak temp files on devices (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | build/android/pylib/android_commands_unittest.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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()
OLDNEW
« no previous file with comments | « no previous file | build/android/pylib/android_commands_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698