blob: 7b80b5755e37a9453593c0bd2ce225476456905a [file] [log] [blame]
Søren Gjessecdae8792018-12-12 09:02:43 +01001#!/usr/bin/env python
2# Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
3# for details. All rights reserved. Use of this source code is governed by a
4# BSD-style license that can be found in the LICENSE file.
5
Christoffer Quist Adamsen4038bbe2019-01-15 14:31:46 +01006import apk_masseur
Søren Gjessecdae8792018-12-12 09:02:43 +01007import apk_utils
Morten Krogh-Jespersenc2fbde22019-02-07 13:59:55 +01008import golem
Søren Gjesseeed839d2019-01-11 15:19:16 +01009import gradle
Ian Zerny3f54e222019-02-12 10:51:17 +010010import jdk
Christoffer Quist Adamsen2a902752019-02-19 12:33:48 +010011import json
Søren Gjessecdae8792018-12-12 09:02:43 +010012import os
13import optparse
Christoffer Quist Adamsenbbe5d7d2019-01-23 13:15:21 +010014import shutil
Søren Gjessecdae8792018-12-12 09:02:43 +010015import subprocess
16import sys
Christoffer Quist Adamsen1d0a0fe2018-12-21 14:28:56 +010017import time
Søren Gjessecdae8792018-12-12 09:02:43 +010018import utils
Christoffer Quist Adamsen404aade2018-12-20 13:00:09 +010019import zipfile
Christoffer Quist Adamsen7cf4c562019-03-07 10:57:33 +010020from xml.dom import minidom
Søren Gjessecdae8792018-12-12 09:02:43 +010021
Christoffer Quist Adamsen10b7db82018-12-13 14:50:38 +010022import as_utils
Christoffer Quist Adamsen2a902752019-02-19 12:33:48 +010023import update_prebuilds_in_android
Rico Windbc7cab02019-04-04 12:22:09 +020024import download_all_benchmark_dependencies
Christoffer Quist Adamsen10b7db82018-12-13 14:50:38 +010025
Morten Krogh-Jespersend45d95e2019-02-07 13:27:17 +010026SHRINKERS = ['r8', 'r8-full', 'r8-nolib', 'r8-nolib-full', 'pg']
Morten Krogh-Jespersen64740202019-02-07 13:06:04 +010027WORKING_DIR = os.path.join(utils.BUILD, 'opensource_apps')
Christoffer Quist Adamsen10b7db82018-12-13 14:50:38 +010028
Morten Krogh-Jespersenaeb665e2019-02-07 12:29:03 +010029if ('R8_BENCHMARK_DIR' in os.environ
30 and os.path.isdir(os.environ['R8_BENCHMARK_DIR'])):
Christoffer Quist Adamsen10b7db82018-12-13 14:50:38 +010031 WORKING_DIR = os.environ['R8_BENCHMARK_DIR']
Søren Gjessecdae8792018-12-12 09:02:43 +010032
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +010033class Repo(object):
34 def __init__(self, fields):
35 self.__dict__ = fields
36
37 # If there is only one app in this repository, then give the app the same
38 # name as the repository, if it does not already have one.
39 if len(self.apps) == 1:
40 app = self.apps[0]
41 if not app.name:
42 app.name = self.name
43
44class App(object):
45 def __init__(self, fields):
46 module = fields.get('module', 'app')
47 defaults = {
48 'archives_base_name': module,
49 'build_dir': 'build',
50 'compile_sdk': None,
51 'dir': '.',
52 'flavor': None,
Christoffer Quist Adamsen7cf4c562019-03-07 10:57:33 +010053 'has_instrumentation_tests': False,
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +010054 'main_dex_rules': None,
55 'module': module,
56 'min_sdk': None,
57 'name': None,
58 'releaseTarget': None,
59 'signed_apk_name': None,
60 'skip': False
61 }
62 self.__dict__ = dict(defaults.items() + fields.items())
63
64# For running on Golem all third-party repositories are bundled as an x20-
65# dependency and then copied to WORKING_DIR. To update the app-bundle use
66# 'run_on_as_app_x20_packager.py'.
67APP_REPOSITORIES = [
68 # ...
69 # Repo({
70 # 'name': ...,
71 # 'url': ...,
Morten Krogh-Jespersene0ce6a32019-02-07 11:44:45 +010072 # 'revision': ...,
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +010073 # 'apps': [
74 # {
75 # 'id': ...,
76 # 'dir': ...,
77 # 'module': ... (default app)
78 # 'name': ...,
79 # 'archives_base_name': ... (default same as module)
80 # 'flavor': ... (default no flavor)
81 # 'releaseTarget': ... (default <module>:assemble<flavor>Release
82 # },
83 # ...
84 # ]
85 # }),
86 # ...
87 Repo({
88 'name': 'android-suite',
89 'url': 'https://github.com/christofferqa/android-suite',
90 'revision': '46c96f214711cf6cdcb72cc0c94520ef418e3739',
91 'apps': [
92 App({
93 'id': 'com.numix.calculator',
94 'dir': 'Calculator',
Christoffer Quist Adamsen7cf4c562019-03-07 10:57:33 +010095 'name': 'numix-calculator',
Jinseong Jeonf1e27572019-04-22 10:44:14 -070096 'has_instrumentation_tests': True
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +010097 })
98 ]
99 }),
100 Repo({
101 'name': 'AnExplorer',
102 'url': 'https://github.com/christofferqa/AnExplorer',
Morten Krogh-Jespersene0ce6a32019-02-07 11:44:45 +0100103 'revision': '365927477b8eab4052a1882d5e358057ae3dee4d',
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100104 'apps': [
105 App({
106 'id': 'dev.dworks.apps.anexplorer.pro',
107 'flavor': 'googleMobilePro',
108 'signed_apk_name': 'AnExplorer-googleMobileProRelease-4.0.3.apk',
109 'min_sdk': 17
110 })
111 ]
112 }),
113 Repo({
114 'name': 'AntennaPod',
115 'url': 'https://github.com/christofferqa/AntennaPod.git',
Morten Krogh-Jespersene0ce6a32019-02-07 11:44:45 +0100116 'revision': '77e94f4783a16abe9cc5b78dc2d2b2b1867d8c06',
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100117 'apps': [
118 App({
119 'id': 'de.danoeh.antennapod',
120 'flavor': 'play',
121 'min_sdk': 14,
122 'compile_sdk': 26
123 })
124 ]
125 }),
126 Repo({
Morten Krogh-Jespersen2af7daa2019-03-11 13:50:42 +0100127 'name': 'applymapping',
128 'url': 'https://github.com/mkj-gram/applymapping',
Christoffer Quist Adamsene4ef1452019-03-13 10:38:00 +0100129 'revision': 'e3ae14b8c16fa4718e5dea8f7ad00937701b3c48',
Morten Krogh-Jespersen2af7daa2019-03-11 13:50:42 +0100130 'apps': [
131 App({
132 'id': 'com.example.applymapping',
133 'has_instrumentation_tests': True
134 })
135 ]
136 }),
137 Repo({
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100138 'name': 'apps-android-wikipedia',
139 'url': 'https://github.com/christofferqa/apps-android-wikipedia',
Morten Krogh-Jespersene0ce6a32019-02-07 11:44:45 +0100140 'revision': '686e8aa5682af8e6a905054b935dd2daa57e63ee',
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100141 'apps': [
142 App({
143 'id': 'org.wikipedia',
144 'flavor': 'prod',
145 'signed_apk_name': 'app-prod-universal-release.apk'
146 })
147 ]
148 }),
149 Repo({
150 'name': 'chanu',
151 'url': 'https://github.com/mkj-gram/chanu.git',
Morten Krogh-Jespersen42fa5cf2019-03-19 14:06:12 +0100152 'revision': '6e53458f167b6d78398da60c20fd0da01a232617',
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100153 'apps': [
154 App({
155 'id': 'com.chanapps.four.activity'
156 })
157 ]
158 }),
159 Repo({
160 'name': 'friendlyeats-android',
161 'url': 'https://github.com/christofferqa/friendlyeats-android.git',
Morten Krogh-Jespersene0ce6a32019-02-07 11:44:45 +0100162 'revision': '10091fa0ec37da12e66286559ad1b6098976b07b',
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100163 'apps': [
164 App({
165 'id': 'com.google.firebase.example.fireeats'
166 })
167 ]
168 }),
169 Repo({
Christoffer Quist Adamsena45e26d2019-05-10 19:08:27 +0200170 'name': 'googlesamples',
171 'url': 'https://github.com/christofferqa/android-sunflower.git',
172 'revision': 'df0a082a0bcbeae253817e13daca3c7a7c54f67a',
173 'apps': [
174 App({
175 'id': 'com.google.samples.apps.sunflower',
176 'name': 'android-sunflower',
177 'min_sdk': 19,
178 'compile_sdk': 28
179 })
180 ]
181 }),
182 Repo({
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100183 'name': 'Instabug-Android',
184 'url': 'https://github.com/christofferqa/Instabug-Android.git',
185 'revision': 'b8df78c96630a6537fbc07787b4990afc030cc0f',
186 'apps': [
187 App({
188 'id': 'com.example.instabug'
189 })
190 ]
191 }),
192 Repo({
193 'name': 'KISS',
194 'url': 'https://github.com/christofferqa/KISS',
Morten Krogh-Jespersene0ce6a32019-02-07 11:44:45 +0100195 'revision': '093da9ee0512e67192f62951c45a07a616fc3224',
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100196 'apps': [
197 App({
198 'id': 'fr.neamar.kiss'
199 })
200 ]
201 }),
202 Repo({
203 'name': 'materialistic',
204 'url': 'https://github.com/christofferqa/materialistic',
Morten Krogh-Jespersene0ce6a32019-02-07 11:44:45 +0100205 'revision': '2b2b2ee25ce9e672d5aab1dc90a354af1522b1d9',
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100206 'apps': [
207 App({
208 'id': 'io.github.hidroh.materialistic'
209 })
210 ]
211 }),
212 Repo({
213 'name': 'Minimal-Todo',
214 'url': 'https://github.com/christofferqa/Minimal-Todo',
Morten Krogh-Jespersene0ce6a32019-02-07 11:44:45 +0100215 'revision': '9d8c73746762cd376b718858ec1e8783ca07ba7c',
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100216 'apps': [
217 App({
218 'id': 'com.avjindersinghsekhon.minimaltodo'
219 })
220 ]
221 }),
222 Repo({
Christoffer Quist Adamsen493acd82019-03-14 12:20:02 +0100223 'name': 'muzei',
224 'url': 'https://github.com/sgjesse/muzei.git',
Christoffer Quist Adamsenf6e08b82019-04-11 10:36:07 +0200225 'revision': 'a1f1d9b119faa0db09b6bbffe2318c4ec3679418',
Christoffer Quist Adamsen493acd82019-03-14 12:20:02 +0100226 'apps': [
227 App({
228 'id': 'net.nurik.roman.muzei',
229 'module': 'main',
230 'archives_base_name': 'muzei',
Morten Krogh-Jespersen137e7322019-04-06 09:47:13 +0200231 'compile_sdk': 28,
Christoffer Quist Adamsen493acd82019-03-14 12:20:02 +0100232 })
233 ]
234 }),
235 Repo({
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100236 'name': 'NewPipe',
237 'url': 'https://github.com/christofferqa/NewPipe',
Morten Krogh-Jespersene0ce6a32019-02-07 11:44:45 +0100238 'revision': 'ed543099c7823be00f15d9340f94bdb7cb37d1e6',
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100239 'apps': [
240 App({
241 'id': 'org.schabi.newpipe'
242 })
243 ]
244 }),
245 Repo({
246 'name': 'rover-android',
247 'url': 'https://github.com/mkj-gram/rover-android.git',
Morten Krogh-Jespersen81bf5ab2019-03-11 13:33:16 +0100248 'revision': 'a5e155a1ed7d19b1cecd9a7b075e2852623a06bf',
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100249 'apps': [
250 App({
251 'id': 'io.rover.app.debug',
252 'module': 'debug-app'
253 })
254 ]
255 }),
256 Repo({
257 'name': 'Signal-Android',
258 'url': 'https://github.com/mkj-gram/Signal-Android.git',
Morten Krogh-Jespersen81bf5ab2019-03-11 13:33:16 +0100259 'revision': 'cd542cab9bf860e71504ecb1caaf0a8476ba3989',
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100260 'apps': [
261 App({
262 'id': 'org.thoughtcrime.securesms',
263 'module': '',
264 'flavor': 'play',
265 'main_dex_rules': 'multidex-config.pro',
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100266 'signed_apk_name': 'Signal-play-release-4.32.7.apk'
267 })
268 ]
269 }),
270 Repo({
271 'name': 'Simple-Calendar',
272 'url': 'https://github.com/christofferqa/Simple-Calendar',
Morten Krogh-Jespersene0ce6a32019-02-07 11:44:45 +0100273 'revision': '82dad8c203eea5a0f0ddb513506d8f1de986ef2b',
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100274 'apps': [
275 App({
276 'id': 'com.simplemobiletools.calendar.pro',
277 'signed_apk_name': 'calendar-release.apk'
278 })
279 ]
280 }),
281 Repo({
282 'name': 'sqldelight',
283 'url': 'https://github.com/christofferqa/sqldelight.git',
Morten Krogh-Jespersene0ce6a32019-02-07 11:44:45 +0100284 'revision': '2e67a1126b6df05e4119d1e3a432fde51d76cdc8',
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100285 'apps': [
286 App({
287 'id': 'com.example.sqldelight.hockey',
288 'module': 'sample/android',
289 'archives_base_name': 'android',
290 'min_sdk': 14,
291 'compile_sdk': 28
292 })
293 ]
294 }),
295 Repo({
296 'name': 'tachiyomi',
297 'url': 'https://github.com/sgjesse/tachiyomi.git',
Morten Krogh-Jespersene0ce6a32019-02-07 11:44:45 +0100298 'revision': 'b15d2fe16864645055af6a745a62cc5566629798',
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100299 'apps': [
300 App({
301 'id': 'eu.kanade.tachiyomi',
Morten Krogh-Jespersen7889f252019-03-19 10:55:23 +0100302 'flavor': 'dev',
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100303 'min_sdk': 16
304 })
305 ]
306 }),
307 Repo({
308 'name': 'tivi',
309 'url': 'https://github.com/sgjesse/tivi.git',
Søren Gjessedbe6ebc2019-02-14 09:38:47 +0100310 'revision': '25c52e3593e7c98da4e537b49b29f6f67f88754d',
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100311 'apps': [
312 App({
313 'id': 'app.tivi',
314 'min_sdk': 23,
Morten Krogh-Jespersen137e7322019-04-06 09:47:13 +0200315 'compile_sdk': 28,
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100316 })
317 ]
318 }),
319 Repo({
320 'name': 'Tusky',
321 'url': 'https://github.com/mkj-gram/Tusky.git',
Morten Krogh-Jespersen81bf5ab2019-03-11 13:33:16 +0100322 'revision': 'e7fbd190fb53bf9fde72253b816920cb6fe34518',
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100323 'apps': [
324 App({
325 'id': 'com.keylesspalace.tusky',
326 'flavor': 'blue'
327 })
328 ]
329 }),
330 Repo({
331 'name': 'Vungle-Android-SDK',
332 'url': 'https://github.com/mkj-gram/Vungle-Android-SDK.git',
Morten Krogh-Jespersen81bf5ab2019-03-11 13:33:16 +0100333 'revision': '138d3f18c027b61b195c98911f1c5ab7d87ad18b',
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100334 'apps': [
335 App({
336 'id': 'com.publisher.vungle.sample'
337 })
338 ]
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100339 })
340]
341
342def GetAllApps():
343 apps = []
344 for repo in APP_REPOSITORIES:
345 for app in repo.apps:
346 apps.append((app, repo))
347 return apps
348
349def GetAllAppNames():
350 return [app.name for (app, repo) in GetAllApps()]
351
352def GetAppWithName(query):
353 for (app, repo) in GetAllApps():
354 if app.name == query:
355 return (app, repo)
356 assert False
Søren Gjessecdae8792018-12-12 09:02:43 +0100357
Christoffer Quist Adamsen404aade2018-12-20 13:00:09 +0100358def ComputeSizeOfDexFilesInApk(apk):
359 dex_size = 0
360 z = zipfile.ZipFile(apk, 'r')
361 for filename in z.namelist():
362 if filename.endswith('.dex'):
363 dex_size += z.getinfo(filename).file_size
364 return dex_size
365
Christoffer Quist Adamsen2a902752019-02-19 12:33:48 +0100366def ExtractMarker(apk, temp_dir, options):
Christoffer Quist Adamsenbbe5d7d2019-01-23 13:15:21 +0100367 r8_jar = os.path.join(temp_dir, 'r8.jar')
Christoffer Quist Adamsenbe2593f2019-02-19 13:01:56 +0100368 r8lib_jar = os.path.join(temp_dir, 'r8lib.jar')
Christoffer Quist Adamsenbbe5d7d2019-01-23 13:15:21 +0100369
Christoffer Quist Adamsenbe2593f2019-02-19 13:01:56 +0100370 # Use the copy of r8.jar or r8lib.jar if one is there.
Christoffer Quist Adamsenbbe5d7d2019-01-23 13:15:21 +0100371 if os.path.isfile(r8_jar):
Ian Zerny3f54e222019-02-12 10:51:17 +0100372 cmd = [jdk.GetJavaExecutable(), '-ea', '-jar', r8_jar, 'extractmarker', apk]
Christoffer Quist Adamsenbe2593f2019-02-19 13:01:56 +0100373 elif os.path.isfile(r8lib_jar):
374 cmd = [jdk.GetJavaExecutable(), '-ea', '-cp', r8lib_jar,
Morten Krogh-Jespersen220e5702019-02-27 12:57:01 +0100375 'com.android.tools.r8.ExtractMarker', apk]
Christoffer Quist Adamsenbbe5d7d2019-01-23 13:15:21 +0100376 else:
377 script = os.path.join(utils.TOOLS_DIR, 'extractmarker.py')
378 cmd = ['python', script, apk]
379
Christoffer Quist Adamsen1de3dde2019-01-24 13:17:46 +0100380 utils.PrintCmd(cmd, quiet=options.quiet)
Christoffer Quist Adamsen2a902752019-02-19 12:33:48 +0100381 stdout = subprocess.check_output(cmd)
382
383 # Return the last line.
384 lines = stdout.strip().splitlines()
385 assert len(lines) >= 1
386 return lines[-1]
387
Morten Krogh-Jespersen0de13732019-03-01 08:56:39 +0100388def CheckIsBuiltWithExpectedR8(apk, temp_dir, shrinker, options):
Christoffer Quist Adamsen47adc352019-05-03 08:58:09 +0200389 marker_raw = ExtractMarker(apk, temp_dir, options)
390
391 # Marker should be a string on the following format (no whitespace):
392 # ~~R8{"compilation-mode":"release",
393 # "min-api":16,
394 # "pg-map-id":"767707e",
395 # "sha-1":"7111a35bae6d5185dcfb338d61074aca8426c006",
396 # "version":"1.5.14-dev"}
397 if not marker_raw.startswith('~~R8'):
398 raise Exception(
399 'Expected marker to start with \'~~R8\' (was: {})'.format(marker_raw))
400
401 marker = json.loads(marker_raw[4:])
402
403 if options.hash:
404 actual_hash = marker.get('sha-1')
405 if actual_hash != options.hash:
406 raise Exception(
407 'Expected APK to be built with R8 version {} (was: {})'.format(
408 expected_hash, marker_raw))
409 return True
410
Christoffer Quist Adamsen2a902752019-02-19 12:33:48 +0100411 expected_version = (
412 options.version
413 if options.version
Morten Krogh-Jespersen0de13732019-03-01 08:56:39 +0100414 else utils.getR8Version(
415 os.path.join(
416 temp_dir,
417 'r8lib.jar' if IsMinifiedR8(shrinker) else 'r8.jar')))
Christoffer Quist Adamsen47adc352019-05-03 08:58:09 +0200418 actual_version = marker.get('version')
419 if actual_version != expected_version:
420 raise Exception(
421 'Expected APK to be built with R8 version {} (was: {})'.format(
422 expected_version, marker_raw))
423 return True
Christoffer Quist Adamsen10b7db82018-12-13 14:50:38 +0100424
Christoffer Quist Adamsen64c28c42019-04-10 11:07:42 +0200425def IsR8(shrinker):
Christoffer Quist Adamsen7cf4c562019-03-07 10:57:33 +0100426 return 'r8' in shrinker
427
Christoffer Quist Adamsen64c28c42019-04-10 11:07:42 +0200428def IsR8FullMode(shrinker):
Christoffer Quist Adamsen7cf4c562019-03-07 10:57:33 +0100429 return shrinker == 'r8-full' or shrinker == 'r8-nolib-full'
430
Christoffer Quist Adamsen64c28c42019-04-10 11:07:42 +0200431def IsLoggingEnabledFor(app, options):
432 if options.no_logging:
433 return False
434 if options.app_logging_filter and app.name not in options.app_logging_filter:
435 return False
436 return True
437
Morten Krogh-Jespersend45d95e2019-02-07 13:27:17 +0100438def IsMinifiedR8(shrinker):
439 return 'nolib' not in shrinker
440
Christoffer Quist Adamsen10b7db82018-12-13 14:50:38 +0100441def IsTrackedByGit(file):
442 return subprocess.check_output(['git', 'ls-files', file]).strip() != ''
443
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100444def GitClone(repo, checkout_dir, quiet):
Morten Krogh-Jespersene0ce6a32019-02-07 11:44:45 +0100445 result = subprocess.check_output(
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100446 ['git', 'clone', repo.url, checkout_dir]).strip()
Morten Krogh-Jespersene0ce6a32019-02-07 11:44:45 +0100447 head_rev = utils.get_HEAD_sha1_for_checkout(checkout_dir)
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100448 if repo.revision == head_rev:
Morten Krogh-Jespersene0ce6a32019-02-07 11:44:45 +0100449 return result
450 warn('Target revision is not head in {}.'.format(checkout_dir))
Morten Krogh-Jespersen54090862019-02-19 11:31:10 +0100451 with utils.ChangedWorkingDirectory(checkout_dir, quiet=quiet):
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100452 subprocess.check_output(['git', 'reset', '--hard', repo.revision])
Morten Krogh-Jespersene0ce6a32019-02-07 11:44:45 +0100453 return result
Søren Gjessecdae8792018-12-12 09:02:43 +0100454
455def GitCheckout(file):
456 return subprocess.check_output(['git', 'checkout', file]).strip()
457
Christoffer Quist Adamsen1de3dde2019-01-24 13:17:46 +0100458def InstallApkOnEmulator(apk_dest, options):
Christoffer Quist Adamsen7cf4c562019-03-07 10:57:33 +0100459 cmd = ['adb', '-s', options.emulator_id, 'install', '-r', '-d', apk_dest]
Christoffer Quist Adamsen1de3dde2019-01-24 13:17:46 +0100460 if options.quiet:
461 with open(os.devnull, 'w') as devnull:
462 subprocess.check_call(cmd, stdout=devnull)
463 else:
464 subprocess.check_call(cmd)
Christoffer Quist Adamsen1d0a0fe2018-12-21 14:28:56 +0100465
Christoffer Quist Adamsen81321b62019-01-15 14:39:53 +0100466def PercentageDiffAsString(before, after):
467 if after < before:
468 return '-' + str(round((1.0 - after / before) * 100)) + '%'
469 else:
470 return '+' + str(round((after - before) / before * 100)) + '%'
471
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100472def UninstallApkOnEmulator(app, options):
Christoffer Quist Adamsen4038bbe2019-01-15 14:31:46 +0100473 process = subprocess.Popen(
Christoffer Quist Adamsen7cf4c562019-03-07 10:57:33 +0100474 ['adb', '-s', options.emulator_id, 'uninstall', app.id],
Christoffer Quist Adamsen4038bbe2019-01-15 14:31:46 +0100475 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
476 stdout, stderr = process.communicate()
477
478 if stdout.strip() == 'Success':
479 # Successfully uninstalled
480 return
481
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100482 if 'Unknown package: {}'.format(app.id) in stderr:
Christoffer Quist Adamsen4038bbe2019-01-15 14:31:46 +0100483 # Application not installed
484 return
485
486 raise Exception(
487 'Unexpected result from `adb uninstall {}\nStdout: {}\nStderr: {}'.format(
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100488 app.id, stdout, stderr))
Christoffer Quist Adamsen4038bbe2019-01-15 14:31:46 +0100489
Christoffer Quist Adamsen7cf4c562019-03-07 10:57:33 +0100490def WaitForEmulator(options):
Christoffer Quist Adamsen1d0a0fe2018-12-21 14:28:56 +0100491 stdout = subprocess.check_output(['adb', 'devices'])
Christoffer Quist Adamsen7cf4c562019-03-07 10:57:33 +0100492 if '{}\tdevice'.format(options.emulator_id) in stdout:
Christoffer Quist Adamsenbae36612019-01-15 12:23:51 +0100493 return True
Christoffer Quist Adamsen1d0a0fe2018-12-21 14:28:56 +0100494
495 print('Emulator \'{}\' not connected; waiting for connection'.format(
Christoffer Quist Adamsen7cf4c562019-03-07 10:57:33 +0100496 options.emulator_id))
Christoffer Quist Adamsen1d0a0fe2018-12-21 14:28:56 +0100497
498 time_waited = 0
499 while True:
500 time.sleep(10)
501 time_waited += 10
502 stdout = subprocess.check_output(['adb', 'devices'])
Christoffer Quist Adamsen7cf4c562019-03-07 10:57:33 +0100503 if '{}\tdevice'.format(options.emulator_id) not in stdout:
Christoffer Quist Adamsen1d0a0fe2018-12-21 14:28:56 +0100504 print('... still waiting for connection')
505 if time_waited >= 5 * 60:
Christoffer Quist Adamsenbae36612019-01-15 12:23:51 +0100506 return False
Christoffer Quist Adamsen1d0a0fe2018-12-21 14:28:56 +0100507 else:
Christoffer Quist Adamsenbae36612019-01-15 12:23:51 +0100508 return True
Christoffer Quist Adamsen1d0a0fe2018-12-21 14:28:56 +0100509
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100510def GetResultsForApp(app, repo, options, temp_dir):
Christoffer Quist Adamsen3aa8d252018-12-13 14:56:40 +0100511 # Checkout and build in the build directory.
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100512 repo_name = repo.name
513 repo_checkout_dir = os.path.join(WORKING_DIR, repo_name)
Christoffer Quist Adamsen3aa8d252018-12-13 14:56:40 +0100514
Christoffer Quist Adamsen724bfb02019-01-10 09:54:38 +0100515 result = {}
516
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100517 if not os.path.exists(repo_checkout_dir) and not options.golem:
Christoffer Quist Adamsen1de3dde2019-01-24 13:17:46 +0100518 with utils.ChangedWorkingDirectory(WORKING_DIR, quiet=options.quiet):
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100519 GitClone(repo, repo_checkout_dir, options.quiet)
Christoffer Quist Adamsen860fa932019-01-10 14:27:39 +0100520
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100521 checkout_rev = utils.get_HEAD_sha1_for_checkout(repo_checkout_dir)
522 if repo.revision != checkout_rev:
Morten Krogh-Jespersene0ce6a32019-02-07 11:44:45 +0100523 msg = 'Checkout is not target revision for {} in {}.'.format(
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100524 app.name, repo_checkout_dir)
Morten Krogh-Jespersene0ce6a32019-02-07 11:44:45 +0100525 if options.ignore_versions:
526 warn(msg)
527 else:
528 raise Exception(msg)
Christoffer Quist Adamsen3aa8d252018-12-13 14:56:40 +0100529
Christoffer Quist Adamsen724bfb02019-01-10 09:54:38 +0100530 result['status'] = 'success'
531
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100532 app_checkout_dir = os.path.join(repo_checkout_dir, app.dir)
Christoffer Quist Adamsen724bfb02019-01-10 09:54:38 +0100533 result_per_shrinker = BuildAppWithSelectedShrinkers(
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100534 app, repo, options, app_checkout_dir, temp_dir)
Christoffer Quist Adamsen724bfb02019-01-10 09:54:38 +0100535 for shrinker, shrinker_result in result_per_shrinker.iteritems():
536 result[shrinker] = shrinker_result
537
538 return result
539
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100540def BuildAppWithSelectedShrinkers(
541 app, repo, options, checkout_dir, temp_dir):
Christoffer Quist Adamsen1d0a0fe2018-12-21 14:28:56 +0100542 result_per_shrinker = {}
Christoffer Quist Adamsen404aade2018-12-20 13:00:09 +0100543
Christoffer Quist Adamsen1de3dde2019-01-24 13:17:46 +0100544 with utils.ChangedWorkingDirectory(checkout_dir, quiet=options.quiet):
Christoffer Quist Adamsen2a902752019-02-19 12:33:48 +0100545 for shrinker in options.shrinker:
Christoffer Quist Adamsen1d0a0fe2018-12-21 14:28:56 +0100546 apk_dest = None
Christoffer Quist Adamsend0e0a7c2019-01-22 10:00:30 +0100547
Christoffer Quist Adamsen1d0a0fe2018-12-21 14:28:56 +0100548 result = {}
549 try:
Christoffer Quist Adamsend0e0a7c2019-01-22 10:00:30 +0100550 out_dir = os.path.join(checkout_dir, 'out', shrinker)
Christoffer Quist Adamsen4038bbe2019-01-15 14:31:46 +0100551 (apk_dest, profile_dest_dir, proguard_config_file) = \
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100552 BuildAppWithShrinker(
553 app, repo, shrinker, checkout_dir, out_dir, temp_dir,
554 options)
Christoffer Quist Adamsen1d0a0fe2018-12-21 14:28:56 +0100555 dex_size = ComputeSizeOfDexFilesInApk(apk_dest)
Morten Krogh-Jespersend35065e2019-02-07 10:28:52 +0100556 result['apk_dest'] = apk_dest
Christoffer Quist Adamsen1d0a0fe2018-12-21 14:28:56 +0100557 result['build_status'] = 'success'
558 result['dex_size'] = dex_size
Christoffer Quist Adamsen1d87ca62019-01-11 12:22:26 +0100559 result['profile_dest_dir'] = profile_dest_dir
Christoffer Quist Adamsen81321b62019-01-15 14:39:53 +0100560
561 profile = as_utils.ParseProfileReport(profile_dest_dir)
562 result['profile'] = {
563 task_name:duration for task_name, duration in profile.iteritems()
564 if as_utils.IsGradleCompilerTask(task_name, shrinker)}
Christoffer Quist Adamsen1d87ca62019-01-11 12:22:26 +0100565 except Exception as e:
Christoffer Quist Adamsen493acd82019-03-14 12:20:02 +0100566 warn('Failed to build {} with {}'.format(app.name, shrinker))
Christoffer Quist Adamsen1d87ca62019-01-11 12:22:26 +0100567 if e:
568 print('Error: ' + str(e))
Christoffer Quist Adamsen1d0a0fe2018-12-21 14:28:56 +0100569 result['build_status'] = 'failed'
Christoffer Quist Adamsen404aade2018-12-20 13:00:09 +0100570
Christoffer Quist Adamsen4038bbe2019-01-15 14:31:46 +0100571 if result.get('build_status') == 'success':
572 if options.monkey:
Christoffer Quist Adamsen1d0a0fe2018-12-21 14:28:56 +0100573 result['monkey_status'] = 'success' if RunMonkey(
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100574 app, options, apk_dest) else 'failed'
Christoffer Quist Adamsen1d0a0fe2018-12-21 14:28:56 +0100575
Christoffer Quist Adamsen4038bbe2019-01-15 14:31:46 +0100576 if 'r8' in shrinker and options.r8_compilation_steps > 1:
Christoffer Quist Adamsen7cf4c562019-03-07 10:57:33 +0100577 result['recompilation_results'] = \
578 ComputeRecompilationResults(
579 app, repo, options, checkout_dir, temp_dir, shrinker,
580 proguard_config_file)
Christoffer Quist Adamsend0e0a7c2019-01-22 10:00:30 +0100581
Christoffer Quist Adamsen7cf4c562019-03-07 10:57:33 +0100582 if options.run_tests and app.has_instrumentation_tests:
583 result['instrumentation_test_results'] = \
584 ComputeInstrumentationTestResults(
585 app, options, checkout_dir, out_dir, shrinker)
Christoffer Quist Adamsen4038bbe2019-01-15 14:31:46 +0100586
Christoffer Quist Adamsen1d0a0fe2018-12-21 14:28:56 +0100587 result_per_shrinker[shrinker] = result
Christoffer Quist Adamsen3aa8d252018-12-13 14:56:40 +0100588
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100589 if len(options.apps) > 1:
Christoffer Quist Adamsen1de3dde2019-01-24 13:17:46 +0100590 print('')
591 LogResultsForApp(app, result_per_shrinker, options)
592 print('')
593
Christoffer Quist Adamsen1d0a0fe2018-12-21 14:28:56 +0100594 return result_per_shrinker
Christoffer Quist Adamsen404aade2018-12-20 13:00:09 +0100595
Christoffer Quist Adamsend0e0a7c2019-01-22 10:00:30 +0100596def BuildAppWithShrinker(
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100597 app, repo, shrinker, checkout_dir, out_dir, temp_dir, options,
Christoffer Quist Adamsen1de3dde2019-01-24 13:17:46 +0100598 keepRuleSynthesisForRecompilation=False):
599 print('Building {} with {}{}'.format(
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100600 app.name,
Christoffer Quist Adamsen1de3dde2019-01-24 13:17:46 +0100601 shrinker,
602 ' for recompilation' if keepRuleSynthesisForRecompilation else ''))
Christoffer Quist Adamsen3aa8d252018-12-13 14:56:40 +0100603
Morten Krogh-Jespersende566ea2019-02-18 11:59:48 +0100604 # Add settings.gradle file if it is not present to prevent gradle from finding
605 # the settings.gradle file in the r8 root when apps are placed under
606 # $R8/build.
Christoffer Quist Adamsen082351d2019-03-08 13:07:50 +0100607 as_utils.add_settings_gradle(checkout_dir, app.name)
Morten Krogh-Jespersende566ea2019-02-18 11:59:48 +0100608
Christoffer Quist Adamsen2a902752019-02-19 12:33:48 +0100609 # Add 'r8.jar' to top-level build.gradle.
Morten Krogh-Jespersend45d95e2019-02-07 13:27:17 +0100610 as_utils.add_r8_dependency(checkout_dir, temp_dir, IsMinifiedR8(shrinker))
Christoffer Quist Adamsenf8ad4792019-01-09 13:19:19 +0100611
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100612 archives_base_name = app.archives_base_name
Christoffer Quist Adamsen3aa8d252018-12-13 14:56:40 +0100613
Christoffer Quist Adamsend0e0a7c2019-01-22 10:00:30 +0100614 if not os.path.exists(out_dir):
615 os.makedirs(out_dir)
Christoffer Quist Adamsen3aa8d252018-12-13 14:56:40 +0100616
Christoffer Quist Adamsen4038bbe2019-01-15 14:31:46 +0100617 # Set -printconfiguration in Proguard rules.
618 proguard_config_dest = os.path.abspath(
Christoffer Quist Adamsend0e0a7c2019-01-22 10:00:30 +0100619 os.path.join(out_dir, 'proguard-rules.pro'))
Christoffer Quist Adamsen4038bbe2019-01-15 14:31:46 +0100620 as_utils.SetPrintConfigurationDirective(
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100621 app, checkout_dir, proguard_config_dest)
Christoffer Quist Adamsen4038bbe2019-01-15 14:31:46 +0100622
Christoffer Quist Adamsen7cf4c562019-03-07 10:57:33 +0100623 env_vars = {}
624 env_vars['ANDROID_HOME'] = utils.getAndroidHome()
Morten Krogh-Jespersen0ca5d9e2019-03-18 10:59:47 +0100625 if not options.disable_assertions:
626 env_vars['JAVA_OPTS'] = '-ea:com.android.tools.r8...'
Christoffer Quist Adamsend0e0a7c2019-01-22 10:00:30 +0100627
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100628 releaseTarget = app.releaseTarget
Søren Gjesse8c111482018-12-21 14:47:57 +0100629 if not releaseTarget:
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100630 releaseTarget = app.module.replace('/', ':') + ':' + 'assemble' + (
631 app.flavor.capitalize() if app.flavor else '') + 'Release'
Christoffer Quist Adamsen3aa8d252018-12-13 14:56:40 +0100632
Christoffer Quist Adamsen7cf4c562019-03-07 10:57:33 +0100633 # Build using gradle.
634 args = [releaseTarget,
Christoffer Quist Adamsen64c28c42019-04-10 11:07:42 +0200635 '-Pandroid.enableR8=' + str(IsR8(shrinker)).lower(),
636 '-Pandroid.enableR8.fullMode=' + str(IsR8FullMode(shrinker)).lower()]
Morten Krogh-Jespersen36d95f52019-03-21 15:56:46 +0100637
638 # Warm up gradle if pre_runs > 0. For posterity we generate the same sequence
639 # as the benchmarking at https://github.com/madsager/santa-tracker-android.
640 for i in range(0, options.gradle_pre_runs):
641 if i == 0:
642 utils.RunGradlew(
643 ["--stop"],
644 env_vars=env_vars,
645 quiet=options.quiet,
Christoffer Quist Adamsen64c28c42019-04-10 11:07:42 +0200646 logging=IsLoggingEnabledFor(app, options),
Morten Krogh-Jespersen36d95f52019-03-21 15:56:46 +0100647 use_daemon=options.use_daemon)
648 utils.RunGradlew(
649 args,
650 env_vars=env_vars,
651 quiet=options.quiet,
652 clean=i > 0,
653 use_daemon=options.use_daemon,
Christoffer Quist Adamsen64c28c42019-04-10 11:07:42 +0200654 logging=IsLoggingEnabledFor(app, options))
Morten Krogh-Jespersen36d95f52019-03-21 15:56:46 +0100655
Christoffer Quist Adamsen1de3dde2019-01-24 13:17:46 +0100656 if keepRuleSynthesisForRecompilation:
Christoffer Quist Adamsen7cf4c562019-03-07 10:57:33 +0100657 args.append('-Dcom.android.tools.r8.keepRuleSynthesisForRecompilation=true')
Søren Gjesse9fb48802019-01-18 11:00:00 +0100658 if options.gradle_flags:
Christoffer Quist Adamsen7cf4c562019-03-07 10:57:33 +0100659 args.extend(options.gradle_flags.split(' '))
Christoffer Quist Adamsen1d87ca62019-01-11 12:22:26 +0100660
Morten Krogh-Jespersen36d95f52019-03-21 15:56:46 +0100661 args.append('--profile')
662
663 stdout = utils.RunGradlew(
664 args,
665 env_vars=env_vars,
666 quiet=options.quiet,
667 use_daemon=options.use_daemon,
Christoffer Quist Adamsen64c28c42019-04-10 11:07:42 +0200668 logging=IsLoggingEnabledFor(app, options))
Christoffer Quist Adamsen3aa8d252018-12-13 14:56:40 +0100669
670 apk_base_name = (archives_base_name
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100671 + (('-' + app.flavor) if app.flavor else '') + '-release')
672 signed_apk_name = (
673 app.signed_apk_name
674 if app.signed_apk_name
675 else apk_base_name + '.apk')
Christoffer Quist Adamsen3aa8d252018-12-13 14:56:40 +0100676 unsigned_apk_name = apk_base_name + '-unsigned.apk'
677
Christoffer Quist Adamsen7d74ef72019-04-12 10:33:38 +0200678 build_dir = os.path.join(app.module, app.build_dir)
679 build_output_apks = os.path.join(build_dir, 'outputs', 'apk')
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100680 if app.flavor:
681 build_output_apks = os.path.join(build_output_apks, app.flavor, 'release')
Christoffer Quist Adamsen3aa8d252018-12-13 14:56:40 +0100682 else:
683 build_output_apks = os.path.join(build_output_apks, 'release')
684
685 signed_apk = os.path.join(build_output_apks, signed_apk_name)
686 unsigned_apk = os.path.join(build_output_apks, unsigned_apk_name)
687
Christoffer Quist Adamsen7d74ef72019-04-12 10:33:38 +0200688 assert os.path.isfile(signed_apk) or os.path.isfile(unsigned_apk), (
689 "Expected a file to be present at {} or {}, found: {}".format(
690 signed_apk, unsigned_apk,
691 ', '.join(
692 as_utils.ListFiles(build_dir, lambda x : x.endswith('.apk')))))
693
Christoffer Quist Adamsen3aa8d252018-12-13 14:56:40 +0100694 if options.sign_apks and not os.path.isfile(signed_apk):
695 assert os.path.isfile(unsigned_apk)
696 if options.sign_apks:
Christoffer Quist Adamsen3aa8d252018-12-13 14:56:40 +0100697 apk_utils.sign_with_apksigner(
Christoffer Quist Adamsen3aa8d252018-12-13 14:56:40 +0100698 unsigned_apk,
699 signed_apk,
Christoffer Quist Adamsen3b6f1062019-02-07 09:49:43 +0100700 options.keystore,
701 options.keystore_password,
Christoffer Quist Adamsen41cbdca2019-04-12 08:52:03 +0200702 quiet=options.quiet,
703 logging=IsLoggingEnabledFor(app, options))
Christoffer Quist Adamsen3aa8d252018-12-13 14:56:40 +0100704
705 if os.path.isfile(signed_apk):
Christoffer Quist Adamsend0e0a7c2019-01-22 10:00:30 +0100706 apk_dest = os.path.join(out_dir, signed_apk_name)
Christoffer Quist Adamsen1de3dde2019-01-24 13:17:46 +0100707 as_utils.MoveFile(signed_apk, apk_dest, quiet=options.quiet)
Christoffer Quist Adamsen3aa8d252018-12-13 14:56:40 +0100708 else:
Christoffer Quist Adamsend0e0a7c2019-01-22 10:00:30 +0100709 apk_dest = os.path.join(out_dir, unsigned_apk_name)
Christoffer Quist Adamsen1de3dde2019-01-24 13:17:46 +0100710 as_utils.MoveFile(unsigned_apk, apk_dest, quiet=options.quiet)
Christoffer Quist Adamsen3aa8d252018-12-13 14:56:40 +0100711
Morten Krogh-Jespersen8a3450d2019-03-07 07:29:14 +0000712 assert ('r8' not in shrinker
713 or CheckIsBuiltWithExpectedR8(apk_dest, temp_dir, shrinker, options))
Christoffer Quist Adamsen3aa8d252018-12-13 14:56:40 +0100714
Christoffer Quist Adamsend0e0a7c2019-01-22 10:00:30 +0100715 profile_dest_dir = os.path.join(out_dir, 'profile')
Christoffer Quist Adamsen1de3dde2019-01-24 13:17:46 +0100716 as_utils.MoveProfileReportTo(profile_dest_dir, stdout, quiet=options.quiet)
Christoffer Quist Adamsen1d87ca62019-01-11 12:22:26 +0100717
Christoffer Quist Adamsen4038bbe2019-01-15 14:31:46 +0100718 return (apk_dest, profile_dest_dir, proguard_config_dest)
719
Christoffer Quist Adamsen7cf4c562019-03-07 10:57:33 +0100720def ComputeInstrumentationTestResults(
721 app, options, checkout_dir, out_dir, shrinker):
722 args = ['connectedAndroidTest',
Christoffer Quist Adamsen64c28c42019-04-10 11:07:42 +0200723 '-Pandroid.enableR8=' + str(IsR8(shrinker)).lower(),
724 '-Pandroid.enableR8.fullMode=' + str(IsR8FullMode(shrinker)).lower()]
Christoffer Quist Adamsen7cf4c562019-03-07 10:57:33 +0100725 env_vars = { 'ANDROID_SERIAL': options.emulator_id }
Morten Krogh-Jespersen36d95f52019-03-21 15:56:46 +0100726 stdout = utils.RunGradlew(
727 args,
728 env_vars=env_vars,
729 quiet=options.quiet,
730 fail=False,
Christoffer Quist Adamsen64c28c42019-04-10 11:07:42 +0200731 logging=IsLoggingEnabledFor(app, options),
Morten Krogh-Jespersen36d95f52019-03-21 15:56:46 +0100732 use_daemon=options.use_daemon)
Christoffer Quist Adamsen7cf4c562019-03-07 10:57:33 +0100733
734 xml_test_result_dest = os.path.join(out_dir, 'test_result')
735 as_utils.MoveXMLTestResultFileTo(
736 xml_test_result_dest, stdout, quiet=options.quiet)
737
738 with open(xml_test_result_dest, 'r') as f:
739 xml_test_result_contents = f.read()
740
741 xml_document = minidom.parseString(xml_test_result_contents)
742 testsuite_element = xml_document.documentElement
743
744 return {
745 'xml_test_result_dest': xml_test_result_dest,
746 'tests': int(testsuite_element.getAttribute('tests')),
747 'failures': int(testsuite_element.getAttribute('failures')),
748 'errors': int(testsuite_element.getAttribute('errors')),
749 'skipped': int(testsuite_element.getAttribute('skipped'))
750 }
751
752def ComputeRecompilationResults(
753 app, repo, options, checkout_dir, temp_dir, shrinker, proguard_config_file):
754 recompilation_results = []
755
Morten Krogh-Jespersenb5d45cd2019-03-19 13:58:30 +0100756 # Build app with gradle using -D...keepRuleSynthesisForRecompilation=true.
Christoffer Quist Adamsen7cf4c562019-03-07 10:57:33 +0100757 out_dir = os.path.join(checkout_dir, 'out', shrinker + '-1')
758 (apk_dest, profile_dest_dir, ext_proguard_config_file) = \
759 BuildAppWithShrinker(
760 app, repo, shrinker, checkout_dir, out_dir,
761 temp_dir, options, keepRuleSynthesisForRecompilation=True)
Christoffer Quist Adamsen7cf4c562019-03-07 10:57:33 +0100762 recompilation_result = {
763 'apk_dest': apk_dest,
764 'build_status': 'success',
765 'dex_size': ComputeSizeOfDexFilesInApk(apk_dest),
766 'monkey_status': 'skipped'
767 }
768 recompilation_results.append(recompilation_result)
769
770 # Sanity check that keep rules have changed.
771 with open(ext_proguard_config_file) as new:
772 with open(proguard_config_file) as old:
773 assert(
774 sum(1 for line in new
775 if line.strip() and '-printconfiguration' not in line)
776 >
777 sum(1 for line in old
778 if line.strip() and '-printconfiguration' not in line))
779
780 # Extract min-sdk and target-sdk
781 (min_sdk, compile_sdk) = \
782 as_utils.GetMinAndCompileSdk(app, checkout_dir, apk_dest)
783
784 # Now rebuild generated apk.
785 previous_apk = apk_dest
786
787 # We may need main dex rules when re-compiling with R8 as standalone.
788 main_dex_rules = None
789 if app.main_dex_rules:
790 main_dex_rules = os.path.join(checkout_dir, app.main_dex_rules)
791
792 for i in range(1, options.r8_compilation_steps):
793 try:
794 recompiled_apk_dest = os.path.join(
795 checkout_dir, 'out', shrinker, 'app-release-{}.apk'.format(i))
796 RebuildAppWithShrinker(
797 app, previous_apk, recompiled_apk_dest,
798 ext_proguard_config_file, shrinker, min_sdk, compile_sdk,
799 options, temp_dir, main_dex_rules)
800 recompilation_result = {
801 'apk_dest': recompiled_apk_dest,
802 'build_status': 'success',
803 'dex_size': ComputeSizeOfDexFilesInApk(recompiled_apk_dest)
804 }
805 if options.monkey:
806 recompilation_result['monkey_status'] = 'success' if RunMonkey(
807 app, options, recompiled_apk_dest) else 'failed'
808 recompilation_results.append(recompilation_result)
809 previous_apk = recompiled_apk_dest
810 except Exception as e:
811 warn('Failed to recompile {} with {}'.format(
812 app.name, shrinker))
813 recompilation_results.append({ 'build_status': 'failed' })
814 break
815 return recompilation_results
816
Christoffer Quist Adamsene59840b2019-01-22 15:25:15 +0100817def RebuildAppWithShrinker(
Christoffer Quist Adamsen1de3dde2019-01-24 13:17:46 +0100818 app, apk, apk_dest, proguard_config_file, shrinker, min_sdk, compile_sdk,
Morten Krogh-Jespersen03627262019-02-18 14:30:22 +0100819 options, temp_dir, main_dex_rules):
Christoffer Quist Adamsen4038bbe2019-01-15 14:31:46 +0100820 assert 'r8' in shrinker
821 assert apk_dest.endswith('.apk')
Søren Gjesse9fb48802019-01-18 11:00:00 +0100822
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100823 print('Rebuilding {} with {}'.format(app.name, shrinker))
Christoffer Quist Adamsen1de3dde2019-01-24 13:17:46 +0100824
Christoffer Quist Adamsen4038bbe2019-01-15 14:31:46 +0100825 # Compile given APK with shrinker to temporary zip file.
Christoffer Quist Adamsen17879c12019-01-22 16:13:54 +0100826 android_jar = utils.get_android_jar(compile_sdk)
Morten Krogh-Jespersend45d95e2019-02-07 13:27:17 +0100827 r8_jar = os.path.join(
828 temp_dir, 'r8lib.jar' if IsMinifiedR8(shrinker) else 'r8.jar')
Christoffer Quist Adamsend0e0a7c2019-01-22 10:00:30 +0100829 zip_dest = apk_dest[:-4] + '.zip'
Christoffer Quist Adamsen4038bbe2019-01-15 14:31:46 +0100830
Christoffer Quist Adamsene59840b2019-01-22 15:25:15 +0100831 # TODO(christofferqa): Entry point should be CompatProguard if the shrinker
832 # is 'r8'.
833 entry_point = 'com.android.tools.r8.R8'
834
Morten Krogh-Jespersen0ca5d9e2019-03-18 10:59:47 +0100835 cmd = ([jdk.GetJavaExecutable()] +
836 (['-ea:com.android.tools.r8...']
837 if not options.disable_assertions
838 else []) +
839 ['-cp', r8_jar, entry_point,
840 '--release', '--min-api', str(min_sdk),
841 '--pg-conf', proguard_config_file,
842 '--lib', android_jar,
843 '--output', zip_dest,
844 apk])
Christoffer Quist Adamsen17879c12019-01-22 16:13:54 +0100845
846 for android_optional_jar in utils.get_android_optional_jars(compile_sdk):
847 cmd.append('--lib')
848 cmd.append(android_optional_jar)
849
Morten Krogh-Jespersen03627262019-02-18 14:30:22 +0100850 if main_dex_rules:
851 cmd.append('--main-dex-rules')
852 cmd.append(main_dex_rules)
853
Christoffer Quist Adamsen41cbdca2019-04-12 08:52:03 +0200854 utils.RunCmd(
855 cmd, quiet=options.quiet, logging=IsLoggingEnabledFor(app, options))
Christoffer Quist Adamsen4038bbe2019-01-15 14:31:46 +0100856
857 # Make a copy of the given APK, move the newly generated dex files into the
858 # copied APK, and then sign the APK.
Christoffer Quist Adamsen1de3dde2019-01-24 13:17:46 +0100859 apk_masseur.masseur(
Christoffer Quist Adamsen2dcea102019-02-20 11:31:38 +0100860 apk, dex=zip_dest, resources='META-INF/services/*', out=apk_dest,
Christoffer Quist Adamsen41cbdca2019-04-12 08:52:03 +0200861 quiet=options.quiet, logging=IsLoggingEnabledFor(app, options),
862 keystore=options.keystore)
Christoffer Quist Adamsen404aade2018-12-20 13:00:09 +0100863
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100864def RunMonkey(app, options, apk_dest):
Christoffer Quist Adamsen7cf4c562019-03-07 10:57:33 +0100865 if not WaitForEmulator(options):
Christoffer Quist Adamsenbae36612019-01-15 12:23:51 +0100866 return False
867
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100868 UninstallApkOnEmulator(app, options)
Christoffer Quist Adamsen1de3dde2019-01-24 13:17:46 +0100869 InstallApkOnEmulator(apk_dest, options)
Christoffer Quist Adamsen1d0a0fe2018-12-21 14:28:56 +0100870
Christoffer Quist Adamsenbae36612019-01-15 12:23:51 +0100871 number_of_events_to_generate = options.monkey_events
Christoffer Quist Adamsen1d0a0fe2018-12-21 14:28:56 +0100872
Christoffer Quist Adamsenbae36612019-01-15 12:23:51 +0100873 # Intentionally using a constant seed such that the monkey generates the same
874 # event sequence for each shrinker.
875 random_seed = 42
876
Christoffer Quist Adamsen7cf4c562019-03-07 10:57:33 +0100877 cmd = ['adb', '-s', options.emulator_id, 'shell', 'monkey', '-p', app.id,
878 '-s', str(random_seed), str(number_of_events_to_generate)]
Christoffer Quist Adamsen88b7ebe2019-01-14 11:22:17 +0100879
880 try:
Christoffer Quist Adamsen41cbdca2019-04-12 08:52:03 +0200881 stdout = utils.RunCmd(
882 cmd, quiet=options.quiet, logging=IsLoggingEnabledFor(app, options))
Christoffer Quist Adamsend0e0a7c2019-01-22 10:00:30 +0100883 succeeded = (
884 'Events injected: {}'.format(number_of_events_to_generate) in stdout)
Christoffer Quist Adamsen88b7ebe2019-01-14 11:22:17 +0100885 except subprocess.CalledProcessError as e:
Christoffer Quist Adamsend0e0a7c2019-01-22 10:00:30 +0100886 succeeded = False
Christoffer Quist Adamsen88b7ebe2019-01-14 11:22:17 +0100887
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100888 UninstallApkOnEmulator(app, options)
Christoffer Quist Adamsen1d0a0fe2018-12-21 14:28:56 +0100889
Christoffer Quist Adamsend0e0a7c2019-01-22 10:00:30 +0100890 return succeeded
891
892def LogResultsForApps(result_per_shrinker_per_app, options):
Christoffer Quist Adamsen1de3dde2019-01-24 13:17:46 +0100893 print('')
Morten Krogh-Jespersene5853302019-04-05 12:46:42 +0200894 app_errors = 0
Christoffer Quist Adamsen7cf4c562019-03-07 10:57:33 +0100895 for (app, result_per_shrinker) in result_per_shrinker_per_app:
Morten Krogh-Jespersene5853302019-04-05 12:46:42 +0200896 app_errors += (1 if LogResultsForApp(app, result_per_shrinker, options)
897 else 0)
898 return app_errors
Christoffer Quist Adamsen724bfb02019-01-10 09:54:38 +0100899
Christoffer Quist Adamsend0e0a7c2019-01-22 10:00:30 +0100900def LogResultsForApp(app, result_per_shrinker, options):
Morten Krogh-Jespersenaeb665e2019-02-07 12:29:03 +0100901 if options.print_dexsegments:
902 LogSegmentsForApp(app, result_per_shrinker, options)
Morten Krogh-Jespersene5853302019-04-05 12:46:42 +0200903 return False
Morten Krogh-Jespersenaeb665e2019-02-07 12:29:03 +0100904 else:
Morten Krogh-Jespersene5853302019-04-05 12:46:42 +0200905 return LogComparisonResultsForApp(app, result_per_shrinker, options)
Morten Krogh-Jespersenaeb665e2019-02-07 12:29:03 +0100906
907def LogSegmentsForApp(app, result_per_shrinker, options):
908 for shrinker in SHRINKERS:
909 if shrinker not in result_per_shrinker:
910 continue
911 result = result_per_shrinker[shrinker];
Christoffer Quist Adamsen7cf4c562019-03-07 10:57:33 +0100912 benchmark_name = '{}-{}'.format(options.print_dexsegments, app.name)
Morten Krogh-Jespersenaeb665e2019-02-07 12:29:03 +0100913 utils.print_dexsegments(benchmark_name, [result.get('apk_dest')])
914 duration = sum(result.get('profile').values())
915 print('%s-Total(RunTimeRaw): %s ms' % (benchmark_name, duration * 1000))
916 print('%s-Total(CodeSize): %s' % (benchmark_name, result.get('dex_size')))
917
918
919def LogComparisonResultsForApp(app, result_per_shrinker, options):
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +0100920 print(app.name + ':')
Morten Krogh-Jespersene5853302019-04-05 12:46:42 +0200921 app_error = False
Christoffer Quist Adamsen1de3dde2019-01-24 13:17:46 +0100922 if result_per_shrinker.get('status', 'success') != 'success':
Christoffer Quist Adamsend0e0a7c2019-01-22 10:00:30 +0100923 error_message = result_per_shrinker.get('error_message')
924 print(' skipped ({})'.format(error_message))
925 return
926
Morten Krogh-Jespersenaeb665e2019-02-07 12:29:03 +0100927 proguard_result = result_per_shrinker.get('pg', {})
Christoffer Quist Adamsend0e0a7c2019-01-22 10:00:30 +0100928 proguard_dex_size = float(proguard_result.get('dex_size', -1))
929 proguard_duration = sum(proguard_result.get('profile', {}).values())
930
931 for shrinker in SHRINKERS:
932 if shrinker not in result_per_shrinker:
Christoffer Quist Adamsen724bfb02019-01-10 09:54:38 +0100933 continue
Christoffer Quist Adamsend0e0a7c2019-01-22 10:00:30 +0100934 result = result_per_shrinker.get(shrinker)
935 build_status = result.get('build_status')
936 if build_status != 'success':
Morten Krogh-Jespersene5853302019-04-05 12:46:42 +0200937 app_error = True
Christoffer Quist Adamsend0e0a7c2019-01-22 10:00:30 +0100938 warn(' {}: {}'.format(shrinker, build_status))
939 else:
940 print(' {}:'.format(shrinker))
941 dex_size = result.get('dex_size')
942 msg = ' dex size: {}'.format(dex_size)
943 if dex_size != proguard_dex_size and proguard_dex_size >= 0:
944 msg = '{} ({}, {})'.format(
945 msg, dex_size - proguard_dex_size,
946 PercentageDiffAsString(proguard_dex_size, dex_size))
947 success(msg) if dex_size < proguard_dex_size else warn(msg)
Christoffer Quist Adamsen404aade2018-12-20 13:00:09 +0100948 else:
Christoffer Quist Adamsend0e0a7c2019-01-22 10:00:30 +0100949 print(msg)
Christoffer Quist Adamsen81321b62019-01-15 14:39:53 +0100950
Christoffer Quist Adamsend0e0a7c2019-01-22 10:00:30 +0100951 profile = result.get('profile')
952 duration = sum(profile.values())
953 msg = ' performance: {}s'.format(duration)
954 if duration != proguard_duration and proguard_duration > 0:
955 msg = '{} ({}s, {})'.format(
956 msg, duration - proguard_duration,
957 PercentageDiffAsString(proguard_duration, duration))
958 success(msg) if duration < proguard_duration else warn(msg)
959 else:
960 print(msg)
961 if len(profile) >= 2:
962 for task_name, task_duration in profile.iteritems():
963 print(' {}: {}s'.format(task_name, task_duration))
Christoffer Quist Adamsen81321b62019-01-15 14:39:53 +0100964
Christoffer Quist Adamsend0e0a7c2019-01-22 10:00:30 +0100965 if options.monkey:
966 monkey_status = result.get('monkey_status')
967 if monkey_status != 'success':
Morten Krogh-Jespersene5853302019-04-05 12:46:42 +0200968 app_error = True
Christoffer Quist Adamsend0e0a7c2019-01-22 10:00:30 +0100969 warn(' monkey: {}'.format(monkey_status))
970 else:
971 success(' monkey: {}'.format(monkey_status))
Christoffer Quist Adamsen7cf4c562019-03-07 10:57:33 +0100972
Christoffer Quist Adamsend0e0a7c2019-01-22 10:00:30 +0100973 recompilation_results = result.get('recompilation_results', [])
974 i = 0
975 for recompilation_result in recompilation_results:
976 build_status = recompilation_result.get('build_status')
977 if build_status != 'success':
Morten Krogh-Jespersene5853302019-04-05 12:46:42 +0200978 app_error = True
Christoffer Quist Adamsend0e0a7c2019-01-22 10:00:30 +0100979 print(' recompilation #{}: {}'.format(i, build_status))
980 else:
981 dex_size = recompilation_result.get('dex_size')
982 print(' recompilation #{}'.format(i))
983 print(' dex size: {}'.format(dex_size))
984 if options.monkey:
985 monkey_status = recompilation_result.get('monkey_status')
986 msg = ' monkey: {}'.format(monkey_status)
987 if monkey_status == 'success':
988 success(msg)
989 elif monkey_status == 'skipped':
990 print(msg)
991 else:
992 warn(msg)
993 i += 1
Christoffer Quist Adamsen404aade2018-12-20 13:00:09 +0100994
Christoffer Quist Adamsen7cf4c562019-03-07 10:57:33 +0100995 if options.run_tests and 'instrumentation_test_results' in result:
996 instrumentation_test_results = \
997 result.get('instrumentation_test_results')
998 succeeded = (
999 instrumentation_test_results.get('failures')
1000 + instrumentation_test_results.get('errors')
1001 + instrumentation_test_results.get('skipped')) == 0
1002 if succeeded:
1003 success(' tests: succeeded')
1004 else:
Morten Krogh-Jespersene5853302019-04-05 12:46:42 +02001005 app_error = True
Christoffer Quist Adamsen7cf4c562019-03-07 10:57:33 +01001006 warn(
1007 ' tests: failed (failures: {}, errors: {}, skipped: {})'
1008 .format(
1009 instrumentation_test_results.get('failures'),
1010 instrumentation_test_results.get('errors'),
1011 instrumentation_test_results.get('skipped')))
1012
Morten Krogh-Jespersene5853302019-04-05 12:46:42 +02001013 return app_error
1014
Søren Gjessecdae8792018-12-12 09:02:43 +01001015def ParseOptions(argv):
1016 result = optparse.OptionParser()
1017 result.add_option('--app',
1018 help='What app to run on',
Christoffer Quist Adamsen3afc9f82019-05-04 13:20:23 +02001019 choices=GetAllAppNames(),
1020 action='append')
Christoffer Quist Adamsen47adc352019-05-03 08:58:09 +02001021 result.add_option('--bot',
1022 help='Running on bot, use third_party dependency.',
1023 default=False,
1024 action='store_true')
Christoffer Quist Adamsen3afc9f82019-05-04 13:20:23 +02001025 result.add_option('--disable-assertions', '--disable_assertions',
Morten Krogh-Jespersen0ca5d9e2019-03-18 10:59:47 +01001026 help='Disable assertions when compiling',
1027 default=False,
1028 action='store_true')
Morten Krogh-Jespersen64740202019-02-07 13:06:04 +01001029 result.add_option('--download-only', '--download_only',
1030 help='Whether to download apps without any compilation',
1031 default=False,
1032 action='store_true')
Christoffer Quist Adamsen7cf4c562019-03-07 10:57:33 +01001033 result.add_option('--emulator-id', '--emulator_id',
1034 help='Id of the emulator to use',
1035 default='emulator-5554')
Morten Krogh-Jespersen64740202019-02-07 13:06:04 +01001036 result.add_option('--golem',
1037 help='Running on golem, do not download',
1038 default=False,
1039 action='store_true')
Morten Krogh-Jespersend35065e2019-02-07 10:28:52 +01001040 result.add_option('--gradle-flags', '--gradle_flags',
1041 help='Flags to pass in to gradle')
Morten Krogh-Jespersen36d95f52019-03-21 15:56:46 +01001042 result.add_option('--gradle-pre-runs', '--gradle_pre_runs',
1043 help='Do rounds of compilations to warm up gradle',
1044 default=0,
1045 type=int)
Christoffer Quist Adamsen47adc352019-05-03 08:58:09 +02001046 result.add_option('--hash',
1047 help='The version of R8 to use')
Morten Krogh-Jespersene0ce6a32019-02-07 11:44:45 +01001048 result.add_option('--ignore-versions', '--ignore_versions',
1049 help='Allow checked-out app to differ in revision from '
1050 'pinned',
1051 default=False,
1052 action='store_true')
Christoffer Quist Adamsen3b6f1062019-02-07 09:49:43 +01001053 result.add_option('--keystore',
1054 help='Path to app.keystore',
Rico Wind533e3ce2019-04-04 10:26:12 +02001055 default=os.path.join(utils.TOOLS_DIR, 'debug.keystore'))
Christoffer Quist Adamsen3b6f1062019-02-07 09:49:43 +01001056 result.add_option('--keystore-password', '--keystore_password',
1057 help='Password for app.keystore',
1058 default='android')
Christoffer Quist Adamsen64c28c42019-04-10 11:07:42 +02001059 result.add_option('--app-logging-filter', '--app_logging_filter',
1060 help='The apps for which to turn on logging',
1061 action='append')
Christoffer Quist Adamsen1d0a0fe2018-12-21 14:28:56 +01001062 result.add_option('--monkey',
1063 help='Whether to install and run app(s) with monkey',
1064 default=False,
1065 action='store_true')
Christoffer Quist Adamsen64c28c42019-04-10 11:07:42 +02001066 result.add_option('--monkey-events', '--monkey_events',
Christoffer Quist Adamsenbae36612019-01-15 12:23:51 +01001067 help='Number of events that the monkey should trigger',
1068 default=250,
1069 type=int)
Morten Krogh-Jespersend35065e2019-02-07 10:28:52 +01001070 result.add_option('--no-build', '--no_build',
1071 help='Run without building ToT first (only when using ToT)',
1072 default=False,
1073 action='store_true')
Morten Krogh-Jespersend35065e2019-02-07 10:28:52 +01001074 result.add_option('--quiet',
1075 help='Disable verbose logging',
1076 default=False,
1077 action='store_true')
Morten Krogh-Jespersen50f00a52019-04-05 10:27:22 +02001078 result.add_option('--no-logging', '--no_logging',
1079 help='Disable logging except for errors',
1080 default=False,
1081 action='store_true')
Morten Krogh-Jespersenaeb665e2019-02-07 12:29:03 +01001082 result.add_option('--print-dexsegments',
1083 metavar='BENCHMARKNAME',
1084 help='Print the sizes of individual dex segments as ' +
1085 '\'<BENCHMARKNAME>-<APP>-<segment>(CodeSize): '
1086 '<bytes>\'')
Morten Krogh-Jespersend35065e2019-02-07 10:28:52 +01001087 result.add_option('--r8-compilation-steps', '--r8_compilation_steps',
1088 help='Number of times R8 should be run on each app',
1089 default=2,
1090 type=int)
Christoffer Quist Adamsen7cf4c562019-03-07 10:57:33 +01001091 result.add_option('--run-tests', '--run_tests',
1092 help='Whether to run instrumentation tests',
1093 default=False,
1094 action='store_true')
Søren Gjesseeed839d2019-01-11 15:19:16 +01001095 result.add_option('--sign-apks', '--sign_apks',
Christoffer Quist Adamsen10b7db82018-12-13 14:50:38 +01001096 help='Whether the APKs should be signed',
1097 default=False,
1098 action='store_true')
1099 result.add_option('--shrinker',
Christoffer Quist Adamsen860fa932019-01-10 14:27:39 +01001100 help='The shrinkers to use (by default, all are run)',
1101 action='append')
Morten Krogh-Jespersen36d95f52019-03-21 15:56:46 +01001102 result.add_option('--use-daemon', '--use_daemon',
1103 help='Whether to use a gradle daemon',
1104 default=False,
1105 action='store_true')
Christoffer Quist Adamsen2a902752019-02-19 12:33:48 +01001106 result.add_option('--version',
1107 help='The version of R8 to use (e.g., 1.4.51)')
Christoffer Quist Adamsen860fa932019-01-10 14:27:39 +01001108 (options, args) = result.parse_args(argv)
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +01001109 if options.app:
Christoffer Quist Adamsen3afc9f82019-05-04 13:20:23 +02001110 options.apps = [(app, repo) for (app, repo) in GetAllApps()
1111 if app.name in options.app]
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +01001112 del options.app
1113 else:
1114 options.apps = GetAllApps()
Christoffer Quist Adamsen64c28c42019-04-10 11:07:42 +02001115 if options.app_logging_filter:
1116 for app_name in options.app_logging_filter:
1117 assert any(app.name == app_name for (app, repo) in options.apps)
Christoffer Quist Adamsen860fa932019-01-10 14:27:39 +01001118 if options.shrinker:
1119 for shrinker in options.shrinker:
1120 assert shrinker in SHRINKERS
Christoffer Quist Adamsen2a902752019-02-19 12:33:48 +01001121 else:
1122 options.shrinker = [shrinker for shrinker in SHRINKERS]
Christoffer Quist Adamsen47adc352019-05-03 08:58:09 +02001123 if options.hash or options.version:
1124 # No need to build R8 if a specific version should be used.
Christoffer Quist Adamsen2a902752019-02-19 12:33:48 +01001125 options.no_build = True
1126 if 'r8-nolib' in options.shrinker:
Christoffer Quist Adamsen47adc352019-05-03 08:58:09 +02001127 warn('Skipping shrinker r8-nolib because a specific version '
Christoffer Quist Adamsen2a902752019-02-19 12:33:48 +01001128 + 'of r8 was specified')
1129 options.shrinker.remove('r8-nolib')
1130 if 'r8-nolib-full' in options.shrinker:
Christoffer Quist Adamsen47adc352019-05-03 08:58:09 +02001131 warn('Skipping shrinker r8-nolib-full because a specific version '
Christoffer Quist Adamsen2a902752019-02-19 12:33:48 +01001132 + 'of r8 was specified')
1133 options.shrinker.remove('r8-nolib-full')
Christoffer Quist Adamsen860fa932019-01-10 14:27:39 +01001134 return (options, args)
Søren Gjessecdae8792018-12-12 09:02:43 +01001135
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +01001136def clone_repositories(quiet):
1137 # Clone repositories into WORKING_DIR.
Morten Krogh-Jespersen64740202019-02-07 13:06:04 +01001138 with utils.ChangedWorkingDirectory(WORKING_DIR):
Christoffer Quist Adamsene57b73c2019-03-07 15:13:03 +01001139 for repo in APP_REPOSITORIES:
1140 repo_dir = os.path.join(WORKING_DIR, repo.name)
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +01001141 if not os.path.exists(repo_dir):
1142 GitClone(repo, repo_dir, quiet)
Morten Krogh-Jespersen64740202019-02-07 13:06:04 +01001143
1144
Søren Gjessecdae8792018-12-12 09:02:43 +01001145def main(argv):
1146 (options, args) = ParseOptions(argv)
Christoffer Quist Adamsenf8ad4792019-01-09 13:19:19 +01001147
Rico Wind7517c3f2019-04-03 16:18:50 +02001148 if options.bot:
Rico Windbc7cab02019-04-04 12:22:09 +02001149 utils.DownloadFromGoogleCloudStorage(utils.OPENSOURCE_APPS_SHA_FILE)
1150 utils.DownloadFromGoogleCloudStorage(utils.ANDROID_SDK + '.tar.gz.sha1',
1151 bucket='r8-deps-internal',
1152 auth=True)
Rico Wind7517c3f2019-04-03 16:18:50 +02001153 if os.path.exists(WORKING_DIR):
1154 shutil.rmtree(WORKING_DIR)
1155 shutil.copytree(utils.OPENSOURCE_APPS_FOLDER, WORKING_DIR)
1156 os.environ[utils.ANDROID_HOME_ENVIROMENT_NAME] = os.path.join(
1157 utils.ANDROID_SDK)
1158 os.environ[utils.ANDROID_TOOLS_VERSION_ENVIRONMENT_NAME] = '28.0.3'
Christoffer Quist Adamsenef8a1532019-04-16 14:15:53 +02001159 options.no_logging = True
Morten Krogh-Jespersen137e7322019-04-06 09:47:13 +02001160 options.shrinker = [shrinker for shrinker in SHRINKERS if shrinker != 'pg']
1161 print(options.shrinker)
Rico Wind7517c3f2019-04-03 16:18:50 +02001162
Morten Krogh-Jespersen64740202019-02-07 13:06:04 +01001163 if options.golem:
Morten Krogh-Jespersenc2fbde22019-02-07 13:59:55 +01001164 golem.link_third_party()
Morten Krogh-Jespersen64740202019-02-07 13:06:04 +01001165 if os.path.exists(WORKING_DIR):
1166 shutil.rmtree(WORKING_DIR)
1167 shutil.copytree(utils.OPENSOURCE_APPS_FOLDER, WORKING_DIR)
Morten Krogh-Jespersen220e5702019-02-27 12:57:01 +01001168 os.environ[utils.ANDROID_HOME_ENVIROMENT_NAME] = os.path.join(
1169 utils.ANDROID_SDK)
1170 os.environ[utils.ANDROID_TOOLS_VERSION_ENVIRONMENT_NAME] = '28.0.3'
Morten Krogh-Jespersen475f6b42019-03-18 13:28:27 +01001171 options.disable_assertions = True
1172 options.ignore_versions = True
1173 options.no_build = True
1174 options.r8_compilation_steps = 1
1175 options.quiet = True
Morten Krogh-Jespersen36d95f52019-03-21 15:56:46 +01001176 options.gradle_pre_runs = 2
1177 options.use_daemon = True
Morten Krogh-Jespersen50f00a52019-04-05 10:27:22 +02001178 options.no_logging = True
Morten Krogh-Jespersen64740202019-02-07 13:06:04 +01001179
1180 if not os.path.exists(WORKING_DIR):
1181 os.makedirs(WORKING_DIR)
1182
1183 if options.download_only:
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +01001184 clone_repositories(options.quiet)
Morten Krogh-Jespersen64740202019-02-07 13:06:04 +01001185 return
1186
Christoffer Quist Adamsenbbe5d7d2019-01-23 13:15:21 +01001187 with utils.TempDir() as temp_dir:
Morten Krogh-Jespersen2bd5ec82019-02-25 16:01:23 +01001188 if not (options.no_build or options.golem):
Rico Wind1ce8b972019-04-04 14:22:42 +02001189 gradle.RunGradle(['r8', 'r8lib', '-Pno_internal'])
Søren Gjessecdae8792018-12-12 09:02:43 +01001190
Christoffer Quist Adamsen47adc352019-05-03 08:58:09 +02001191 if options.hash:
1192 # Download r8-<hash>.jar from
1193 # http://storage.googleapis.com/r8-releases/raw/.
1194 target = 'r8-{}.jar'.format(options.hash)
1195 update_prebuilds_in_android.download_hash(
1196 temp_dir, 'com/android/tools/r8/' + options.hash, target)
1197 as_utils.MoveFile(
1198 os.path.join(temp_dir, target), os.path.join(temp_dir, 'r8lib.jar'),
1199 quiet=options.quiet)
1200 elif options.version:
Christoffer Quist Adamsen2a902752019-02-19 12:33:48 +01001201 # Download r8-<version>.jar from
1202 # http://storage.googleapis.com/r8-releases/raw/.
1203 target = 'r8-{}.jar'.format(options.version)
1204 update_prebuilds_in_android.download_version(
1205 temp_dir, 'com/android/tools/r8/' + options.version, target)
1206 as_utils.MoveFile(
1207 os.path.join(temp_dir, target), os.path.join(temp_dir, 'r8lib.jar'),
1208 quiet=options.quiet)
1209 else:
1210 # Make a copy of r8.jar and r8lib.jar such that they stay the same for
1211 # the entire execution of this script.
Morten Krogh-Jespersenffc73812019-03-19 12:59:17 +01001212 if 'r8-nolib' in options.shrinker or 'r8-nolib-full' in options.shrinker:
Christoffer Quist Adamsen2a902752019-02-19 12:33:48 +01001213 assert os.path.isfile(utils.R8_JAR), 'Cannot build without r8.jar'
1214 shutil.copyfile(utils.R8_JAR, os.path.join(temp_dir, 'r8.jar'))
Morten Krogh-Jespersenffc73812019-03-19 12:59:17 +01001215 if 'r8' in options.shrinker or 'r8-full' in options.shrinker:
Christoffer Quist Adamsen2a902752019-02-19 12:33:48 +01001216 assert os.path.isfile(utils.R8LIB_JAR), 'Cannot build without r8lib.jar'
1217 shutil.copyfile(utils.R8LIB_JAR, os.path.join(temp_dir, 'r8lib.jar'))
Christoffer Quist Adamsen404aade2018-12-20 13:00:09 +01001218
Christoffer Quist Adamsen7cf4c562019-03-07 10:57:33 +01001219 result_per_shrinker_per_app = []
Christoffer Quist Adamsen404aade2018-12-20 13:00:09 +01001220
Christoffer Quist Adamsenb899c112019-03-06 15:25:00 +01001221 for (app, repo) in options.apps:
1222 if app.skip:
1223 continue
Christoffer Quist Adamsen7cf4c562019-03-07 10:57:33 +01001224 result_per_shrinker_per_app.append(
1225 (app, GetResultsForApp(app, repo, options, temp_dir)))
Christoffer Quist Adamsenbbe5d7d2019-01-23 13:15:21 +01001226
Morten Krogh-Jespersene5853302019-04-05 12:46:42 +02001227 return LogResultsForApps(result_per_shrinker_per_app, options)
Christoffer Quist Adamsen404aade2018-12-20 13:00:09 +01001228
1229def success(message):
1230 CGREEN = '\033[32m'
1231 CEND = '\033[0m'
1232 print(CGREEN + message + CEND)
1233
1234def warn(message):
1235 CRED = '\033[91m'
1236 CEND = '\033[0m'
1237 print(CRED + message + CEND)
Søren Gjessecdae8792018-12-12 09:02:43 +01001238
1239if __name__ == '__main__':
1240 sys.exit(main(sys.argv[1:]))