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

Side by Side Diff: build/android/devil/android/device_utils.py

Issue 1325893002: Defer running of install_commands.Installed() until necessary (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@device2
Patch Set: prefetch NeedsSU Created 5 years, 3 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
« no previous file with comments | « no previous file | build/android/devil/android/device_utils_test.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 2014 The Chromium Authors. All rights reserved. 1 # Copyright 2014 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 a variety of device interactions based on adb. 5 """Provides a variety of device interactions based on adb.
6 6
7 Eventually, this will be based on adb_wrapper. 7 Eventually, this will be based on adb_wrapper.
8 """ 8 """
9 # pylint: disable=unused-argument 9 # pylint: disable=unused-argument
10 10
(...skipping 1110 matching lines...) Expand 10 before | Expand all | Expand 10 after
1121 1121
1122 def _ComputeStaleApks(self, package_name, host_apk_paths): 1122 def _ComputeStaleApks(self, package_name, host_apk_paths):
1123 host_checksums, device_checksums = reraiser_thread.RunAsync(( 1123 host_checksums, device_checksums = reraiser_thread.RunAsync((
1124 lambda: md5sum.CalculateHostMd5Sums(host_apk_paths), 1124 lambda: md5sum.CalculateHostMd5Sums(host_apk_paths),
1125 lambda: self._ComputeDeviceChecksumsForApks(package_name))) 1125 lambda: self._ComputeDeviceChecksumsForApks(package_name)))
1126 stale_apks = [k for (k, v) in host_checksums.iteritems() 1126 stale_apks = [k for (k, v) in host_checksums.iteritems()
1127 if v not in device_checksums] 1127 if v not in device_checksums]
1128 return stale_apks, set(host_checksums.values()) 1128 return stale_apks, set(host_checksums.values())
1129 1129
1130 def _PushFilesImpl(self, host_device_tuples, files): 1130 def _PushFilesImpl(self, host_device_tuples, files):
1131 if not files:
1132 return
1133
1131 size = sum(host_utils.GetRecursiveDiskUsage(h) for h, _ in files) 1134 size = sum(host_utils.GetRecursiveDiskUsage(h) for h, _ in files)
1132 file_count = len(files) 1135 file_count = len(files)
1133 dir_size = sum(host_utils.GetRecursiveDiskUsage(h) 1136 dir_size = sum(host_utils.GetRecursiveDiskUsage(h)
1134 for h, _ in host_device_tuples) 1137 for h, _ in host_device_tuples)
1135 dir_file_count = 0 1138 dir_file_count = 0
1136 for h, _ in host_device_tuples: 1139 for h, _ in host_device_tuples:
1137 if os.path.isdir(h): 1140 if os.path.isdir(h):
1138 dir_file_count += sum(len(f) for _r, _d, f in os.walk(h)) 1141 dir_file_count += sum(len(f) for _r, _d, f in os.walk(h))
1139 else: 1142 else:
1140 dir_file_count += 1 1143 dir_file_count += 1
1141 1144
1142 push_duration = self._ApproximateDuration( 1145 push_duration = self._ApproximateDuration(
1143 file_count, file_count, size, False) 1146 file_count, file_count, size, False)
1144 dir_push_duration = self._ApproximateDuration( 1147 dir_push_duration = self._ApproximateDuration(
1145 len(host_device_tuples), dir_file_count, dir_size, False) 1148 len(host_device_tuples), dir_file_count, dir_size, False)
1146 zip_duration = self._ApproximateDuration(1, 1, size, True) 1149 zip_duration = self._ApproximateDuration(1, 1, size, True)
1147 1150
1148 self._InstallCommands() 1151 if dir_push_duration < push_duration and dir_push_duration < zip_duration:
1149
1150 if dir_push_duration < push_duration and (
1151 dir_push_duration < zip_duration or not self._commands_installed):
1152 self._PushChangedFilesIndividually(host_device_tuples) 1152 self._PushChangedFilesIndividually(host_device_tuples)
1153 elif push_duration < zip_duration or not self._commands_installed: 1153 elif push_duration < zip_duration:
1154 self._PushChangedFilesIndividually(files)
1155 elif self._commands_installed is False:
1156 # Already tried and failed to install unzip command.
1154 self._PushChangedFilesIndividually(files) 1157 self._PushChangedFilesIndividually(files)
1155 else: 1158 else:
1156 self._PushChangedFilesZipped(files) 1159 self._PushChangedFilesZipped(files, [d for _, d in host_device_tuples])
1157 self.RunShellCommand(
1158 ['chmod', '-R', '777'] + [d for _, d in host_device_tuples],
1159 as_root=True, check_return=True)
1160 1160
1161 def _InstallCommands(self): 1161 def _MaybeInstallCommands(self):
1162 if self._commands_installed is None: 1162 if self._commands_installed is None:
1163 try: 1163 if not install_commands.Installed(self):
jbudorick 2015/09/04 16:09:11 What happened to the exception handler on installa
agrieve 2015/09/04 17:21:23 Yikes! Removed it when debugging. put it back.
1164 if not install_commands.Installed(self): 1164 install_commands.InstallCommands(self)
1165 install_commands.InstallCommands(self) 1165 self._commands_installed = True
1166 self._commands_installed = True 1166 return self._commands_installed
1167 except Exception as e:
1168 logging.warning('unzip not available: %s' % str(e))
1169 self._commands_installed = False
1170 1167
1171 @staticmethod 1168 @staticmethod
1172 def _ApproximateDuration(adb_calls, file_count, byte_count, is_zipping): 1169 def _ApproximateDuration(adb_calls, file_count, byte_count, is_zipping):
1173 # We approximate the time to push a set of files to a device as: 1170 # We approximate the time to push a set of files to a device as:
1174 # t = c1 * a + c2 * f + c3 + b / c4 + b / (c5 * c6), where 1171 # t = c1 * a + c2 * f + c3 + b / c4 + b / (c5 * c6), where
1175 # t: total time (sec) 1172 # t: total time (sec)
1176 # c1: adb call time delay (sec) 1173 # c1: adb call time delay (sec)
1177 # a: number of times adb is called (unitless) 1174 # a: number of times adb is called (unitless)
1178 # c2: push time delay (sec) 1175 # c2: push time delay (sec)
1179 # f: number of files pushed via adb (unitless) 1176 # f: number of files pushed via adb (unitless)
(...skipping 18 matching lines...) Expand all
1198 transfer_time = byte_count / (TRANSFER_RATE * COMPRESSION_RATIO) 1195 transfer_time = byte_count / (TRANSFER_RATE * COMPRESSION_RATIO)
1199 else: 1196 else:
1200 zip_time = 0 1197 zip_time = 0
1201 transfer_time = byte_count / TRANSFER_RATE 1198 transfer_time = byte_count / TRANSFER_RATE
1202 return adb_call_time + adb_push_setup_time + zip_time + transfer_time 1199 return adb_call_time + adb_push_setup_time + zip_time + transfer_time
1203 1200
1204 def _PushChangedFilesIndividually(self, files): 1201 def _PushChangedFilesIndividually(self, files):
1205 for h, d in files: 1202 for h, d in files:
1206 self.adb.Push(h, d) 1203 self.adb.Push(h, d)
1207 1204
1208 def _PushChangedFilesZipped(self, files): 1205 def _PushChangedFilesZipped(self, files, dirs):
1209 if not files:
1210 return
1211
1212 with tempfile.NamedTemporaryFile(suffix='.zip') as zip_file: 1206 with tempfile.NamedTemporaryFile(suffix='.zip') as zip_file:
1213 zip_proc = multiprocessing.Process( 1207 zip_proc = multiprocessing.Process(
1214 target=DeviceUtils._CreateDeviceZip, 1208 target=DeviceUtils._CreateDeviceZip,
1215 args=(zip_file.name, files)) 1209 args=(zip_file.name, files))
1216 zip_proc.start() 1210 zip_proc.start()
1217 zip_proc.join() 1211 try:
1212 # While it's zipping, ensure the unzip command exists on the device.
jbudorick 2015/09/04 16:09:11 I'm not crazy about this flow... PuchChangedFilesZ
agrieve 2015/09/04 17:21:23 Fair. Moved it up a level.
1213 if not self._MaybeInstallCommands():
1214 zip_proc.terminate()
1215 self._PushChangedFilesIndividually(files)
1216 return
1218 1217
1219 zip_on_device = '%s/tmp.zip' % self.GetExternalStoragePath() 1218 # Warm up NeedsSU cache while we're still zipping.
1220 try: 1219 self.NeedsSU()
1221 self.adb.Push(zip_file.name, zip_on_device) 1220 external_dir = self.GetExternalStoragePath()
1222 self.RunShellCommand( 1221 with device_temp_file.DeviceTempFile(
1223 ['unzip', zip_on_device], 1222 self.adb, suffix='.zip', dir=external_dir) as device_temp:
1224 as_root=True, 1223 zip_proc.join()
1225 env={'PATH': '%s:$PATH' % install_commands.BIN_DIR}, 1224 self.adb.Push(zip_file.name, device_temp.name)
1226 check_return=True) 1225 quoted_dirs = ' '.join(cmd_helper.SingleQuote(d) for d in dirs)
1226 self.RunShellCommand(
1227 'unzip %s&&chmod -R 777 %s' % (device_temp.name, quoted_dirs),
1228 as_root=True,
1229 env={'PATH': '%s:$PATH' % install_commands.BIN_DIR},
1230 check_return=True)
1227 finally: 1231 finally:
1228 if zip_proc.is_alive(): 1232 if zip_proc.is_alive():
1229 zip_proc.terminate() 1233 zip_proc.terminate()
1230 if self.IsOnline():
1231 self.RunShellCommand(['rm', zip_on_device], check_return=True)
1232 1234
1233 @staticmethod 1235 @staticmethod
1234 def _CreateDeviceZip(zip_path, host_device_tuples): 1236 def _CreateDeviceZip(zip_path, host_device_tuples):
1235 with zipfile.ZipFile(zip_path, 'w') as zip_file: 1237 with zipfile.ZipFile(zip_path, 'w') as zip_file:
1236 for host_path, device_path in host_device_tuples: 1238 for host_path, device_path in host_device_tuples:
1237 zip_utils.WriteToZipFile(zip_file, host_path, device_path) 1239 zip_utils.WriteToZipFile(zip_file, host_path, device_path)
1238 1240
1239 # TODO(nednguyen): remove this and migrate the callsite to PathExists(). 1241 # TODO(nednguyen): remove this and migrate the callsite to PathExists().
1240 def FileExists(self, device_path, timeout=None, retries=None): 1242 def FileExists(self, device_path, timeout=None, retries=None):
1241 """Checks whether the given file exists on the device. 1243 """Checks whether the given file exists on the device.
1242 1244
1243 Arguments are the same as PathExists. 1245 Arguments are the same as PathExists.
1244 """ 1246 """
1245 return self.PathExists(device_path, timeout=timeout, retries=retries) 1247 return self.PathExists(device_path, timeout=timeout, retries=retries)
1246 1248
1247 @decorators.WithTimeoutAndRetriesFromInstance() 1249 def PathExists(self, device_paths, timeout=None, retries=None):
1248 def PathExists(self, device_path, timeout=None, retries=None): 1250 """Checks whether the given path(s) exists on the device.
1249 """Checks whether the given path exists on the device.
1250 1251
1251 Args: 1252 Args:
1252 device_path: A string containing the absolute path to the file on the 1253 device_path: A string containing the absolute path to the file on the
1253 device. 1254 device, or an iterable of paths to check.
1254 timeout: timeout in seconds 1255 timeout: timeout in seconds
1255 retries: number of retries 1256 retries: number of retries
1256 1257
1257 Returns: 1258 Returns:
1258 True if the file exists on the device, False otherwise. 1259 True if the all given paths exist on the device, False otherwise.
1259 1260
1260 Raises: 1261 Raises:
1261 CommandTimeoutError on timeout. 1262 CommandTimeoutError on timeout.
1262 DeviceUnreachableError on missing device. 1263 DeviceUnreachableError on missing device.
1263 """ 1264 """
1264 try: 1265 paths = device_paths
1265 self.RunShellCommand(['test', '-e', device_path], check_return=True) 1266 if isinstance(paths, basestring):
1266 return True 1267 paths = (paths,)
1267 except device_errors.AdbCommandFailedError: 1268 condition = ' -a '.join('-e %s' % cmd_helper.SingleQuote(p) for p in paths)
1268 return False 1269 cmd = 'test %s;echo $?' % condition
1270 result = self.RunShellCommand(cmd, check_return=True, timeout=timeout,
1271 retries=retries)
1272 return '0' == result[0]
1269 1273
1270 @decorators.WithTimeoutAndRetriesFromInstance() 1274 @decorators.WithTimeoutAndRetriesFromInstance()
1271 def PullFile(self, device_path, host_path, timeout=None, retries=None): 1275 def PullFile(self, device_path, host_path, timeout=None, retries=None):
1272 """Pull a file from the device. 1276 """Pull a file from the device.
1273 1277
1274 Args: 1278 Args:
1275 device_path: A string containing the absolute path of the file to pull 1279 device_path: A string containing the absolute path of the file to pull
1276 from the device. 1280 from the device.
1277 host_path: A string containing the absolute path of the destination on 1281 host_path: A string containing the absolute path of the destination on
1278 the host. 1282 the host.
(...skipping 651 matching lines...) Expand 10 before | Expand all | Expand 10 after
1930 return [cls(adb, **kwargs) for adb in adb_wrapper.AdbWrapper.Devices() 1934 return [cls(adb, **kwargs) for adb in adb_wrapper.AdbWrapper.Devices()
1931 if not blacklisted(adb)] 1935 if not blacklisted(adb)]
1932 1936
1933 @decorators.WithTimeoutAndRetriesFromInstance() 1937 @decorators.WithTimeoutAndRetriesFromInstance()
1934 def RestartAdbd(self, timeout=None, retries=None): 1938 def RestartAdbd(self, timeout=None, retries=None):
1935 logging.info('Restarting adbd on device.') 1939 logging.info('Restarting adbd on device.')
1936 with device_temp_file.DeviceTempFile(self.adb, suffix='.sh') as script: 1940 with device_temp_file.DeviceTempFile(self.adb, suffix='.sh') as script:
1937 self.WriteFile(script.name, _RESTART_ADBD_SCRIPT) 1941 self.WriteFile(script.name, _RESTART_ADBD_SCRIPT)
1938 self.RunShellCommand(['source', script.name], as_root=True) 1942 self.RunShellCommand(['source', script.name], as_root=True)
1939 self.adb.WaitForDevice() 1943 self.adb.WaitForDevice()
OLDNEW
« no previous file with comments | « no previous file | build/android/devil/android/device_utils_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698