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

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 logging 14 import logging
15 import os 15 import os
16 import random
16 import re 17 import re
17 import shlex 18 import shlex
18 import signal 19 import signal
19 import subprocess 20 import subprocess
20 import sys 21 import sys
21 import tempfile 22 import tempfile
22 import time 23 import time
23 24
24 import cmd_helper 25 import cmd_helper
25 import constants 26 import constants
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
71 CONTROL_USB_CHARGING_COMMANDS = [ 72 CONTROL_USB_CHARGING_COMMANDS = [
72 { 73 {
73 # Nexus 4 74 # Nexus 4
74 'witness_file': '/sys/module/pm8921_charger/parameters/disabled', 75 'witness_file': '/sys/module/pm8921_charger/parameters/disabled',
75 'enable_command': 'echo 0 > /sys/module/pm8921_charger/parameters/disabled', 76 'enable_command': 'echo 0 > /sys/module/pm8921_charger/parameters/disabled',
76 'disable_command': 77 'disable_command':
77 'echo 1 > /sys/module/pm8921_charger/parameters/disabled', 78 'echo 1 > /sys/module/pm8921_charger/parameters/disabled',
78 }, 79 },
79 ] 80 ]
80 81
82 class DeviceTempFile(object):
83 def __init__(self, android_commands, prefix='temp_file', suffix=''):
84 """Find an unused temporary file path in the devices external directory.
85
86 When this object is closed, the file will be deleted on the device.
87 """
88 self.android_commands = android_commands
89 while True:
90 # TODO(cjhopman): This could actually return the same file in multiple
91 # calls if the caller doesn't write to the files immediately. This is
92 # expected to never happen.
93 i = random.randint(0, 1000000)
94 self.name = '%s/%s-%d-%010d%s' % (
95 android_commands.GetExternalStorage(),
96 prefix, int(time.time()), i, suffix)
97 if not android_commands.FileExistsOnDevice(self.name):
98 break
99
100 def __enter__(self):
101 return self
102
103 def __exit__(self, type, value, traceback):
104 self.close()
105
106 def close(self):
107 self.android_commands.RunShellCommand('rm ' + self.name)
108
109
81 def GetAVDs(): 110 def GetAVDs():
82 """Returns a list of AVDs.""" 111 """Returns a list of AVDs."""
83 re_avd = re.compile('^[ ]+Name: ([a-zA-Z0-9_:.-]+)', re.MULTILINE) 112 re_avd = re.compile('^[ ]+Name: ([a-zA-Z0-9_:.-]+)', re.MULTILINE)
84 avds = re_avd.findall(cmd_helper.GetCmdOutput(['android', 'list', 'avd'])) 113 avds = re_avd.findall(cmd_helper.GetCmdOutput(['android', 'list', 'avd']))
85 return avds 114 return avds
86 115
87 def ResetBadDevices(): 116 def ResetBadDevices():
88 """Removes the blacklist that keeps track of bad devices for a current 117 """Removes the blacklist that keeps track of bad devices for a current
89 build. 118 build.
90 """ 119 """
(...skipping 1027 matching lines...) Expand 10 before | Expand all | Expand 10 after
1118 return self.RunShellCommand('cat "%s" 2>/dev/null' % filename, 1147 return self.RunShellCommand('cat "%s" 2>/dev/null' % filename,
1119 log_result=log_result) 1148 log_result=log_result)
1120 1149
1121 def SetFileContents(self, filename, contents): 1150 def SetFileContents(self, filename, contents):
1122 """Writes |contents| to the file specified by |filename|.""" 1151 """Writes |contents| to the file specified by |filename|."""
1123 with tempfile.NamedTemporaryFile() as f: 1152 with tempfile.NamedTemporaryFile() as f:
1124 f.write(contents) 1153 f.write(contents)
1125 f.flush() 1154 f.flush()
1126 self._adb.Push(f.name, filename) 1155 self._adb.Push(f.name, filename)
1127 1156
1128 _TEMP_FILE_BASE_FMT = 'temp_file_%d'
1129 _TEMP_SCRIPT_FILE_BASE_FMT = 'temp_script_file_%d.sh'
1130
1131 def _GetDeviceTempFileName(self, base_name):
1132 i = 0
1133 while self.FileExistsOnDevice(
1134 self.GetExternalStorage() + '/' + base_name % i):
1135 i += 1
1136 return self.GetExternalStorage() + '/' + base_name % i
1137
1138 def RunShellCommandWithSU(self, command, timeout_time=20, log_result=False): 1157 def RunShellCommandWithSU(self, command, timeout_time=20, log_result=False):
1139 return self.RunShellCommand('su -c %s' % command, timeout_time, log_result) 1158 return self.RunShellCommand('su -c %s' % command, timeout_time, log_result)
1140 1159
1141 def CanAccessProtectedFileContents(self): 1160 def CanAccessProtectedFileContents(self):
1142 """Returns True if Get/SetProtectedFileContents would work via "su" or adb 1161 """Returns True if Get/SetProtectedFileContents would work via "su" or adb
1143 shell running as root. 1162 shell running as root.
1144 1163
1145 Devices running user builds don't have adb root, but may provide "su" which 1164 Devices running user builds don't have adb root, but may provide "su" which
1146 can be used for accessing protected files. 1165 can be used for accessing protected files.
1147 """ 1166 """
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
1185 return command_runner(command) 1204 return command_runner(command)
1186 else: 1205 else:
1187 logging.warning('Could not access protected file: %s' % filename) 1206 logging.warning('Could not access protected file: %s' % filename)
1188 return [] 1207 return []
1189 1208
1190 def SetProtectedFileContents(self, filename, contents): 1209 def SetProtectedFileContents(self, filename, contents):
1191 """Writes |contents| to the protected file specified by |filename|. 1210 """Writes |contents| to the protected file specified by |filename|.
1192 1211
1193 This is less efficient than SetFileContents. 1212 This is less efficient than SetFileContents.
1194 """ 1213 """
1195 temp_file = self._GetDeviceTempFileName(AndroidCommands._TEMP_FILE_BASE_FMT) 1214 with DeviceTempFile(self) as temp_file:
1196 temp_script = self._GetDeviceTempFileName( 1215 with DeviceTempFile(self, suffix=".sh") as temp_script:
1197 AndroidCommands._TEMP_SCRIPT_FILE_BASE_FMT) 1216 # Put the contents in a temporary file
1217 self.SetFileContents(temp_file.name, contents)
1218 # Create a script to copy the file contents to its final destination
1219 self.SetFileContents(temp_script.name,
1220 'cat %s > %s' % (temp_file.name, filename))
1198 1221
1199 try: 1222 command = 'sh %s' % temp_script.name
1200 # Put the contents in a temporary file 1223 command_runner = self._GetProtectedFileCommandRunner()
1201 self.SetFileContents(temp_file, contents) 1224 if command_runner:
1202 # Create a script to copy the file contents to its final destination 1225 return command_runner(command)
1203 self.SetFileContents(temp_script, 'cat %s > %s' % (temp_file, filename)) 1226 else:
1227 logging.warning(
1228 'Could not set contents of protected file: %s' % filename)
1204 1229
1205 command = 'sh %s' % temp_script
1206 command_runner = self._GetProtectedFileCommandRunner()
1207 if command_runner:
1208 return command_runner(command)
1209 else:
1210 logging.warning(
1211 'Could not set contents of protected file: %s' % filename)
1212 finally:
1213 # And remove the temporary files
1214 self.RunShellCommand('rm ' + temp_file)
1215 self.RunShellCommand('rm ' + temp_script)
1216 1230
1217 def RemovePushedFiles(self): 1231 def RemovePushedFiles(self):
1218 """Removes all files pushed with PushIfNeeded() from the device.""" 1232 """Removes all files pushed with PushIfNeeded() from the device."""
1219 for p in self._pushed_files: 1233 for p in self._pushed_files:
1220 self.RunShellCommand('rm -r %s' % p, timeout_time=2 * 60) 1234 self.RunShellCommand('rm -r %s' % p, timeout_time=2 * 60)
1221 1235
1222 def ListPathContents(self, path): 1236 def ListPathContents(self, path):
1223 """Lists files in all subdirectories of |path|. 1237 """Lists files in all subdirectories of |path|.
1224 1238
1225 Args: 1239 Args:
(...skipping 644 matching lines...) Expand 10 before | Expand all | Expand 10 after
1870 1884
1871 Uses a shell script running on the target to copy new and changed files the 1885 Uses a shell script running on the target to copy new and changed files the
1872 source directory to the destination directory and remove added files. This 1886 source directory to the destination directory and remove added files. This
1873 is in some cases much faster than cp -r. 1887 is in some cases much faster than cp -r.
1874 1888
1875 Args: 1889 Args:
1876 source: absolute path of source directory 1890 source: absolute path of source directory
1877 dest: absolute path of destination directory 1891 dest: absolute path of destination directory
1878 """ 1892 """
1879 logging.info('In EfficientDeviceDirectoryCopy %s %s', source, dest) 1893 logging.info('In EfficientDeviceDirectoryCopy %s %s', source, dest)
1880 temp_script_file = self._GetDeviceTempFileName( 1894 with DeviceTempFile(self, suffix=".sh") as temp_script_file:
1881 AndroidCommands._TEMP_SCRIPT_FILE_BASE_FMT) 1895 host_script_path = os.path.join(constants.DIR_SOURCE_ROOT,
1882 host_script_path = os.path.join(constants.DIR_SOURCE_ROOT, 1896 'build',
1883 'build', 1897 'android',
1884 'android', 1898 'pylib',
1885 'pylib', 1899 'efficient_android_directory_copy.sh')
1886 'efficient_android_directory_copy.sh') 1900 self._adb.Push(host_script_path, temp_script_file.name)
1887 try: 1901 self.EnableAdbRoot
1888 self._adb.Push(host_script_path, temp_script_file) 1902 out = self.RunShellCommand(
1889 self.EnableAdbRoot() 1903 'sh %s %s %s' % (temp_script_file.name, source, dest),
1890 out = self.RunShellCommand('sh %s %s %s' % (temp_script_file, 1904 timeout_time=120)
1891 source,
1892 dest),
1893 timeout_time=120)
1894 if self._device: 1905 if self._device:
1895 device_repr = self._device[-4:] 1906 device_repr = self._device[-4:]
1896 else: 1907 else:
1897 device_repr = '????' 1908 device_repr = '????'
1898 for line in out: 1909 for line in out:
1899 logging.info('[%s]> %s', device_repr, line) 1910 logging.info('[%s]> %s', device_repr, line)
1900 finally:
1901 self.RunShellCommand('rm %s' % temp_script_file)
1902 1911
1903 def _GetControlUsbChargingCommand(self): 1912 def _GetControlUsbChargingCommand(self):
1904 if self._control_usb_charging_command['cached']: 1913 if self._control_usb_charging_command['cached']:
1905 return self._control_usb_charging_command['command'] 1914 return self._control_usb_charging_command['command']
1906 self._control_usb_charging_command['cached'] = True 1915 self._control_usb_charging_command['cached'] = True
1907 for command in CONTROL_USB_CHARGING_COMMANDS: 1916 for command in CONTROL_USB_CHARGING_COMMANDS:
1908 # Assert command is valid. 1917 # Assert command is valid.
1909 assert 'disable_command' in command 1918 assert 'disable_command' in command
1910 assert 'enable_command' in command 1919 assert 'enable_command' in command
1911 assert 'witness_file' in command 1920 assert 'witness_file' in command
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
1960 """ 1969 """
1961 def __init__(self, output): 1970 def __init__(self, output):
1962 self._output = output 1971 self._output = output
1963 1972
1964 def write(self, data): 1973 def write(self, data):
1965 data = data.replace('\r\r\n', '\n') 1974 data = data.replace('\r\r\n', '\n')
1966 self._output.write(data) 1975 self._output.write(data)
1967 1976
1968 def flush(self): 1977 def flush(self):
1969 self._output.flush() 1978 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