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

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

Issue 1375043002: Speed up incremental_install by caching device checksums between runs. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@device-utils-brace-fix
Patch Set: rebase Created 5 years, 2 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
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
11 import collections 11 import collections
12 import itertools 12 import itertools
13 import json
13 import logging 14 import logging
14 import multiprocessing 15 import multiprocessing
15 import os 16 import os
16 import posixpath 17 import posixpath
17 import re 18 import re
18 import shutil 19 import shutil
19 import tempfile 20 import tempfile
20 import time 21 import time
21 import zipfile 22 import zipfile
22 23
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after
156 _MAX_ADB_OUTPUT_LENGTH = 32768 157 _MAX_ADB_OUTPUT_LENGTH = 32768
157 _LAUNCHER_FOCUSED_RE = re.compile( 158 _LAUNCHER_FOCUSED_RE = re.compile(
158 r'\s*mCurrentFocus.*(Launcher|launcher).*') 159 r'\s*mCurrentFocus.*(Launcher|launcher).*')
159 _VALID_SHELL_VARIABLE = re.compile('^[a-zA-Z_][a-zA-Z0-9_]*$') 160 _VALID_SHELL_VARIABLE = re.compile('^[a-zA-Z_][a-zA-Z0-9_]*$')
160 161
161 LOCAL_PROPERTIES_PATH = posixpath.join('/', 'data', 'local.prop') 162 LOCAL_PROPERTIES_PATH = posixpath.join('/', 'data', 'local.prop')
162 163
163 # Property in /data/local.prop that controls Java assertions. 164 # Property in /data/local.prop that controls Java assertions.
164 JAVA_ASSERT_PROPERTY = 'dalvik.vm.enableassertions' 165 JAVA_ASSERT_PROPERTY = 'dalvik.vm.enableassertions'
165 166
166 def __init__(self, device, default_timeout=_DEFAULT_TIMEOUT, 167 def __init__(self, device, enable_device_files_cache=False,
jbudorick 2015/10/01 17:15:26 Document this parameter.
agrieve 2015/10/01 18:30:16 Done.
168 default_timeout=_DEFAULT_TIMEOUT,
167 default_retries=_DEFAULT_RETRIES): 169 default_retries=_DEFAULT_RETRIES):
168 """DeviceUtils constructor. 170 """DeviceUtils constructor.
169 171
170 Args: 172 Args:
171 device: Either a device serial, an existing AdbWrapper instance, or an 173 device: Either a device serial, an existing AdbWrapper instance, or an
172 an existing AndroidCommands instance. 174 an existing AndroidCommands instance.
173 default_timeout: An integer containing the default number of seconds to 175 default_timeout: An integer containing the default number of seconds to
174 wait for an operation to complete if no explicit value 176 wait for an operation to complete if no explicit value
175 is provided. 177 is provided.
176 default_retries: An integer containing the default number or times an 178 default_retries: An integer containing the default number or times an
177 operation should be retried on failure if no explicit 179 operation should be retried on failure if no explicit
178 value is provided. 180 value is provided.
179 """ 181 """
180 self.adb = None 182 self.adb = None
181 if isinstance(device, basestring): 183 if isinstance(device, basestring):
182 self.adb = adb_wrapper.AdbWrapper(device) 184 self.adb = adb_wrapper.AdbWrapper(device)
183 elif isinstance(device, adb_wrapper.AdbWrapper): 185 elif isinstance(device, adb_wrapper.AdbWrapper):
184 self.adb = device 186 self.adb = device
185 else: 187 else:
186 raise ValueError('Unsupported device value: %r' % device) 188 raise ValueError('Unsupported device value: %r' % device)
187 self._commands_installed = None 189 self._commands_installed = None
188 self._default_timeout = default_timeout 190 self._default_timeout = default_timeout
189 self._default_retries = default_retries 191 self._default_retries = default_retries
192 self._enable_device_files_cache = enable_device_files_cache
190 self._cache = {} 193 self._cache = {}
191 self._client_caches = {} 194 self._client_caches = {}
192 assert hasattr(self, decorators.DEFAULT_TIMEOUT_ATTR) 195 assert hasattr(self, decorators.DEFAULT_TIMEOUT_ATTR)
193 assert hasattr(self, decorators.DEFAULT_RETRIES_ATTR) 196 assert hasattr(self, decorators.DEFAULT_RETRIES_ATTR)
194 197
195 self._ClearCache() 198 self._ClearCache()
196 199
197 def __eq__(self, other): 200 def __eq__(self, other):
198 """Checks whether |other| refers to the same device as |self|. 201 """Checks whether |other| refers to the same device as |self|.
199 202
(...skipping 895 matching lines...) Expand 10 before | Expand all | Expand 10 after
1095 track_stale: whether to bother looking for stale files (slower) 1098 track_stale: whether to bother looking for stale files (slower)
1096 1099
1097 Returns: 1100 Returns:
1098 a three-element tuple 1101 a three-element tuple
1099 1st element: a list of (host_files_path, device_files_path) tuples to push 1102 1st element: a list of (host_files_path, device_files_path) tuples to push
1100 2nd element: a list of host_files_path that are up-to-date 1103 2nd element: a list of host_files_path that are up-to-date
1101 3rd element: a list of stale files under device_path, or [] when 1104 3rd element: a list of stale files under device_path, or [] when
1102 track_stale == False 1105 track_stale == False
1103 """ 1106 """
1104 try: 1107 try:
1105 host_checksums = md5sum.CalculateHostMd5Sums([host_path]) 1108 specific_device_paths = [device_path]
1106 interesting_device_paths = [device_path] 1109 ignore_other_files = not track_stale and os.path.isdir(host_path)
1107 if not track_stale and os.path.isdir(host_path): 1110 if ignore_other_files:
1108 interesting_device_paths = [ 1111 specific_device_paths = []
1109 posixpath.join(device_path, os.path.relpath(p, host_path)) 1112 for root, _, filenames in os.walk(host_path):
1110 for p in host_checksums.keys()] 1113 relative_dir = root[len(host_path) + 1:]
1111 device_checksums = md5sum.CalculateDeviceMd5Sums( 1114 specific_device_paths.extend(
1112 interesting_device_paths, self) 1115 posixpath.join(device_path, relative_dir, f) for f in filenames)
1116
1117 def device_sums_helper():
1118 if self._enable_device_files_cache:
1119 cache_entry = self._cache['device_path_checksums'].get(device_path)
1120 if cache_entry and cache_entry[0] == ignore_other_files:
1121 return dict(cache_entry[1])
1122
1123 sums = md5sum.CalculateDeviceMd5Sums(specific_device_paths, self)
1124
1125 if self._enable_device_files_cache:
1126 cache_entry = [ignore_other_files, sums]
1127 self._cache['device_path_checksums'][device_path] = cache_entry
1128 return dict(sums)
1129
1130 host_checksums, device_checksums = reraiser_thread.RunAsync((
1131 lambda: md5sum.CalculateHostMd5Sums([host_path]),
1132 device_sums_helper))
1113 except EnvironmentError as e: 1133 except EnvironmentError as e:
1114 logging.warning('Error calculating md5: %s', e) 1134 logging.warning('Error calculating md5: %s', e)
1115 return ([(host_path, device_path)], [], []) 1135 return ([(host_path, device_path)], [], [])
1116 1136
1117 to_push = [] 1137 to_push = []
1118 up_to_date = [] 1138 up_to_date = []
1119 to_delete = [] 1139 to_delete = []
1120 if os.path.isfile(host_path): 1140 if os.path.isfile(host_path):
1121 host_checksum = host_checksums.get(host_path) 1141 host_checksum = host_checksums.get(host_path)
1122 device_checksum = device_checksums.get(device_path) 1142 device_checksum = device_checksums.get(device_path)
(...skipping 787 matching lines...) Expand 10 before | Expand all | Expand 10 after
1910 """Clears all caches.""" 1930 """Clears all caches."""
1911 for client in self._client_caches: 1931 for client in self._client_caches:
1912 self._client_caches[client].clear() 1932 self._client_caches[client].clear()
1913 self._cache = { 1933 self._cache = {
1914 # Map of packageId -> list of on-device .apk paths 1934 # Map of packageId -> list of on-device .apk paths
1915 'package_apk_paths': {}, 1935 'package_apk_paths': {},
1916 # Map of packageId -> set of on-device .apk checksums 1936 # Map of packageId -> set of on-device .apk checksums
1917 'package_apk_checksums': {}, 1937 'package_apk_checksums': {},
1918 # Map of property_name -> value 1938 # Map of property_name -> value
1919 'getprop': {}, 1939 'getprop': {},
1940 # Map of device_path -> [ignore_other_files, map of path->checksum]
jbudorick 2015/10/01 17:15:26 Isn't this just a map of device_path -> checksum?
agrieve 2015/10/01 18:30:16 The comment is correct. The reason it's not a map
1941 'device_path_checksums': {},
1920 } 1942 }
1921 1943
1944 def LoadCacheData(self, data):
1945 """Initializes the cache from data created using DumpCacheData."""
1946 obj = json.loads(data)
1947 self._cache['package_apk_paths'] = obj.get('package_apk_paths', {})
1948 package_apk_checksums = obj.get('package_apk_checksums', {})
1949 for k, v in package_apk_checksums.iteritems():
1950 package_apk_checksums[k] = set(v)
1951 self._cache['package_apk_checksums'] = package_apk_checksums
1952 device_path_checksums = obj.get('device_path_checksums', {})
1953 self._cache['device_path_checksums'] = device_path_checksums
1954
1955 def DumpCacheData(self):
1956 """Dumps the current cache state to a string."""
1957 obj = {}
1958 obj['package_apk_paths'] = self._cache['package_apk_paths']
1959 obj['package_apk_checksums'] = self._cache['package_apk_checksums']
1960 # JSON can't handle sets.
1961 for k, v in obj['package_apk_checksums'].iteritems():
1962 obj['package_apk_checksums'][k] = list(v)
1963 obj['device_path_checksums'] = self._cache['device_path_checksums']
1964 return json.dumps(obj, separators=(',', ':'))
1965
1922 @classmethod 1966 @classmethod
1923 def parallel(cls, devices, async=False): 1967 def parallel(cls, devices, async=False):
1924 """Creates a Parallelizer to operate over the provided list of devices. 1968 """Creates a Parallelizer to operate over the provided list of devices.
1925 1969
1926 If |devices| is either |None| or an empty list, the Parallelizer will 1970 If |devices| is either |None| or an empty list, the Parallelizer will
1927 operate over all attached devices that have not been blacklisted. 1971 operate over all attached devices that have not been blacklisted.
1928 1972
1929 Args: 1973 Args:
1930 devices: A list of either DeviceUtils instances or objects from 1974 devices: A list of either DeviceUtils instances or objects from
1931 from which DeviceUtils instances can be constructed. If None, 1975 from which DeviceUtils instances can be constructed. If None,
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
1979 if ('android.permission.WRITE_EXTERNAL_STORAGE' in permissions 2023 if ('android.permission.WRITE_EXTERNAL_STORAGE' in permissions
1980 and 'android.permission.READ_EXTERNAL_STORAGE' not in permissions): 2024 and 'android.permission.READ_EXTERNAL_STORAGE' not in permissions):
1981 permissions.append('android.permission.READ_EXTERNAL_STORAGE') 2025 permissions.append('android.permission.READ_EXTERNAL_STORAGE')
1982 cmd = ';'.join('pm grant %s %s' %(package, p) for p in permissions) 2026 cmd = ';'.join('pm grant %s %s' %(package, p) for p in permissions)
1983 if cmd: 2027 if cmd:
1984 output = self.RunShellCommand(cmd) 2028 output = self.RunShellCommand(cmd)
1985 if output: 2029 if output:
1986 logging.warning('Possible problem when granting permissions. Blacklist ' 2030 logging.warning('Possible problem when granting permissions. Blacklist '
1987 'may need to be updated.') 2031 'may need to be updated.')
1988 logging.warning(output) 2032 logging.warning(output)
OLDNEW
« no previous file with comments | « no previous file | build/android/incremental_install/installer.py » ('j') | build/android/incremental_install/installer.py » ('J')

Powered by Google App Engine
This is Rietveld 408576698