| Index: build/android/devil/android/device_utils.py
|
| diff --git a/build/android/devil/android/device_utils.py b/build/android/devil/android/device_utils.py
|
| index c35bc264ef9e48da1cfbcb10aa4df75fbaf2c42f..416009a2d29331f2a01e8ed6b5d4248bdee0f341 100644
|
| --- a/build/android/devil/android/device_utils.py
|
| +++ b/build/android/devil/android/device_utils.py
|
| @@ -1128,6 +1128,9 @@ class DeviceUtils(object):
|
| return stale_apks, set(host_checksums.values())
|
|
|
| def _PushFilesImpl(self, host_device_tuples, files):
|
| + if not files:
|
| + return
|
| +
|
| size = sum(host_utils.GetRecursiveDiskUsage(h) for h, _ in files)
|
| file_count = len(files)
|
| dir_size = sum(host_utils.GetRecursiveDiskUsage(h)
|
| @@ -1145,20 +1148,18 @@ class DeviceUtils(object):
|
| len(host_device_tuples), dir_file_count, dir_size, False)
|
| zip_duration = self._ApproximateDuration(1, 1, size, True)
|
|
|
| - self._InstallCommands()
|
| -
|
| - if dir_push_duration < push_duration and (
|
| - dir_push_duration < zip_duration or not self._commands_installed):
|
| + if dir_push_duration < push_duration and dir_push_duration < zip_duration:
|
| self._PushChangedFilesIndividually(host_device_tuples)
|
| - elif push_duration < zip_duration or not self._commands_installed:
|
| + elif push_duration < zip_duration:
|
| + self._PushChangedFilesIndividually(files)
|
| + elif self._commands_installed is False:
|
| + # Already tried and failed to install unzip command.
|
| + self._PushChangedFilesIndividually(files)
|
| + elif not self._PushChangedFilesZipped(
|
| + files, [d for _, d in host_device_tuples]):
|
| self._PushChangedFilesIndividually(files)
|
| - else:
|
| - self._PushChangedFilesZipped(files)
|
| - self.RunShellCommand(
|
| - ['chmod', '-R', '777'] + [d for _, d in host_device_tuples],
|
| - as_root=True, check_return=True)
|
|
|
| - def _InstallCommands(self):
|
| + def _MaybeInstallCommands(self):
|
| if self._commands_installed is None:
|
| try:
|
| if not install_commands.Installed(self):
|
| @@ -1167,6 +1168,7 @@ class DeviceUtils(object):
|
| except Exception as e:
|
| logging.warning('unzip not available: %s' % str(e))
|
| self._commands_installed = False
|
| + return self._commands_installed
|
|
|
| @staticmethod
|
| def _ApproximateDuration(adb_calls, file_count, byte_count, is_zipping):
|
| @@ -1205,30 +1207,35 @@ class DeviceUtils(object):
|
| for h, d in files:
|
| self.adb.Push(h, d)
|
|
|
| - def _PushChangedFilesZipped(self, files):
|
| - if not files:
|
| - return
|
| -
|
| + def _PushChangedFilesZipped(self, files, dirs):
|
| with tempfile.NamedTemporaryFile(suffix='.zip') as zip_file:
|
| zip_proc = multiprocessing.Process(
|
| target=DeviceUtils._CreateDeviceZip,
|
| args=(zip_file.name, files))
|
| zip_proc.start()
|
| - zip_proc.join()
|
| -
|
| - zip_on_device = '%s/tmp.zip' % self.GetExternalStoragePath()
|
| try:
|
| - self.adb.Push(zip_file.name, zip_on_device)
|
| - self.RunShellCommand(
|
| - ['unzip', zip_on_device],
|
| - as_root=True,
|
| - env={'PATH': '%s:$PATH' % install_commands.BIN_DIR},
|
| - check_return=True)
|
| + # While it's zipping, ensure the unzip command exists on the device.
|
| + if not self._MaybeInstallCommands():
|
| + zip_proc.terminate()
|
| + return False
|
| +
|
| + # Warm up NeedsSU cache while we're still zipping.
|
| + self.NeedsSU()
|
| + external_dir = self.GetExternalStoragePath()
|
| + with device_temp_file.DeviceTempFile(
|
| + self.adb, suffix='.zip', dir=external_dir) as device_temp:
|
| + zip_proc.join()
|
| + self.adb.Push(zip_file.name, device_temp.name)
|
| + quoted_dirs = ' '.join(cmd_helper.SingleQuote(d) for d in dirs)
|
| + self.RunShellCommand(
|
| + 'unzip %s&&chmod -R 777 %s' % (device_temp.name, quoted_dirs),
|
| + as_root=True,
|
| + env={'PATH': '%s:$PATH' % install_commands.BIN_DIR},
|
| + check_return=True)
|
| finally:
|
| if zip_proc.is_alive():
|
| zip_proc.terminate()
|
| - if self.IsOnline():
|
| - self.RunShellCommand(['rm', zip_on_device], check_return=True)
|
| + return True
|
|
|
| @staticmethod
|
| def _CreateDeviceZip(zip_path, host_device_tuples):
|
| @@ -1244,28 +1251,30 @@ class DeviceUtils(object):
|
| """
|
| return self.PathExists(device_path, timeout=timeout, retries=retries)
|
|
|
| - @decorators.WithTimeoutAndRetriesFromInstance()
|
| - def PathExists(self, device_path, timeout=None, retries=None):
|
| - """Checks whether the given path exists on the device.
|
| + def PathExists(self, device_paths, timeout=None, retries=None):
|
| + """Checks whether the given path(s) exists on the device.
|
|
|
| Args:
|
| device_path: A string containing the absolute path to the file on the
|
| - device.
|
| + device, or an iterable of paths to check.
|
| timeout: timeout in seconds
|
| retries: number of retries
|
|
|
| Returns:
|
| - True if the file exists on the device, False otherwise.
|
| + True if the all given paths exist on the device, False otherwise.
|
|
|
| Raises:
|
| CommandTimeoutError on timeout.
|
| DeviceUnreachableError on missing device.
|
| """
|
| - try:
|
| - self.RunShellCommand(['test', '-e', device_path], check_return=True)
|
| - return True
|
| - except device_errors.AdbCommandFailedError:
|
| - return False
|
| + paths = device_paths
|
| + if isinstance(paths, basestring):
|
| + paths = (paths,)
|
| + condition = ' -a '.join('-e %s' % cmd_helper.SingleQuote(p) for p in paths)
|
| + cmd = 'test %s;echo $?' % condition
|
| + result = self.RunShellCommand(cmd, check_return=True, timeout=timeout,
|
| + retries=retries)
|
| + return '0' == result[0]
|
|
|
| @decorators.WithTimeoutAndRetriesFromInstance()
|
| def PullFile(self, device_path, host_path, timeout=None, retries=None):
|
|
|