Android: Add APK patch size estimates to resource_sizes.py.
APK patch size estimates will be used on certain perf builders, and will
track estimated patch size based on a reference APK (built by the same
builder) for the current milestone.
BUG=695188
Review-Url: https://codereview.chromium.org/2757293002
Cr-Commit-Position: refs/heads/master@{#458181}
diff --git a/build/android/binary_size/__init__.py b/build/android/binary_size/__init__.py
new file mode 100644
index 0000000..a22a6ee
--- /dev/null
+++ b/build/android/binary_size/__init__.py
@@ -0,0 +1,3 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
diff --git a/build/android/binary_size/update_apks.py b/build/android/binary_size/apk_downloader.py
similarity index 95%
rename from build/android/binary_size/update_apks.py
rename to build/android/binary_size/apk_downloader.py
index a197e64..b90fe5f 100755
--- a/build/android/binary_size/update_apks.py
+++ b/build/android/binary_size/apk_downloader.py
@@ -23,13 +23,16 @@
def MaybeDownloadApk(builder, milestone, apk, download_path, bucket):
+ """Returns path to the downloaded APK or None if not found."""
apk_path = os.path.join(download_path, builder, milestone, apk)
sha1_path = apk_path + '.sha1'
base_url = os.path.join(bucket, builder, milestone)
if os.path.exists(apk_path):
print '%s already exists' % apk_path
+ return apk_path
elif not os.path.exists(sha1_path):
print 'Skipping %s, file not found' % sha1_path
+ return None
else:
download_from_google_storage.download_from_google_storage(
input_filename=sha1_path,
@@ -46,6 +49,7 @@
verbose=True,
auto_platform=False,
extract=False)
+ return apk_path
def main():
diff --git a/build/android/binary_size/apks/README.md b/build/android/binary_size/apks/README.md
new file mode 100644
index 0000000..474ba93
--- /dev/null
+++ b/build/android/binary_size/apks/README.md
@@ -0,0 +1,24 @@
+### Updating APKs in this folder (for new milestones, builders, or APKs)
+
+1. Find the commit as close as possible to the current branch point (i.e. if the
+latest builds are m59, we want to compare to the commit before the m58 branch
+point).
+
+2. Download and unzip build artifacts from the relevant perf builder. You can
+use this link:
+[https<nolink>://storage.cloud.google.com/chrome-perf/**Android%20Builder**/full-build-linux_**3a87aecc31cd1ffe751dd72c04e5a96a1fc8108a**.zip](https://storage.cloud.google.com/chrome-perf/Android%20Builder/full-build-linux_3a87aecc31cd1ffe751dd72c04e5a96a1fc8108a.zip)
+, replacing the bolded parts with your info OR from the
+"gsutil upload_build_product" step on the bot page (both are Googlers only).
+
+3. Upload the apk: _upload_to_google_storage.py --bucket
+'chromium-android-tools/apks/**Android_Builder**/**58**'
+**path/to/ApkTarget.apk**_ replacing the bolded parts again.
+ * Note that we use **Android_Builder** instead of **Android Builder** (replace
+spaces with underscores)
+
+4. Move the generated .sha1 file to the corresponding place in
+//build/android/binary_size/apks/. In this case, the path would be
+//build/android/binary_size/apks/Android_Builder/58
+
+5. Commit the added .sha1 files and (optionally) update the `CURRENT_MILESTONE`
+in apk_downloader.py
diff --git a/build/android/resource_sizes.py b/build/android/resource_sizes.py
index a0ff3f0..ce0d6de6 100755
--- a/build/android/resource_sizes.py
+++ b/build/android/resource_sizes.py
@@ -23,6 +23,7 @@
import zipfile
import zlib
+from binary_size import apk_downloader
import devil_chromium
from devil.android.sdk import build_tools
from devil.utils import cmd_helper
@@ -35,6 +36,8 @@
_GRIT_PATH = os.path.join(host_paths.DIR_SOURCE_ROOT, 'tools', 'grit')
_BUILD_UTILS_PATH = os.path.join(
host_paths.DIR_SOURCE_ROOT, 'build', 'android', 'gyp')
+_APK_PATCH_SIZE_ESTIMATOR_PATH = os.path.join(
+ host_paths.DIR_SOURCE_ROOT, 'third_party', 'apk-patch-size-estimator')
# Prepend the grit module from the source tree so it takes precedence over other
# grit versions that might present in the search path.
@@ -47,6 +50,9 @@
with host_paths.SysPath(_BUILD_UTILS_PATH, 1):
from util import build_utils # pylint: disable=import-error
+with host_paths.SysPath(_APK_PATCH_SIZE_ESTIMATOR_PATH):
+ import apk_patch_size_estimator # pylint: disable=import-error
+
# Python had a bug in zipinfo parsing that triggers on ChromeModern.apk
# https://bugs.python.org/issue14315
@@ -674,6 +680,26 @@
'bytes')
+def _PrintPatchSizeEstimate(new_apk, builder, bucket, chartjson=None):
+ apk_name = os.path.basename(new_apk)
+ title = apk_name + '_PatchSizeEstimate'
+ # Reference APK paths have spaces replaced by underscores.
+ builder = builder.replace(' ', '_')
+ old_apk = apk_downloader.MaybeDownloadApk(
+ builder, apk_downloader.CURRENT_MILESTONE, apk_name,
+ apk_downloader.DEFAULT_DOWNLOAD_PATH, bucket)
+ if old_apk:
+ # Use a temp dir in case patch size functions fail to clean up temp files.
+ with build_utils.TempDir() as tmp:
+ tmp_name = os.path.join(tmp, 'patch.tmp')
+ bsdiff = apk_patch_size_estimator.calculate_bsdiff(
+ old_apk, new_apk, None, tmp_name)
+ ReportPerfResult(chartjson, title, 'BSDiff (gzipped)', bsdiff, 'bytes')
+ fbf = apk_patch_size_estimator.calculate_filebyfile(
+ old_apk, new_apk, None, tmp_name)
+ ReportPerfResult(chartjson, title, 'FileByFile (gzipped)', fbf, 'bytes')
+
+
@contextmanager
def Unzip(zip_file, filename=None):
"""Utility for temporary use of a single file in a zip archive."""
@@ -712,6 +738,17 @@
'output-dir')
argparser.add_argument('-d', '--device',
help='Dummy option for perf runner.')
+ argparser.add_argument('--estimate-patch-size', action='store_true',
+ help='Include patch size estimates. Useful for perf '
+ 'builders where a reference APK is available but adds '
+ '~3 mins to run time.')
+ argparser.add_argument('--reference-apk-builder',
+ default=apk_downloader.DEFAULT_BUILDER,
+ help='Builder name to use for reference APK for patch '
+ 'size estimates.')
+ argparser.add_argument('--reference-apk-bucket',
+ default=apk_downloader.DEFAULT_BUCKET,
+ help='Storage bucket holding reference APKs.')
argparser.add_argument('apk', help='APK file path.')
args = argparser.parse_args()
@@ -730,6 +767,9 @@
PrintApkAnalysis(args.apk, tools_prefix, chartjson=chartjson)
_PrintDexAnalysis(args.apk, chartjson=chartjson)
+ if args.estimate_patch_size:
+ _PrintPatchSizeEstimate(
+ args.apk, args.builder, args.bucket, chartjson=chartjson)
if not args.no_output_dir:
PrintPakAnalysis(args.apk, args.min_pak_resource_size)
_PrintStaticInitializersCountFromApk(
diff --git a/third_party/apk-patch-size-estimator/README.chromium b/third_party/apk-patch-size-estimator/README.chromium
index 67e9c73..6ed5efee5 100644
--- a/third_party/apk-patch-size-estimator/README.chromium
+++ b/third_party/apk-patch-size-estimator/README.chromium
@@ -12,4 +12,5 @@
for more details.
Local Modifications:
-Removed the following files: CONTRIBUTING.md, tests/, images/.
+- Removed the following files: CONTRIBUTING.md, tests/, images/.
+- Changed file-by-file-tools.jar path to be absolute instead of relative.
diff --git a/third_party/apk-patch-size-estimator/apk_patch_size_estimator.py b/third_party/apk-patch-size-estimator/apk_patch_size_estimator.py
index 1be08e7..64b4bb6 100755
--- a/third_party/apk-patch-size-estimator/apk_patch_size_estimator.py
+++ b/third_party/apk-patch-size-estimator/apk_patch_size_estimator.py
@@ -36,6 +36,9 @@
import os
import subprocess
+_FILEBYFILE_JAR_PATH = os.path.abspath(
+ os.path.join(os.path.dirname(__file__), 'lib', 'file-by-file-tools.jar'))
+
bsdiff_path = None
gzip_path = None
head_path = None
@@ -259,8 +262,8 @@
# We use a jar from https://github.com/andrewhayden/archive-patcher
if os.path.exists(filebyfile_patch_path): os.remove(filebyfile_patch_path)
p = subprocess.Popen(
- [java_path, '-jar', 'lib/file-by-file-tools.jar', '--generate',
- '--old', old_file, '--new', new_file, '--patch', filebyfile_patch_path],
+ [java_path, '-jar', _FILEBYFILE_JAR_PATH, '--generate', '--old', old_file,
+ '--new', new_file, '--patch', filebyfile_patch_path],
shell=False)
ret_code = p.wait()
if ret_code != 0: raise Exception(