Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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() |
| OLD | NEW |