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

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=""):
jbudorick 2014/05/09 15:57:03 nit: single quotes
cjhopman 2014/05/09 18:55:14 Done.
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' % (
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 Name(self):
jbudorick 2014/05/09 15:57:03 nit: unused?
cjhopman 2014/05/09 18:55:14 Done.
109 return self.name
110
111 def close(self):
112 self.android_commands.RunShellCommand('rm ' + self.name)
113
114
85 def GetAVDs(): 115 def GetAVDs():
86 """Returns a list of AVDs.""" 116 """Returns a list of AVDs."""
87 re_avd = re.compile('^[ ]+Name: ([a-zA-Z0-9_:.-]+)', re.MULTILINE) 117 re_avd = re.compile('^[ ]+Name: ([a-zA-Z0-9_:.-]+)', re.MULTILINE)
88 avds = re_avd.findall(cmd_helper.GetCmdOutput(['android', 'list', 'avd'])) 118 avds = re_avd.findall(cmd_helper.GetCmdOutput(['android', 'list', 'avd']))
89 return avds 119 return avds
90 120
91 def ResetBadDevices(): 121 def ResetBadDevices():
92 """Removes the blacklist that keeps track of bad devices for a current 122 """Removes the blacklist that keeps track of bad devices for a current
93 build. 123 build.
94 """ 124 """
(...skipping 991 matching lines...) Expand 10 before | Expand all | Expand 10 after
1086 return self.RunShellCommand('cat "%s" 2>/dev/null' % filename, 1116 return self.RunShellCommand('cat "%s" 2>/dev/null' % filename,
1087 log_result=log_result) 1117 log_result=log_result)
1088 1118
1089 def SetFileContents(self, filename, contents): 1119 def SetFileContents(self, filename, contents):
1090 """Writes |contents| to the file specified by |filename|.""" 1120 """Writes |contents| to the file specified by |filename|."""
1091 with tempfile.NamedTemporaryFile() as f: 1121 with tempfile.NamedTemporaryFile() as f:
1092 f.write(contents) 1122 f.write(contents)
1093 f.flush() 1123 f.flush()
1094 self._adb.Push(f.name, filename) 1124 self._adb.Push(f.name, filename)
1095 1125
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): 1126 def RunShellCommandWithSU(self, command, timeout_time=20, log_result=False):
1107 return self.RunShellCommand('su -c %s' % command, timeout_time, log_result) 1127 return self.RunShellCommand('su -c %s' % command, timeout_time, log_result)
1108 1128
1109 def CanAccessProtectedFileContents(self): 1129 def CanAccessProtectedFileContents(self):
1110 """Returns True if Get/SetProtectedFileContents would work via "su" or adb 1130 """Returns True if Get/SetProtectedFileContents would work via "su" or adb
1111 shell running as root. 1131 shell running as root.
1112 1132
1113 Devices running user builds don't have adb root, but may provide "su" which 1133 Devices running user builds don't have adb root, but may provide "su" which
1114 can be used for accessing protected files. 1134 can be used for accessing protected files.
1115 """ 1135 """
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
1153 return command_runner(command) 1173 return command_runner(command)
1154 else: 1174 else:
1155 logging.warning('Could not access protected file: %s' % filename) 1175 logging.warning('Could not access protected file: %s' % filename)
1156 return [] 1176 return []
1157 1177
1158 def SetProtectedFileContents(self, filename, contents): 1178 def SetProtectedFileContents(self, filename, contents):
1159 """Writes |contents| to the protected file specified by |filename|. 1179 """Writes |contents| to the protected file specified by |filename|.
1160 1180
1161 This is less efficient than SetFileContents. 1181 This is less efficient than SetFileContents.
1162 """ 1182 """
1163 temp_file = self._GetDeviceTempFileName(AndroidCommands._TEMP_FILE_BASE_FMT) 1183 with DeviceTempFile(self) as temp_file:
craigdh 2014/05/09 16:02:40 I don't think we need to support pre-2.7 Python, s
cjhopman 2014/05/09 18:55:14 Done.
cjhopman 2014/05/16 01:15:19 Undone. So, making this one with statement means t
1164 temp_script = self._GetDeviceTempFileName( 1184 with DeviceTempFile(self, suffix=".sh") as temp_script:
1165 AndroidCommands._TEMP_SCRIPT_FILE_BASE_FMT) 1185 # Put the contents in a temporary file
1186 self.SetFileContents(temp_file.name, contents)
1187 # Create a script to copy the file contents to its final destination
1188 self.SetFileContents(temp_script.name,
1189 'cat %s > %s' % (temp_file.name, filename))
1166 1190
1167 # Put the contents in a temporary file 1191 command = 'sh %s' % temp_script.name
1168 self.SetFileContents(temp_file, contents) 1192 command_runner = self._GetProtectedFileCommandRunner()
1169 # Create a script to copy the file contents to its final destination 1193 if command_runner:
1170 self.SetFileContents(temp_script, 'cat %s > %s' % (temp_file, filename)) 1194 return command_runner(command)
1195 else:
1196 logging.warning(
1197 'Could not set contents of protected file: %s' % filename)
1171 1198
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 1199
1183 def RemovePushedFiles(self): 1200 def RemovePushedFiles(self):
1184 """Removes all files pushed with PushIfNeeded() from the device.""" 1201 """Removes all files pushed with PushIfNeeded() from the device."""
1185 for p in self._pushed_files: 1202 for p in self._pushed_files:
1186 self.RunShellCommand('rm -r %s' % p, timeout_time=2 * 60) 1203 self.RunShellCommand('rm -r %s' % p, timeout_time=2 * 60)
1187 1204
1188 def ListPathContents(self, path): 1205 def ListPathContents(self, path):
1189 """Lists files in all subdirectories of |path|. 1206 """Lists files in all subdirectories of |path|.
1190 1207
1191 Args: 1208 Args:
(...skipping 685 matching lines...) Expand 10 before | Expand all | Expand 10 after
1877 1894
1878 Uses a shell script running on the target to copy new and changed files the 1895 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 1896 source directory to the destination directory and remove added files. This
1880 is in some cases much faster than cp -r. 1897 is in some cases much faster than cp -r.
1881 1898
1882 Args: 1899 Args:
1883 source: absolute path of source directory 1900 source: absolute path of source directory
1884 dest: absolute path of destination directory 1901 dest: absolute path of destination directory
1885 """ 1902 """
1886 logging.info('In EfficientDeviceDirectoryCopy %s %s', source, dest) 1903 logging.info('In EfficientDeviceDirectoryCopy %s %s', source, dest)
1887 temp_script_file = self._GetDeviceTempFileName( 1904 with DeviceTempFile(self, suffix=".sh") as temp_script_file:
1888 AndroidCommands._TEMP_SCRIPT_FILE_BASE_FMT) 1905 host_script_path = os.path.join(constants.DIR_SOURCE_ROOT,
1889 host_script_path = os.path.join(constants.DIR_SOURCE_ROOT, 1906 'build',
1890 'build', 1907 'android',
1891 'android', 1908 'pylib',
1892 'pylib', 1909 'efficient_android_directory_copy.sh')
1893 'efficient_android_directory_copy.sh') 1910 self._adb.Push(host_script_path, temp_script_file.name)
1894 self._adb.Push(host_script_path, temp_script_file) 1911 self.EnableAdbRoot
1895 self.EnableAdbRoot 1912 out = self.RunShellCommand(
1896 out = self.RunShellCommand('sh %s %s %s' % (temp_script_file, source, dest), 1913 'sh %s %s %s' % (temp_script_file.name, source, dest),
1897 timeout_time=120) 1914 timeout_time=120)
1898 if self._device: 1915 if self._device:
1899 device_repr = self._device[-4:] 1916 device_repr = self._device[-4:]
1900 else: 1917 else:
1901 device_repr = '????' 1918 device_repr = '????'
1902 for line in out: 1919 for line in out:
1903 logging.info('[%s]> %s', device_repr, line) 1920 logging.info('[%s]> %s', device_repr, line)
1904 self.RunShellCommand('rm %s' % temp_script_file)
1905 1921
1906 def _GetControlUsbChargingCommand(self): 1922 def _GetControlUsbChargingCommand(self):
1907 if self._control_usb_charging_command['cached']: 1923 if self._control_usb_charging_command['cached']:
1908 return self._control_usb_charging_command['command'] 1924 return self._control_usb_charging_command['command']
1909 self._control_usb_charging_command['cached'] = True 1925 self._control_usb_charging_command['cached'] = True
1910 for command in CONTROL_USB_CHARGING_COMMANDS: 1926 for command in CONTROL_USB_CHARGING_COMMANDS:
1911 # Assert command is valid. 1927 # Assert command is valid.
1912 assert 'disable_command' in command 1928 assert 'disable_command' in command
1913 assert 'enable_command' in command 1929 assert 'enable_command' in command
1914 assert 'witness_file' in command 1930 assert 'witness_file' in command
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
1963 """ 1979 """
1964 def __init__(self, output): 1980 def __init__(self, output):
1965 self._output = output 1981 self._output = output
1966 1982
1967 def write(self, data): 1983 def write(self, data):
1968 data = data.replace('\r\r\n', '\n') 1984 data = data.replace('\r\r\n', '\n')
1969 self._output.write(data) 1985 self._output.write(data)
1970 1986
1971 def flush(self): 1987 def flush(self):
1972 self._output.flush() 1988 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