| Index: build/android/pylib/android_commands.py
|
| diff --git a/build/android/pylib/android_commands.py b/build/android/pylib/android_commands.py
|
| index 48116b88ffd8e7e7a889ea679ff99e55569e702c..6b97ec270f326d434d38a5fa43434d485cc3746d 100644
|
| --- a/build/android/pylib/android_commands.py
|
| +++ b/build/android/pylib/android_commands.py
|
| @@ -61,10 +61,6 @@ KEYCODE_DPAD_RIGHT = 22
|
| KEYCODE_ENTER = 66
|
| KEYCODE_MENU = 82
|
|
|
| -MD5SUM_DEVICE_FOLDER = constants.TEST_EXECUTABLE_DIR + '/md5sum/'
|
| -MD5SUM_DEVICE_PATH = MD5SUM_DEVICE_FOLDER + 'md5sum_bin'
|
| -MD5SUM_LD_LIBRARY_PATH = 'LD_LIBRARY_PATH=%s' % MD5SUM_DEVICE_FOLDER
|
| -
|
| def GetEmulators():
|
| """Returns a list of emulators. Does not filter by status (e.g. offline).
|
|
|
| @@ -176,6 +172,21 @@ def _ComputeFileListHash(md5sum_output):
|
| return [line.split(' ')[0] for line in md5sum_output]
|
|
|
|
|
| +def _ComputeFileListTimesModified(timemodified_output):
|
| + """Returns a list of tuples from the provided timemodified output.
|
| +
|
| + Args:
|
| + timemodified_output: output directly from timemodified binary.
|
| +
|
| + Returns:
|
| + List of namedtuples (time, path).
|
| + """
|
| + TimeAndPath = collections.namedtuple('TimeAndPath', ['time', 'path'])
|
| + split_lines = [line.split(' ') for line in timemodified_output]
|
| + assert all(len(s) == 2 for s in split_lines), 'Invalid timemodified output'
|
| + return [TimeAndPath._make(s) for s in split_lines]
|
| +
|
| +
|
| def _HasAdbPushSucceeded(command_output):
|
| """Returns whether adb push has succeeded from the provided output."""
|
| # TODO(frankf): We should look at the return code instead of the command
|
| @@ -225,6 +236,7 @@ class AndroidCommands(object):
|
| self._potential_push_size = 0
|
| self._actual_push_size = 0
|
| self._md5sum_build_dir = ''
|
| + self._timemodified_build_dir = ''
|
| self._external_storage = ''
|
| self._util_wrapper = ''
|
|
|
| @@ -712,6 +724,9 @@ class AndroidCommands(object):
|
| Returns:
|
| True if the md5sums match.
|
| """
|
| + MD5SUM_DEVICE_FOLDER = constants.TEST_EXECUTABLE_DIR + '/md5sum/'
|
| + MD5SUM_DEVICE_PATH = MD5SUM_DEVICE_FOLDER + 'md5sum_bin'
|
| + MD5SUM_LD_LIBRARY_PATH = 'LD_LIBRARY_PATH=%s' % MD5SUM_DEVICE_FOLDER
|
| if not self._md5sum_build_dir:
|
| default_build_type = os.environ.get('BUILD_TYPE', 'Debug')
|
| build_dir = '%s/%s/' % (
|
| @@ -740,11 +755,81 @@ class AndroidCommands(object):
|
|
|
| return hashes_on_device == hashes_on_host
|
|
|
| + def _AreFilesUnsynchronized(self, local_path, device_path):
|
| + """Compares the time modified of a local path against a device path.
|
| +
|
| + NOTE: Files transferred via "adb push" keep the host's modified time.
|
| +
|
| + Args:
|
| + local_path: Path (file or directory) on the host.
|
| + device_path: Path (file or directory) on the device.
|
| +
|
| + Returns:
|
| + True if the time the files were modified match.
|
| + """
|
| + TIMEMODIFIED_DEVICE_DIRECTORY = (constants.TEST_EXECUTABLE_DIR +
|
| + '/timemodified/')
|
| + TIMEMODIFIED_DEVICE_PATH = (TIMEMODIFIED_DEVICE_DIRECTORY +
|
| + 'timemodified_bin')
|
| + TIMEMODIFIED_LD_LIBRARY_PATH = ('LD_LIBRARY_PATH=%s' %
|
| + TIMEMODIFIED_DEVICE_DIRECTORY)
|
| + assert os.path.exists(local_path), 'Local path not found %s' % local_path
|
| +
|
| + if not self._timemodified_build_dir:
|
| + default_build_type = os.environ.get('BUILD_TYPE', 'Debug')
|
| + build_dir = '%s/%s/' % (
|
| + cmd_helper.OutDirectory().get(), default_build_type)
|
| + host_timemodified_dist_path = '%s/timemodified_dist' % build_dir
|
| + if not os.path.exists(host_timemodified_dist_path):
|
| + build_dir = '%s/Release/' % cmd_helper.OutDirectory().get()
|
| + host_timemodified_dist_path = '%s/timemodified_dist' % build_dir
|
| + assert os.path.exists(host_timemodified_dist_path), 'Build timemodified'
|
| + command = 'push %s %s' % (host_timemodified_dist_path,
|
| + TIMEMODIFIED_DEVICE_DIRECTORY)
|
| + assert _HasAdbPushSucceeded(self._adb.SendCommand(command))
|
| + self._timemodified_build_dir = build_dir
|
| +
|
| + self._pushed_files.append(device_path)
|
| + device_timemodified_output = self.RunShellCommand(
|
| + TIMEMODIFIED_LD_LIBRARY_PATH + ' ' + self._util_wrapper + ' ' +
|
| + TIMEMODIFIED_DEVICE_PATH + ' ' + device_path)
|
| + device_time_tuples = _ComputeFileListTimesModified(
|
| + device_timemodified_output)
|
| + assert os.path.exists(local_path), 'Local path not found %s' % local_path
|
| + host_timemodified_output = cmd_helper.GetCmdOutput(
|
| + ['%s/timemodified_bin_host' % self._timemodified_build_dir, local_path])
|
| + host_time_tuples = _ComputeFileListTimesModified(
|
| + host_timemodified_output.splitlines())
|
| +
|
| + if len(device_time_tuples) < len(host_time_tuples):
|
| + return True
|
| +
|
| + # Ignore extra files on the device.
|
| + if len(device_time_tuples) > len(host_time_tuples):
|
| + host_files = [os.path.relpath(os.path.normpath(p.path),
|
| + os.path.normpath(local_path)) for p in host_time_tuples]
|
| +
|
| + def _host_has(fname):
|
| + return any(path in fname for path in host_files)
|
| +
|
| + times_on_device = [t.time for t in device_time_tuples if
|
| + _host_has(t.path)]
|
| + else:
|
| + times_on_device = [t.time for t in device_time_tuples]
|
| +
|
| + # Compare timestamps between host and device files.
|
| + times_on_host = [t.time for t in host_time_tuples]
|
| + times_on_device.sort()
|
| + times_on_host.sort()
|
| + return any(int(dtime) != int(htime) for dtime, htime in
|
| + zip(times_on_device, times_on_host))
|
| +
|
| def PushIfNeeded(self, local_path, device_path):
|
| """Pushes |local_path| to |device_path|.
|
|
|
| Works for files and directories. This method skips copying any paths in
|
| - |test_data_paths| that already exist on the device with the same hash.
|
| + |test_data_paths| that already exist on the device with the same modified
|
| + time.
|
|
|
| All pushed files can be removed by calling RemovePushedFiles().
|
| """
|
| @@ -753,7 +838,7 @@ class AndroidCommands(object):
|
| self._pushed_files.append(device_path)
|
| self._potential_push_size += size
|
|
|
| - if self.CheckMd5Sum(local_path, device_path):
|
| + if not self._AreFilesUnsynchronized(local_path, device_path):
|
| return
|
|
|
| self._actual_push_size += size
|
| @@ -1305,7 +1390,7 @@ class AndroidCommands(object):
|
|
|
| def SetUtilWrapper(self, util_wrapper):
|
| """Sets a wrapper prefix to be used when running a locally-built
|
| - binary on the device (ex.: md5sum_bin).
|
| + binary on the device (ex.: timemodified_bin).
|
| """
|
| self._util_wrapper = util_wrapper
|
|
|
|
|