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 |