blob: 78b12c779b54405e6bb9f5462448f29a5a356606 [file] [log] [blame]
Rico Wind3d369b42021-01-12 10:26:24 +01001#!/usr/bin/env python3
Christoffer Quist Adamsenf2e8db72020-11-07 14:09:49 +01002# Copyright (c) 2020, 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.
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +01005
Ian Zerny161ff742022-01-20 12:39:40 +01006import argparse
7import hashlib
8import os
9import shutil
10import sys
11import time
12import zipfile
13from datetime import datetime
14
Morten Krogh-Jespersencd55f812020-11-04 09:13:31 +010015import adb
16import apk_masseur
Christoffer Quist Adamsenf79f1a22021-01-12 16:24:34 +010017import as_utils
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +010018import compiledump
19import gradle
Rico Wind61a034f2021-03-16 09:37:11 +010020import jdk
Morten Krogh-Jespersen47764032020-11-11 15:09:39 +010021import update_prebuilds_in_android
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +010022import utils
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +010023
Ian Zerny161ff742022-01-20 12:39:40 +010024GOLEM_BUILD_TARGETS = ['R8Lib', 'R8Retrace']
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +010025SHRINKERS = ['r8', 'r8-full', 'r8-nolib', 'r8-nolib-full']
26
27class AttrDict(dict):
28 def __getattr__(self, name):
29 return self.get(name, None)
30
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +010031# To generate the files for a new app, navigate to the app source folder and
32# run:
33# ./gradlew clean :app:assembleRelease -Dcom.android.tools.r8.dumpinputtodirectory=<path>
34# and store the dump and the apk.
35# If the app has instrumented tests, adding `testBuildType "release"` and
36# running:
37# ./gradlew assembleAndroidTest -Dcom.android.tools.r8.dumpinputtodirectory=<path>
38# will also generate dumps and apk for tests.
39
40class App(object):
41 def __init__(self, fields):
42 defaults = {
43 'id': None,
44 'name': None,
Christoffer Quist Adamsen53e29472020-11-13 10:53:06 +010045 'collections': [],
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +010046 'dump_app': None,
Morten Krogh-Jespersencd55f812020-11-04 09:13:31 +010047 'apk_app': None,
Morten Krogh-Jespersen571cfe72020-11-09 23:44:03 +010048 'dump_test': None,
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +010049 'apk_test': None,
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +010050 'skip': False,
51 'url': None, # url is not used but nice to have for updating apps
52 'revision': None,
53 'folder': None,
54 'skip_recompilation': False,
Morten Krogh-Jespersen43f3cea2020-11-12 17:09:51 +010055 'compiler_properties': [],
Morten Krogh-Jespersen86222742021-03-02 11:13:33 +010056 'internal': False,
Morten Krogh-Jespersen9e7951b2022-08-10 15:05:26 +020057 'golem_duration': None,
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +010058 }
59 # This below does not work in python3
60 defaults.update(fields.items())
61 self.__dict__ = defaults
62
63
Christoffer Quist Adamsen53e29472020-11-13 10:53:06 +010064class AppCollection(object):
65 def __init__(self, fields):
66 defaults = {
67 'name': None
68 }
69 # This below does not work in python3
70 defaults.update(fields.items())
71 self.__dict__ = defaults
72
73
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +010074APPS = [
75 App({
Morten Krogh-Jespersen0f85fa52020-11-04 13:40:43 +010076 'id': 'com.numix.calculator',
77 'name': 'Calculator',
78 'dump_app': 'dump_app.zip',
79 'apk_app': 'app-release.apk',
80 # Compiling tests fail: Library class android.content.res.XmlResourceParser
81 # implements program class org.xmlpull.v1.XmlPullParser. Nothing to really
82 # do about that.
83 'id_test': 'com.numix.calculator.test',
84 'dump_test': 'dump_test.zip',
85 'apk_test': 'app-release-androidTest.apk',
86 'url': 'https://github.com/numixproject/android-suite/tree/master/Calculator',
87 'revision': 'f58e1b53f7278c9b675d5855842c6d8a44cccb1f',
88 'folder': 'android-suite-calculator',
89 }),
90 App({
Morten Krogh-Jespersen3f0d72f2020-11-04 15:49:17 +010091 'id': 'dev.dworks.apps.anexplorer.pro',
92 'name': 'AnExplorer',
93 'dump_app': 'dump_app.zip',
94 'apk_app': 'AnExplorer-googleMobileProRelease-4.0.3.apk',
95 'url': 'https://github.com/christofferqa/AnExplorer',
96 'revision': '365927477b8eab4052a1882d5e358057ae3dee4d',
97 'folder': 'anexplorer',
98 }),
99 App({
Morten Krogh-Jespersen09e2fda2020-11-04 16:43:25 +0100100 'id': 'de.danoeh.antennapod',
101 'name': 'AntennaPod',
102 'dump_app': 'dump_app.zip',
103 'apk_app': 'app-free-release.apk',
104 # TODO(b/172452102): Tests and monkey do not work
105 'id_test': 'de.danoeh.antennapod.test',
106 'dump_test': 'dump_test.zip',
107 'apk_test': 'app-free-release-androidTest.apk',
108 'url': 'https://github.com/christofferqa/AntennaPod.git',
109 'revision': '77e94f4783a16abe9cc5b78dc2d2b2b1867d8c06',
110 'folder': 'antennapod',
Morten Krogh-Jespersen09e2fda2020-11-04 16:43:25 +0100111 }),
112 App({
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100113 'id': 'com.example.applymapping',
114 'name': 'applymapping',
115 'dump_app': 'dump_app.zip',
Morten Krogh-Jespersencd55f812020-11-04 09:13:31 +0100116 'apk_app': 'app-release.apk',
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100117 'id_test': 'com.example.applymapping.test',
118 'dump_test': 'dump_test.zip',
119 'apk_test': 'app-release-androidTest.apk',
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100120 'url': 'https://github.com/mkj-gram/applymapping',
121 'revision': 'e3ae14b8c16fa4718e5dea8f7ad00937701b3c48',
122 'folder': 'applymapping',
Morten Krogh-Jespersen90912fd2020-11-05 09:21:16 +0100123 }),
124 App({
Morten Krogh-Jespersena98a4222020-11-05 10:50:10 +0100125 'id': 'com.chanapps.four.activity',
126 'name': 'chanu',
127 'dump_app': 'dump_app.zip',
128 'apk_app': 'app-release.apk',
129 'url': 'https://github.com/mkj-gram/chanu.git',
130 'revision': '6e53458f167b6d78398da60c20fd0da01a232617',
131 'folder': 'chanu',
Morten Krogh-Jespersen43f3cea2020-11-12 17:09:51 +0100132 # The app depends on a class file that has access flags interface but
133 # not abstract
134 'compiler_properties': ['-Dcom.android.tools.r8.allowInvalidCfAccessFlags=true']
Morten Krogh-Jespersena98a4222020-11-05 10:50:10 +0100135 }),
Christoffer Quist Adamsen00840062021-12-16 12:24:13 +0100136 App({
137 'id': 'com.example.myapplication',
138 'name': 'empty-activity',
139 'dump_app': 'dump_app.zip',
140 'apk_app': 'app-release.apk',
141 'url': 'https://github.com/christofferqa/empty_android_activity.git',
142 'revision': '2d297ec3373dadb03cbae916b9feba4792563156',
143 'folder': 'empty-activity',
144 }),
145 App({
146 'id': 'com.example.emptycomposeactivity',
147 'name': 'empty-compose-activity',
148 'dump_app': 'dump_app.zip',
149 'apk_app': 'app-release.apk',
150 'url': 'https://github.com/christofferqa/empty_android_compose_activity.git',
151 'revision': '3c8111b8b7d6e9184049a07e2b96702d7b33d03e',
152 'folder': 'empty-compose-activity',
153 }),
Morten Krogh-Jespersend06ff012020-11-05 10:50:21 +0100154 # TODO(b/172539375): Monkey runner fails on recompilation.
155 App({
156 'id': 'com.google.firebase.example.fireeats',
157 'name': 'FriendlyEats',
158 'dump_app': 'dump_app.zip',
159 'apk_app': 'app-release-unsigned.apk',
160 'url': 'https://github.com/firebase/friendlyeats-android',
161 'revision': '7c6dd016fc31ea5ecb948d5166b8479efc3775cc',
162 'folder': 'friendlyeats',
163 }),
Morten Krogh-Jespersena98a4222020-11-05 10:50:10 +0100164 App({
Morten Krogh-Jespersen162b3452020-11-05 13:07:10 +0100165 'id': 'com.google.samples.apps.sunflower',
166 'name': 'Sunflower',
167 'dump_app': 'dump_app.zip',
168 'apk_app': 'app-debug.apk',
169 # TODO(b/172549283): Compiling tests fails
Morten Krogh-Jespersend0389c02020-11-09 23:42:51 +0100170 'id_test': 'com.google.samples.apps.sunflower.test',
Morten Krogh-Jespersen162b3452020-11-05 13:07:10 +0100171 'dump_test': 'dump_test.zip',
172 'apk_test': 'app-debug-androidTest.apk',
173 'url': 'https://github.com/android/sunflower',
174 'revision': '0c4c88fdad2a74791199dffd1a6559559b1dbd4a',
175 'folder': 'sunflower',
Morten Krogh-Jespersen162b3452020-11-05 13:07:10 +0100176 }),
Morten Krogh-Jespersenac9de3f2020-11-05 17:07:26 +0100177 # TODO(b/172565385): Monkey runner fails on recompilation
178 App({
179 'id': 'com.google.samples.apps.iosched',
180 'name': 'iosched',
181 'dump_app': 'dump_app.zip',
182 'apk_app': 'mobile-release.apk',
183 'url': 'https://github.com/christofferqa/iosched.git',
184 'revision': '581cbbe2253711775dbccb753cdb53e7e506cb02',
185 'folder': 'iosched',
186 }),
Morten Krogh-Jespersen162b3452020-11-05 13:07:10 +0100187 App({
Morten Krogh-Jespersend0389c02020-11-09 23:42:51 +0100188 'id': 'fr.neamar.kiss',
189 'name': 'KISS',
190 'dump_app': 'dump_app.zip',
191 'apk_app': 'app-release.apk',
192 # TODO(b/172569220): Running tests fails due to missing keep rules
193 'id_test': 'fr.neamar.kiss.test',
194 'dump_test': 'dump_test.zip',
195 'apk_test': 'app-release-androidTest.apk',
196 'url': 'https://github.com/Neamar/KISS',
197 'revision': '8ccffaadaf0d0b8fc4418ed2b4281a0935d3d971',
198 'folder': 'kiss',
199 }),
Morten Krogh-Jespersenaaacd722020-11-09 23:43:24 +0100200 # TODO(b/172577344): Monkey runner not working.
201 App({
202 'id': 'io.github.hidroh.materialistic',
203 'name': 'materialistic',
204 'dump_app': 'dump_app.zip',
205 'apk_app': 'app-release.apk',
206 'url': 'https://github.com/christofferqa/materialistic.git',
207 'revision': '2b2b2ee25ce9e672d5aab1dc90a354af1522b1d9',
208 'folder': 'materialistic',
209 }),
Morten Krogh-Jespersend0389c02020-11-09 23:42:51 +0100210 App({
Morten Krogh-Jespersen571cfe72020-11-09 23:44:03 +0100211 'id': 'com.avjindersinghsekhon.minimaltodo',
212 'name': 'MinimalTodo',
213 'dump_app': 'dump_app.zip',
214 'apk_app': 'app-release.apk',
215 'url': 'https://github.com/christofferqa/Minimal-Todo',
216 'revision': '9d8c73746762cd376b718858ec1e8783ca07ba7c',
217 'folder': 'minimal-todo',
218 }),
219 App({
Morten Krogh-Jespersen3e3781f2020-11-09 23:44:33 +0100220 'id': 'net.nurik.roman.muzei',
221 'name': 'muzei',
222 'dump_app': 'dump_app.zip',
223 'apk_app': 'muzei-release.apk',
224 'url': 'https://github.com/romannurik/muzei',
225 'revision': '9eac6e98aebeaf0ae40bdcd85f16dd2886551138',
226 'folder': 'muzei',
227 }),
Morten Krogh-Jespersenf8e77032020-11-09 23:44:58 +0100228 # TODO(b/172806281): Monkey runner does not work.
229 App({
230 'id': 'org.schabi.newpipe',
231 'name': 'NewPipe',
232 'dump_app': 'dump_app.zip',
233 'apk_app': 'app-release-unsigned.apk',
234 'url': 'https://github.com/TeamNewPipe/NewPipe',
235 'revision': 'f4435f90313281beece70c544032f784418d85fa',
236 'folder': 'newpipe',
Morten Krogh-Jespersenf8e77032020-11-09 23:44:58 +0100237 }),
Morten Krogh-Jespersendf700642020-11-09 23:45:25 +0100238 # TODO(b/172806808): Monkey runner does not work.
239 App({
240 'id': 'io.rover.app.debug',
241 'name': 'Rover',
242 'dump_app': 'dump_app.zip',
243 'apk_app': 'example-app-release-unsigned.apk',
244 'url': 'https://github.com/RoverPlatform/rover-android',
245 'revision': '94342117097770ea3ca2c6df6ab496a1a55c3ce7',
246 'folder': 'rover-android',
247 }),
Morten Krogh-Jespersen2f1be952020-11-09 23:45:48 +0100248 # TODO(b/172808159): Monkey runner does not work
249 App({
250 'id': 'com.google.android.apps.santatracker',
251 'name': 'SantaTracker',
252 'dump_app': 'dump_app.zip',
253 'apk_app': 'santa-tracker-release.apk',
254 'url': 'https://github.com/christofferqa/santa-tracker-android',
255 'revision': '8dee74be7d9ee33c69465a07088c53087d24a6dd',
256 'folder': 'santa-tracker',
257 }),
258 App({
Morten Krogh-Jespersen88cc0772020-11-09 23:46:13 +0100259 'id': 'org.thoughtcrime.securesms',
260 'name': 'Signal',
261 'dump_app': 'dump_app.zip',
262 'apk_app': 'Signal-Android-play-prod-universal-release-4.76.2.apk',
263 # TODO(b/172812839): Instrumentation test fails.
264 'id_test': 'org.thoughtcrime.securesms.test',
265 'dump_test': 'dump_test.zip',
266 'apk_test': 'Signal-Android-play-prod-release-androidTest.apk',
267 'url': 'https://github.com/signalapp/Signal-Android',
268 'revision': '91ca19f294362ccee2c2b43c247eba228e2b30a1',
269 'folder': 'signal-android',
270 }),
Morten Krogh-Jespersen733bcff2020-11-09 23:46:43 +0100271 # TODO(b/172815827): Monkey runner does not work
272 App({
273 'id': 'com.simplemobiletools.calendar.pro',
274 'name': 'Simple-Calendar',
275 'dump_app': 'dump_app.zip',
276 'apk_app': 'calendar-release.apk',
277 'url': 'https://github.com/SimpleMobileTools/Simple-Calendar',
278 'revision': '906209874d0a091c7fce5a57972472f272d6b068',
279 'folder': 'simple-calendar',
280 }),
Morten Krogh-Jespersen8a564d32020-11-09 23:47:07 +0100281 # TODO(b/172815534): Monkey runner does not work
282 App({
283 'id': 'com.simplemobiletools.camera.pro',
284 'name': 'Simple-Camera',
285 'dump_app': 'dump_app.zip',
286 'apk_app': 'camera-release.apk',
287 'url': 'https://github.com/SimpleMobileTools/Simple-Camera',
288 'revision': 'ebf9820c51e960912b3238287e30a131244fdee6',
289 'folder': 'simple-camera',
290 }),
Morten Krogh-Jespersen88cc0772020-11-09 23:46:13 +0100291 App({
Morten Krogh-Jespersen805e31a2020-11-09 23:47:32 +0100292 'id': 'com.simplemobiletools.filemanager.pro',
293 'name': 'Simple-File-Manager',
294 'dump_app': 'dump_app.zip',
295 'apk_app': 'file-manager-release.apk',
296 'url': 'https://github.com/SimpleMobileTools/Simple-File-Manager',
297 'revision': '2b7fa68ea251222cc40cf6d62ad1de260a6f54d9',
298 'folder': 'simple-file-manager',
299 }),
300 App({
Morten Krogh-Jespersendc29e992020-11-09 23:48:01 +0100301 'id': 'com.simplemobiletools.gallery.pro',
302 'name': 'Simple-Gallery',
303 'dump_app': 'dump_app.zip',
304 'apk_app': 'gallery-326-foss-release.apk',
305 'url': 'https://github.com/SimpleMobileTools/Simple-Gallery',
306 'revision': '564e56b20d33b28d0018c8087ec705beeb60785e',
307 'folder': 'simple-gallery',
Morten Krogh-Jespersendc29e992020-11-09 23:48:01 +0100308 }),
309 App({
Morten Krogh-Jespersen4a9657a2020-11-09 23:48:21 +0100310 'id': 'com.example.sqldelight.hockey',
311 'name': 'SQLDelight',
312 'dump_app': 'dump_app.zip',
313 'apk_app': 'android-release.apk',
314 'url': 'https://github.com/christofferqa/sqldelight',
315 'revision': '2e67a1126b6df05e4119d1e3a432fde51d76cdc8',
316 'folder': 'sqldelight',
317 }),
Morten Krogh-Jespersenf12a57e2020-11-09 23:48:53 +0100318 # TODO(b/172824096): Monkey runner does not work.
319 App({
320 'id': 'eu.kanade.tachiyomi',
321 'name': 'Tachiyomi',
322 'dump_app': 'dump_app.zip',
323 'apk_app': 'app-dev-release.apk',
324 'url': 'https://github.com/inorichi/tachiyomi',
325 'revision': '8aa6486bf76ab9a61a5494bee284b1a5e9180bf3',
326 'folder': 'tachiyomi',
327 }),
Morten Krogh-Jespersen58974522020-11-10 00:20:46 +0100328 # TODO(b/172862042): Monkey runner does not work.
329 App({
330 'id': 'app.tivi',
331 'name': 'Tivi',
332 'dump_app': 'dump_app.zip',
333 'apk_app': 'app-release.apk',
334 'url': 'https://github.com/chrisbanes/tivi',
Morten Krogh-Jespersen44e2f892020-12-17 09:18:35 +0100335 'revision': '5c6d9ed338885c59b1fc64050d92d056417bb4de',
Morten Krogh-Jespersen58974522020-11-10 00:20:46 +0100336 'folder': 'tivi',
Morten Krogh-Jespersen58974522020-11-10 00:20:46 +0100337 }),
Morten Krogh-Jespersen4a9657a2020-11-09 23:48:21 +0100338 App({
Morten Krogh-Jespersen9033d1a2020-11-09 23:49:23 +0100339 'id': 'com.keylesspalace.tusky',
340 'name': 'Tusky',
341 'dump_app': 'dump_app.zip',
342 'apk_app': 'app-blue-release.apk',
343 'url': 'https://github.com/tuskyapp/Tusky',
344 'revision': '814a9b8f9bacf8d26f712b06a0313a3534a2be95',
345 'folder': 'tusky',
Morten Krogh-Jespersen9033d1a2020-11-09 23:49:23 +0100346 }),
347 App({
Morten Krogh-Jespersen90912fd2020-11-05 09:21:16 +0100348 'id': 'org.wikipedia',
349 'name': 'Wikipedia',
350 'dump_app': 'dump_app.zip',
351 'apk_app': 'app-prod-release.apk',
352 'url': 'https://github.com/wikimedia/apps-android-wikipedia',
353 'revision': '0fa7cad843c66313be8e25790ef084cf1a1fa67e',
354 'folder': 'wikipedia',
355 }),
Christoffer Quist Adamsen53e29472020-11-13 10:53:06 +0100356 # TODO(b/173167253): Check if monkey testing works.
357 App({
358 'id': 'androidx.compose.samples.crane',
359 'name': 'compose-crane',
360 'collections': ['compose-samples'],
361 'dump_app': 'dump_app.zip',
362 'apk_app': 'app-release-unsigned.apk',
363 'url': 'https://github.com/android/compose-samples',
364 'revision': '779cf9e187b8ee2c6b620b2abb4524719b3f10f8',
365 'folder': 'android/compose-samples/crane',
Morten Krogh-Jespersen9e7951b2022-08-10 15:05:26 +0200366 'golem_duration': 240
Christoffer Quist Adamsen53e29472020-11-13 10:53:06 +0100367 }),
368 # TODO(b/173167253): Check if monkey testing works.
369 App({
370 'id': 'com.example.jetcaster',
371 'name': 'compose-jetcaster',
372 'collections': ['compose-samples'],
373 'dump_app': 'dump_app.zip',
374 'apk_app': 'app-release-unsigned.apk',
375 'url': 'https://github.com/android/compose-samples',
376 'revision': '779cf9e187b8ee2c6b620b2abb4524719b3f10f8',
377 'folder': 'android/compose-samples/jetcaster',
Christoffer Quist Adamsen53e29472020-11-13 10:53:06 +0100378 }),
379 # TODO(b/173167253): Check if monkey testing works.
380 App({
381 'id': 'com.example.compose.jetchat',
382 'name': 'compose-jetchat',
383 'collections': ['compose-samples'],
384 'dump_app': 'dump_app.zip',
385 'apk_app': 'app-release-unsigned.apk',
386 'url': 'https://github.com/android/compose-samples',
387 'revision': '779cf9e187b8ee2c6b620b2abb4524719b3f10f8',
388 'folder': 'android/compose-samples/jetchat',
Christoffer Quist Adamsen53e29472020-11-13 10:53:06 +0100389 }),
390 # TODO(b/173167253): Check if monkey testing works.
391 App({
392 'id': 'com.example.jetnews',
393 'name': 'compose-jetnews',
394 'collections': ['compose-samples'],
395 'dump_app': 'dump_app.zip',
396 'apk_app': 'app-release-unsigned.apk',
397 'url': 'https://github.com/android/compose-samples',
398 'revision': '779cf9e187b8ee2c6b620b2abb4524719b3f10f8',
399 'folder': 'android/compose-samples/jetnews',
Christoffer Quist Adamsen53e29472020-11-13 10:53:06 +0100400 }),
401 # TODO(b/173167253): Check if monkey testing works.
402 App({
403 'id': 'com.example.jetsnack',
404 'name': 'compose-jetsnack',
405 'collections': ['compose-samples'],
406 'dump_app': 'dump_app.zip',
407 'apk_app': 'app-release-unsigned.apk',
408 'url': 'https://github.com/android/compose-samples',
409 'revision': '779cf9e187b8ee2c6b620b2abb4524719b3f10f8',
410 'folder': 'android/compose-samples/jetsnack',
411 }),
412 # TODO(b/173167253): Check if monkey testing works.
413 App({
414 'id': 'com.example.compose.jetsurvey',
415 'name': 'compose-jetsurvey',
416 'collections': ['compose-samples'],
417 'dump_app': 'dump_app.zip',
418 'apk_app': 'app-release-unsigned.apk',
419 'url': 'https://github.com/android/compose-samples',
420 'revision': '779cf9e187b8ee2c6b620b2abb4524719b3f10f8',
421 'folder': 'android/compose-samples/jetsurvey',
422 }),
423 # TODO(b/173167253): Check if monkey testing works.
424 App({
425 'id': 'com.example.owl',
426 'name': 'compose-owl',
427 'collections': ['compose-samples'],
428 'dump_app': 'dump_app.zip',
429 'apk_app': 'app-release-unsigned.apk',
430 'url': 'https://github.com/android/compose-samples',
431 'revision': '779cf9e187b8ee2c6b620b2abb4524719b3f10f8',
432 'folder': 'android/compose-samples/owl',
433 }),
434 # TODO(b/173167253): Check if monkey testing works.
435 App({
436 'id': 'com.example.compose.rally',
437 'name': 'compose-rally',
438 'collections': ['compose-samples'],
439 'dump_app': 'dump_app.zip',
440 'apk_app': 'app-release-unsigned.apk',
441 'url': 'https://github.com/android/compose-samples',
442 'revision': '779cf9e187b8ee2c6b620b2abb4524719b3f10f8',
443 'folder': 'android/compose-samples/rally',
444 }),
445]
446
447
448APP_COLLECTIONS = [
449 AppCollection({
450 'name': 'compose-samples',
451 })
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100452]
453
Morten Krogh-Jespersenf8e77032020-11-09 23:44:58 +0100454
Morten Krogh-Jespersendfeb0e32020-11-04 14:55:55 +0100455def remove_print_lines(file):
456 with open(file) as f:
457 lines = f.readlines()
458 with open(file, 'w') as f:
459 for line in lines:
460 if '-printconfiguration' not in line:
461 f.write(line)
462
463
Rico Wind61a034f2021-03-16 09:37:11 +0100464def download_sha(app_sha, internal, quiet=False):
Morten Krogh-Jespersen86222742021-03-02 11:13:33 +0100465 if internal:
466 utils.DownloadFromX20(app_sha)
467 else:
Rico Wind59593922021-03-03 09:12:36 +0100468 utils.DownloadFromGoogleCloudStorage(app_sha, quiet=quiet)
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100469
470
Morten Krogh-Jespersencd55f812020-11-04 09:13:31 +0100471def is_logging_enabled_for(app, options):
472 if options.no_logging:
473 return False
474 if options.app_logging_filter and app.name not in options.app_logging_filter:
475 return False
476 return True
477
478
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100479def is_minified_r8(shrinker):
480 return '-nolib' not in shrinker
481
482
483def is_full_r8(shrinker):
Morten Krogh-Jespersen270d0932020-11-11 11:05:57 +0100484 return '-full' in shrinker
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100485
486
Morten Krogh-Jespersen51db2b02020-11-11 12:49:26 +0100487def version_is_built_jar(version):
Rico Wind1b52acf2021-03-21 12:36:55 +0100488 return version != 'main' and version != 'source'
Morten Krogh-Jespersen51db2b02020-11-11 12:49:26 +0100489
490
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100491def compute_size_of_dex_files_in_package(path):
492 dex_size = 0
493 z = zipfile.ZipFile(path, 'r')
494 for filename in z.namelist():
495 if filename.endswith('.dex'):
496 dex_size += z.getinfo(filename).file_size
497 return dex_size
498
499
500def dump_for_app(app_dir, app):
501 return os.path.join(app_dir, app.dump_app)
502
503
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100504def dump_test_for_app(app_dir, app):
505 return os.path.join(app_dir, app.dump_test)
506
507
Morten Krogh-Jespersen51db2b02020-11-11 12:49:26 +0100508def get_r8_jar(options, temp_dir, shrinker):
509 if (options.version == 'source'):
510 return None
511 return os.path.join(
512 temp_dir, 'r8lib.jar' if is_minified_r8(shrinker) else 'r8.jar')
513
514
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100515def get_results_for_app(app, options, temp_dir):
516 app_folder = app.folder if app.folder else app.name + "_" + app.revision
Rico Windb2ae4c62021-06-01 15:09:56 +0200517 # Golem extraction will extract to the basename under the benchmarks dir.
518 app_location = os.path.basename(app_folder) if options.golem else app_folder
Rico Winde32a9c72021-03-16 09:00:06 +0100519 opensource_basedir = (os.path.join('benchmarks', app.name) if options.golem
520 else utils.OPENSOURCE_DUMPS_DIR)
Rico Windb2ae4c62021-06-01 15:09:56 +0200521 app_dir = (os.path.join(utils.INTERNAL_DUMPS_DIR, app_location) if app.internal
522 else os.path.join(opensource_basedir, app_location))
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100523 if not os.path.exists(app_dir) and not options.golem:
524 # Download the app from google storage.
Rico Wind61a034f2021-03-16 09:37:11 +0100525 download_sha(app_dir + ".tar.gz.sha1", app.internal)
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100526
527 # Ensure that the dumps are in place
528 assert os.path.isfile(dump_for_app(app_dir, app)), "Could not find dump " \
529 "for app " + app.name
530
531 result = {}
532 result['status'] = 'success'
533 result_per_shrinker = build_app_with_shrinkers(
534 app, options, temp_dir, app_dir)
Christoffer Quist Adamsena9ff1cf2021-01-13 08:49:48 +0100535 for shrinker, shrinker_result in result_per_shrinker.items():
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100536 result[shrinker] = shrinker_result
537 return result
538
539
540def build_app_with_shrinkers(app, options, temp_dir, app_dir):
541 result_per_shrinker = {}
542 for shrinker in options.shrinker:
543 results = []
544 build_app_and_run_with_shrinker(
545 app, options, temp_dir, app_dir, shrinker, results)
546 result_per_shrinker[shrinker] = results
547 if len(options.apps) > 1:
548 print('')
549 log_results_for_app(app, result_per_shrinker, options)
550 print('')
551
552 return result_per_shrinker
553
554
555def is_last_build(index, compilation_steps):
556 return index == compilation_steps - 1
557
558
559def build_app_and_run_with_shrinker(app, options, temp_dir, app_dir, shrinker,
560 results):
561 print('[{}] Building {} with {}'.format(
562 datetime.now().strftime("%H:%M:%S"),
563 app.name,
564 shrinker))
565 print('To compile locally: '
Morten Krogh-Jespersenf098b422020-11-11 13:53:52 +0100566 'tools/run_on_app_dump.py --shrinker {} --r8-compilation-steps {} '
Christoffer Quist Adamsenf86fc0b2021-12-10 12:39:36 +0100567 '--app {} --minify {} --optimize {} --shrink {}'.format(
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100568 shrinker,
569 options.r8_compilation_steps,
Christoffer Quist Adamsenf86fc0b2021-12-10 12:39:36 +0100570 app.name,
571 options.minify,
572 options.optimize,
573 options.shrink))
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100574 print('HINT: use --shrinker r8-nolib --no-build if you have a local R8.jar')
575 recomp_jar = None
576 status = 'success'
Morten Krogh-Jespersenee89b3a2020-11-13 11:59:43 +0100577 if options.r8_compilation_steps < 1:
578 return
579 compilation_steps = 1 if app.skip_recompilation else options.r8_compilation_steps
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100580 for compilation_step in range(0, compilation_steps):
581 if status != 'success':
582 break
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100583 print('Compiling {} of {}'.format(compilation_step + 1, compilation_steps))
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100584 result = {}
585 try:
586 start = time.time()
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100587 (app_jar, mapping, new_recomp_jar) = \
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100588 build_app_with_shrinker(
589 app, options, temp_dir, app_dir, shrinker, compilation_step,
590 compilation_steps, recomp_jar)
591 end = time.time()
592 dex_size = compute_size_of_dex_files_in_package(app_jar)
593 result['build_status'] = 'success'
594 result['recompilation_status'] = 'success'
595 result['output_jar'] = app_jar
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100596 result['output_mapping'] = mapping
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100597 result['dex_size'] = dex_size
598 result['duration'] = int((end - start) * 1000) # Wall time
599 if (new_recomp_jar is None
600 and not is_last_build(compilation_step, compilation_steps)):
601 result['recompilation_status'] = 'failed'
602 warn('Failed to build {} with {}'.format(app.name, shrinker))
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100603 recomp_jar = new_recomp_jar
604 except Exception as e:
605 warn('Failed to build {} with {}'.format(app.name, shrinker))
606 if e:
607 print('Error: ' + str(e))
608 result['build_status'] = 'failed'
609 status = 'failed'
610
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100611 original_app_apk = os.path.join(app_dir, app.apk_app)
612 app_apk_destination = os.path.join(
613 temp_dir,"{}_{}.apk".format(app.id, compilation_step))
614
Morten Krogh-Jespersencd55f812020-11-04 09:13:31 +0100615 if result.get('build_status') == 'success' and options.monkey:
616 # Make a copy of the given APK, move the newly generated dex files into the
617 # copied APK, and then sign the APK.
Morten Krogh-Jespersencd55f812020-11-04 09:13:31 +0100618 apk_masseur.masseur(
619 original_app_apk, dex=app_jar, resources='META-INF/services/*',
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100620 out=app_apk_destination,
Morten Krogh-Jespersencd55f812020-11-04 09:13:31 +0100621 quiet=options.quiet, logging=is_logging_enabled_for(app, options),
622 keystore=options.keystore)
623
624 result['monkey_status'] = 'success' if adb.run_monkey(
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100625 app.id, options.emulator_id, app_apk_destination, options.monkey_events,
Morten Krogh-Jespersencd55f812020-11-04 09:13:31 +0100626 options.quiet, is_logging_enabled_for(app, options)) else 'failed'
627
Morten Krogh-Jespersen571cfe72020-11-09 23:44:03 +0100628 if (result.get('build_status') == 'success'
629 and options.run_tests and app.dump_test):
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100630 if not os.path.isfile(app_apk_destination):
631 apk_masseur.masseur(
632 original_app_apk, dex=app_jar, resources='META-INF/services/*',
633 out=app_apk_destination,
634 quiet=options.quiet, logging=is_logging_enabled_for(app, options),
635 keystore=options.keystore)
636
637 # Compile the tests with the mapping file.
638 test_jar = build_test_with_shrinker(
639 app, options, temp_dir, app_dir,shrinker, compilation_step,
640 result['output_mapping'])
Morten Krogh-Jespersen162b3452020-11-05 13:07:10 +0100641 if not test_jar:
642 result['instrumentation_test_status'] = 'compilation_failed'
643 else:
644 original_test_apk = os.path.join(app_dir, app.apk_test)
645 test_apk_destination = os.path.join(
646 temp_dir,"{}_{}.test.apk".format(app.id_test, compilation_step))
647 apk_masseur.masseur(
648 original_test_apk, dex=test_jar, resources='META-INF/services/*',
649 out=test_apk_destination,
650 quiet=options.quiet, logging=is_logging_enabled_for(app, options),
651 keystore=options.keystore)
652 result['instrumentation_test_status'] = 'success' if adb.run_instrumented(
653 app.id, app.id_test, options.emulator_id, app_apk_destination,
654 test_apk_destination, options.quiet,
655 is_logging_enabled_for(app, options)) else 'failed'
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100656
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100657 results.append(result)
Morten Krogh-Jespersencd55f812020-11-04 09:13:31 +0100658 if result.get('recompilation_status') != 'success':
659 break
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100660
Rico Wind33936d12021-04-07 08:04:14 +0200661def get_jdk_home(options, app):
Rico Winda74174d2021-04-07 09:10:35 +0200662 if options.golem:
Rico Wind33936d12021-04-07 08:04:14 +0200663 return os.path.join('benchmarks', app.name, 'linux')
664 return None
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100665
666def build_app_with_shrinker(app, options, temp_dir, app_dir, shrinker,
667 compilation_step_index, compilation_steps,
668 prev_recomp_jar):
Christoffer Quist Adamsen3f21c2b2023-02-28 09:37:22 +0100669 def config_files_consumer(files):
670 for file in files:
671 compiledump.clean_config(file, options)
672 remove_print_lines(file)
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100673 args = AttrDict({
674 'dump': dump_for_app(app_dir, app),
Morten Krogh-Jespersen51db2b02020-11-11 12:49:26 +0100675 'r8_jar': get_r8_jar(options, temp_dir, shrinker),
Christoffer Quist Adamsen2f48f3f2021-10-14 17:25:03 +0200676 'r8_flags': options.r8_flags,
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100677 'ea': False if options.disable_assertions else True,
Morten Krogh-Jespersen51db2b02020-11-11 12:49:26 +0100678 'version': options.version,
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100679 'compiler': 'r8full' if is_full_r8(shrinker) else 'r8',
680 'debug_agent': options.debug_agent,
681 'program_jar': prev_recomp_jar,
Morten Krogh-Jespersendfeb0e32020-11-04 14:55:55 +0100682 'nolib': not is_minified_r8(shrinker),
Christoffer Quist Adamsen3f21c2b2023-02-28 09:37:22 +0100683 'config_files_consumer': config_files_consumer,
Morten Krogh-Jespersen43f3cea2020-11-12 17:09:51 +0100684 'properties': app.compiler_properties,
Morten Krogh-Jespersend86a81b2020-11-13 12:33:26 +0100685 'disable_desugared_lib': False,
Morten Krogh-Jespersen6c702402021-06-21 12:29:48 +0200686 'print_times': options.print_times,
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100687 })
688
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100689 app_jar = os.path.join(
690 temp_dir, '{}_{}_{}_dex_out.jar'.format(
691 app.name, shrinker, compilation_step_index))
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100692 app_mapping = os.path.join(
693 temp_dir, '{}_{}_{}_dex_out.jar.map'.format(
694 app.name, shrinker, compilation_step_index))
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100695 recomp_jar = None
Rico Wind33936d12021-04-07 08:04:14 +0200696 jdkhome = get_jdk_home(options, app)
Morten Krogh-Jespersenc9d23462020-11-12 15:36:57 +0100697 with utils.TempDir() as compile_temp_dir:
Rico Wind33936d12021-04-07 08:04:14 +0200698 compile_result = compiledump.run1(compile_temp_dir, args, [], jdkhome)
Morten Krogh-Jespersenc9d23462020-11-12 15:36:57 +0100699 out_jar = os.path.join(compile_temp_dir, "out.jar")
700 out_mapping = os.path.join(compile_temp_dir, "out.jar.map")
701
702 if compile_result != 0 or not os.path.isfile(out_jar):
703 assert False, 'Compilation of {} failed'.format(dump_for_app(app_dir, app))
704 shutil.move(out_jar, app_jar)
705 shutil.move(out_mapping, app_mapping)
706
707 if compilation_step_index < compilation_steps - 1:
708 args['classfile'] = True
709 args['min_api'] = "10000"
Morten Krogh-Jespersend86a81b2020-11-13 12:33:26 +0100710 args['disable_desugared_lib'] = True
Rico Wind33936d12021-04-07 08:04:14 +0200711 compile_result = compiledump.run1(compile_temp_dir, args, [], jdkhome)
Morten Krogh-Jespersenc9d23462020-11-12 15:36:57 +0100712 if compile_result == 0:
713 recomp_jar = os.path.join(
714 temp_dir, '{}_{}_{}_cf_out.jar'.format(
715 app.name, shrinker, compilation_step_index))
716 shutil.move(out_jar, recomp_jar)
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100717
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100718 return (app_jar, app_mapping, recomp_jar)
719
Morten Krogh-Jespersen162b3452020-11-05 13:07:10 +0100720
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100721def build_test_with_shrinker(app, options, temp_dir, app_dir, shrinker,
722 compilation_step_index, mapping):
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100723
Christoffer Quist Adamsen3f21c2b2023-02-28 09:37:22 +0100724 def rewrite_files(files):
725 add_applymapping = True
726 for file in files:
727 compiledump.clean_config(file, options)
728 remove_print_lines(file)
729 with open(file) as f:
730 lines = f.readlines()
731 with open(file, 'w') as f:
732 for line in lines:
733 if '-applymapping' not in line:
734 f.write(line + '\n')
735 if add_applymapping:
736 f.write("-applymapping " + mapping + '\n')
737 add_applymapping = False
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100738
739 args = AttrDict({
740 'dump': dump_test_for_app(app_dir, app),
Morten Krogh-Jespersen51db2b02020-11-11 12:49:26 +0100741 'r8_jar': get_r8_jar(options, temp_dir, shrinker),
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100742 'ea': False if options.disable_assertions else True,
Morten Krogh-Jespersen51db2b02020-11-11 12:49:26 +0100743 'version': options.version,
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100744 'compiler': 'r8full' if is_full_r8(shrinker) else 'r8',
745 'debug_agent': options.debug_agent,
746 'nolib': not is_minified_r8(shrinker),
747 # The config file will have an -applymapping reference to an old map.
748 # Update it to point to mapping file build in the compilation of the app.
Christoffer Quist Adamsen3f21c2b2023-02-28 09:37:22 +0100749 'config_files_consumer': rewrite_files,
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100750 })
751
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100752 test_jar = os.path.join(
753 temp_dir, '{}_{}_{}_test_out.jar'.format(
754 app.name, shrinker, compilation_step_index))
755
Morten Krogh-Jespersenc9d23462020-11-12 15:36:57 +0100756 with utils.TempDir() as compile_temp_dir:
Rico Wind33936d12021-04-07 08:04:14 +0200757 jdkhome = get_jdk_home(options, app)
758 compile_result = compiledump.run1(compile_temp_dir, args, [], jdkhome)
Morten Krogh-Jespersenc9d23462020-11-12 15:36:57 +0100759 out_jar = os.path.join(compile_temp_dir, "out.jar")
760 if compile_result != 0 or not os.path.isfile(out_jar):
761 return None
762 shutil.move(out_jar, test_jar)
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100763
764 return test_jar
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100765
766
767def log_results_for_apps(result_per_shrinker_per_app, options):
768 print('')
769 app_errors = 0
770 for (app, result_per_shrinker) in result_per_shrinker_per_app:
771 app_errors += (1 if log_results_for_app(app, result_per_shrinker, options)
772 else 0)
773 return app_errors
774
775
776def log_results_for_app(app, result_per_shrinker, options):
777 if options.print_dexsegments:
778 log_segments_for_app(app, result_per_shrinker, options)
779 return False
780 else:
781 return log_comparison_results_for_app(app, result_per_shrinker, options)
782
783
784def log_segments_for_app(app, result_per_shrinker, options):
785 for shrinker in SHRINKERS:
786 if shrinker not in result_per_shrinker:
787 continue
788 for result in result_per_shrinker.get(shrinker):
789 benchmark_name = '{}-{}'.format(options.print_dexsegments, app.name)
790 utils.print_dexsegments(benchmark_name, [result.get('output_jar')])
791 duration = result.get('duration')
792 print('%s-Total(RunTimeRaw): %s ms' % (benchmark_name, duration))
793 print('%s-Total(CodeSize): %s' % (benchmark_name, result.get('dex_size')))
794
795
796def percentage_diff_as_string(before, after):
797 if after < before:
798 return '-' + str(round((1.0 - after / before) * 100)) + '%'
799 else:
800 return '+' + str(round((after - before) / before * 100)) + '%'
801
802
803def log_comparison_results_for_app(app, result_per_shrinker, options):
804 print(app.name + ':')
805 app_error = False
806 if result_per_shrinker.get('status', 'success') != 'success':
807 error_message = result_per_shrinker.get('error_message')
808 print(' skipped ({})'.format(error_message))
809 return
810
811 proguard_result = result_per_shrinker.get('pg', {})
812 proguard_dex_size = float(proguard_result.get('dex_size', -1))
813
814 for shrinker in SHRINKERS:
815 if shrinker not in result_per_shrinker:
816 continue
817 compilation_index = 1
818 for result in result_per_shrinker.get(shrinker):
819 build_status = result.get('build_status')
820 if build_status != 'success' and build_status is not None:
821 app_error = True
822 warn(' {}-#{}: {}'.format(shrinker, compilation_index, build_status))
823 continue
824
Rico Wind59593922021-03-03 09:12:36 +0100825 if options.golem:
826 print('%s(RunTimeRaw): %s ms' % (app.name, result.get('duration')))
827 print('%s(CodeSize): %s' % (app.name, result.get('dex_size')))
828 continue
829
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100830 print(' {}-#{}:'.format(shrinker, compilation_index))
831 dex_size = result.get('dex_size')
832 msg = ' dex size: {}'.format(dex_size)
Rudi Horn82e7d222020-11-17 11:22:39 +0000833 if options.print_runtimeraw:
834 print(' run time raw: {} ms'.format(result.get('duration')))
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100835 if dex_size != proguard_dex_size and proguard_dex_size >= 0:
836 msg = '{} ({}, {})'.format(
837 msg, dex_size - proguard_dex_size,
838 percentage_diff_as_string(proguard_dex_size, dex_size))
839 success(msg) if dex_size < proguard_dex_size else warn(msg)
840 else:
841 print(msg)
842
Morten Krogh-Jespersencd55f812020-11-04 09:13:31 +0100843 if options.monkey:
844 monkey_status = result.get('monkey_status')
845 if monkey_status != 'success':
846 app_error = True
847 warn(' monkey: {}'.format(monkey_status))
848 else:
849 success(' monkey: {}'.format(monkey_status))
850
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100851 if options.run_tests and 'instrumentation_test_status' in result:
852 test_status = result.get('instrumentation_test_status')
853 if test_status != 'success':
854 warn(' instrumentation_tests: {}'.format(test_status))
855 else:
856 success(' instrumentation_tests: {}'.format(test_status))
857
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100858 recompilation_status = result.get('recompilation_status', '')
859 if recompilation_status == 'failed':
860 app_error = True
861 warn(' recompilation {}-#{}: failed'.format(shrinker,
862 compilation_index))
863 continue
864
865 compilation_index += 1
866
867 return app_error
868
869
870def parse_options(argv):
Morten Krogh-Jespersen6c702402021-06-21 12:29:48 +0200871 result = argparse.ArgumentParser(description = 'Run/compile dump artifacts.')
872 result.add_argument('--app',
873 help='What app to run on',
874 choices=[app.name for app in APPS],
875 action='append')
876 result.add_argument('--app-collection', '--app_collection',
877 help='What app collection to run',
878 choices=[collection.name for collection in
879 APP_COLLECTIONS],
880 action='append')
881 result.add_argument('--app-logging-filter', '--app_logging_filter',
882 help='The apps for which to turn on logging',
883 action='append')
884 result.add_argument('--bot',
885 help='Running on bot, use third_party dependency.',
886 default=False,
887 action='store_true')
888 result.add_argument('--generate-golem-config', '--generate_golem_config',
889 help='Generate a new config for golem.',
890 default=False,
891 action='store_true')
892 result.add_argument('--debug-agent',
893 help='Enable Java debug agent and suspend compilation '
894 '(default disabled)',
895 default=False,
896 action='store_true')
897 result.add_argument('--disable-assertions', '--disable_assertions',
898 help='Disable assertions when compiling',
899 default=False,
900 action='store_true')
901 result.add_argument('--emulator-id', '--emulator_id',
902 help='Id of the emulator to use',
903 default='emulator-5554')
904 result.add_argument('--golem',
905 help='Running on golem, do not download',
906 default=False,
907 action='store_true')
908 result.add_argument('--hash',
909 help='The commit of R8 to use')
910 result.add_argument('--internal',
911 help='Run internal apps if set, otherwise run opensource',
912 default=False,
913 action='store_true')
914 result.add_argument('--keystore',
915 help='Path to app.keystore',
916 default=os.path.join(utils.TOOLS_DIR, 'debug.keystore'))
917 result.add_argument('--keystore-password', '--keystore_password',
918 help='Password for app.keystore',
919 default='android')
Christoffer Quist Adamsenf86fc0b2021-12-10 12:39:36 +0100920 result.add_argument('--minify',
921 help='Force enable/disable minification' +
922 ' (defaults to app proguard config)',
923 choices=['default', 'force-enable', 'force-disable'],
924 default='default')
Morten Krogh-Jespersen6c702402021-06-21 12:29:48 +0200925 result.add_argument('--monkey',
926 help='Whether to install and run app(s) with monkey',
927 default=False,
928 action='store_true')
929 result.add_argument('--monkey-events', '--monkey_events',
930 help='Number of events that the monkey should trigger',
931 default=250,
932 type=int)
933 result.add_argument('--no-build', '--no_build',
934 help='Run without building first (only when using ToT)',
935 default=False,
936 action='store_true')
937 result.add_argument('--no-logging', '--no_logging',
938 help='Disable logging except for errors',
939 default=False,
940 action='store_true')
Christoffer Quist Adamsenf86fc0b2021-12-10 12:39:36 +0100941 result.add_argument('--optimize',
942 help='Force enable/disable optimizations' +
943 ' (defaults to app proguard config)',
944 choices=['default', 'force-enable', 'force-disable'],
945 default='default')
Morten Krogh-Jespersen6c702402021-06-21 12:29:48 +0200946 result.add_argument('--print-times',
947 help='Print timing information from r8',
948 default=False,
949 action='store_true')
950 result.add_argument('--print-dexsegments',
951 metavar='BENCHMARKNAME',
952 help='Print the sizes of individual dex segments as ' +
953 '\'<BENCHMARKNAME>-<APP>-<segment>(CodeSize): '
954 '<bytes>\'')
955 result.add_argument('--print-runtimeraw',
956 metavar='BENCHMARKNAME',
957 help='Print the line \'<BENCHMARKNAME>(RunTimeRaw):' +
958 ' <elapsed> ms\' at the end where <elapsed> is' +
959 ' the elapsed time in milliseconds.')
960 result.add_argument('--quiet',
961 help='Disable verbose logging',
962 default=False,
963 action='store_true')
964 result.add_argument('--r8-compilation-steps', '--r8_compilation_steps',
965 help='Number of times R8 should be run on each app',
966 default=2,
967 type=int)
Christoffer Quist Adamsen2f48f3f2021-10-14 17:25:03 +0200968 result.add_argument('--r8-flags', '--r8_flags',
969 help='Additional option(s) for the compiler.')
Morten Krogh-Jespersen6c702402021-06-21 12:29:48 +0200970 result.add_argument('--run-tests', '--run_tests',
971 help='Whether to run instrumentation tests',
972 default=False,
973 action='store_true')
Christoffer Quist Adamsenf86fc0b2021-12-10 12:39:36 +0100974 result.add_argument('--shrink',
975 help='Force enable/disable shrinking' +
976 ' (defaults to app proguard config)',
977 choices=['default', 'force-enable', 'force-disable'],
978 default='default')
Morten Krogh-Jespersen6c702402021-06-21 12:29:48 +0200979 result.add_argument('--sign-apks', '--sign_apks',
980 help='Whether the APKs should be signed',
981 default=False,
982 action='store_true')
983 result.add_argument('--shrinker',
984 help='The shrinkers to use (by default, all are run)',
985 action='append')
Ian Zernyf5a57ec2021-11-25 14:02:07 +0100986 result.add_argument('--temp',
987 help='A directory to use for temporaries and outputs.',
988 default=None)
Morten Krogh-Jespersen6c702402021-06-21 12:29:48 +0200989 result.add_argument('--version',
990 default='main',
991 help='The version of R8 to use (e.g., 1.4.51)')
992 (options, args) = result.parse_known_args(argv)
Christoffer Quist Adamsen53e29472020-11-13 10:53:06 +0100993
994 if options.app or options.app_collection:
995 if not options.app:
996 options.app = []
997 if not options.app_collection:
998 options.app_collection = []
999 options.apps = [
1000 app
1001 for app in APPS
1002 if app.name in options.app
1003 or any(collection in options.app_collection
1004 for collection in app.collections)]
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +01001005 del options.app
Christoffer Quist Adamsen53e29472020-11-13 10:53:06 +01001006 del options.app_collection
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +01001007 else:
Morten Krogh-Jespersen86222742021-03-02 11:13:33 +01001008 options.apps = [app for app in APPS if app.internal == options.internal]
Christoffer Quist Adamsen53e29472020-11-13 10:53:06 +01001009
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +01001010 if options.app_logging_filter:
1011 for app_name in options.app_logging_filter:
1012 assert any(app.name == app_name for app in options.apps)
1013 if options.shrinker:
1014 for shrinker in options.shrinker:
Christoffer Quist Adamsena9ff1cf2021-01-13 08:49:48 +01001015 assert shrinker in SHRINKERS, (
1016 'Shrinker must be one of %s' % ', '.join(SHRINKERS))
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +01001017 else:
1018 options.shrinker = [shrinker for shrinker in SHRINKERS]
1019
Morten Krogh-Jespersen51db2b02020-11-11 12:49:26 +01001020 if options.hash or version_is_built_jar(options.version):
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +01001021 # No need to build R8 if a specific version should be used.
1022 options.no_build = True
1023 if 'r8-nolib' in options.shrinker:
1024 warn('Skipping shrinker r8-nolib because a specific version '
1025 + 'of r8 was specified')
1026 options.shrinker.remove('r8-nolib')
1027 if 'r8-nolib-full' in options.shrinker:
1028 warn('Skipping shrinker r8-nolib-full because a specific version '
1029 + 'of r8 was specified')
1030 options.shrinker.remove('r8-nolib-full')
1031 return (options, args)
1032
1033
Rico Wind59593922021-03-03 09:12:36 +01001034def print_indented(s, indent):
1035 print(' ' * indent + s)
1036
1037
1038def get_sha256(gz_file):
1039 with open(gz_file, 'rb') as f:
1040 bytes = f.read() # read entire file as bytes
1041 return hashlib.sha256(bytes).hexdigest();
1042
1043
1044def get_sha_from_file(sha_file):
1045 with open(sha_file, 'r') as f:
1046 return f.readlines()[0]
1047
1048
1049def print_golem_config(options):
1050 print('// AUTOGENERATED FILE from tools/run_on_app_dump.py in R8 repo')
Rico Windca91a952021-03-03 09:34:54 +01001051 print('part of r8_config;')
Rico Wind71ea2862021-03-03 10:17:59 +01001052 print('')
Ian Zernyd3af0992022-10-06 20:12:04 +02001053 print('final Suite dumpsSuite = Suite("OpenSourceAppDumps");')
Rico Wind59593922021-03-03 09:12:36 +01001054 print('')
1055 print('createOpenSourceAppBenchmarks() {')
Rico Wind1abf5482021-03-03 13:55:43 +01001056 print_indented('final cpus = ["Lenovo M90"];', 2)
Christoffer Quist Adamsen8e9f7982021-12-10 13:10:05 +01001057 print_indented('final targetsCompat = ["R8"];', 2)
1058 print_indented('final targetsFull = ["R8-full-minify-optimize-shrink"];', 2)
Rico Wind61a034f2021-03-16 09:37:11 +01001059 # Avoid calculating this for every app
1060 jdk_gz = jdk.GetJdkHome() + '.tar.gz'
Ian Zerny161ff742022-01-20 12:39:40 +01001061 add_golem_resource(2, jdk_gz, 'openjdk')
Rico Wind59593922021-03-03 09:12:36 +01001062 for app in options.apps:
1063 if app.folder and not app.internal:
1064 indentation = 2;
1065 print_indented('{', indentation)
1066 indentation = 4
Rico Wind641e79a2021-03-04 09:12:07 +01001067 print_indented('final name = "%s";' % app.name, indentation)
1068 print_indented('final benchmark =', indentation)
Rico Wind59593922021-03-03 09:12:36 +01001069 print_indented(
Ian Zernyc013b702022-03-08 16:26:27 +01001070 'StandardBenchmark(name, [Metric.RunTimeRaw, Metric.CodeSize]);',
Rico Wind59593922021-03-03 09:12:36 +01001071 indentation + 4)
Morten Krogh-Jespersen9e7951b2022-08-10 15:05:26 +02001072 if app.golem_duration != None:
1073 print_indented(
1074 'final timeout = const Duration(seconds: %s);' % app.golem_duration,
1075 indentation)
1076 print_indented(
1077 'ExecutionManagement.addTimeoutConstraint'
1078 '(timeout, benchmark: benchmark);', indentation)
Rico Wind59593922021-03-03 09:12:36 +01001079 app_gz = os.path.join(utils.OPENSOURCE_DUMPS_DIR, app.folder + '.tar.gz')
Rico Wind5102b912021-06-02 07:50:49 +02001080 name = 'appResource'
1081 add_golem_resource(indentation, app_gz, name)
Christoffer Quist Adamsen8e9f7982021-12-10 13:10:05 +01001082 print_golem_config_target('Compat', 'r8', app, indentation)
1083 print_golem_config_target(
1084 'Full',
1085 'r8-full',
1086 app,
1087 indentation,
1088 minify='force-enable',
1089 optimize='force-enable',
1090 shrink='force-enable')
Rico Wind59593922021-03-03 09:12:36 +01001091 print_indented('dumpsSuite.addBenchmark(name);', indentation)
1092 indentation = 2
1093 print_indented('}', indentation)
1094 print('}')
1095
Christoffer Quist Adamsen8e9f7982021-12-10 13:10:05 +01001096def print_golem_config_target(
1097 target, shrinker, app, indentation,
1098 minify='default', optimize='default', shrink='default'):
1099 options="options" + target
1100 print_indented(
1101 'final %s = benchmark.addTargets(noImplementation, targets%s);'
1102 % (options, target),
1103 indentation)
1104 print_indented('%s.cpus = cpus;' % options, indentation)
1105 print_indented('%s.isScript = true;' % options, indentation)
1106 print_indented('%s.fromRevision = 9700;' % options, indentation);
1107 print_indented('%s.mainFile = "tools/run_on_app_dump.py "' % options,
1108 indentation)
1109 print_indented('"--golem --quiet --shrinker %s --app %s "'
1110 % (shrinker, app.name),
1111 indentation + 4)
1112 print_indented('"--minify %s --optimize %s --shrink %s";'
1113 % (minify, optimize, shrink),
1114 indentation + 4)
1115 print_indented('%s.resources.add(appResource);' % options, indentation)
1116 print_indented('%s.resources.add(openjdk);' % options, indentation)
1117
Rico Wind61a034f2021-03-16 09:37:11 +01001118def add_golem_resource(indentation, gz, name, sha256=None):
1119 sha = gz + '.sha1'
1120 if not sha256:
1121 # Golem uses a sha256 of the file in the cache, and you need to specify that.
1122 download_sha(sha, False, quiet=True)
1123 sha256 = get_sha256(gz)
1124 sha = get_sha_from_file(sha)
1125 print_indented('final %s = BenchmarkResource("",' % name, indentation)
Ian Zernyc013b702022-03-08 16:26:27 +01001126 print_indented('type: BenchmarkResourceType.storage,', indentation + 4)
Rico Wind61a034f2021-03-16 09:37:11 +01001127 print_indented('uri: "gs://r8-deps/%s",' % sha, indentation + 4)
Rico Wind5102b912021-06-02 07:50:49 +02001128 # Make dart formatter happy.
1129 if indentation > 2:
1130 print_indented('hash:', indentation + 4)
1131 print_indented('"%s",' % sha256, indentation + 8)
1132 else:
1133 print_indented('hash: "%s",' % sha256, indentation + 4)
Rico Wind61a034f2021-03-16 09:37:11 +01001134 print_indented('extract: "gz");', indentation + 4);
Rico Wind61a034f2021-03-16 09:37:11 +01001135
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +01001136def main(argv):
1137 (options, args) = parse_options(argv)
1138
1139 if options.bot:
1140 options.no_logging = True
1141 options.shrinker = ['r8', 'r8-full']
1142 print(options.shrinker)
1143
1144 if options.golem:
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +01001145 options.disable_assertions = True
1146 options.no_build = True
1147 options.r8_compilation_steps = 1
1148 options.quiet = True
1149 options.no_logging = True
1150
Rico Wind59593922021-03-03 09:12:36 +01001151 if options.generate_golem_config:
1152 print_golem_config(options)
1153 return 0
1154
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +01001155 with utils.TempDir() as temp_dir:
Ian Zernyf5a57ec2021-11-25 14:02:07 +01001156 if options.temp:
1157 temp_dir = options.temp
Ian Zerny7b500ba2022-02-03 16:41:17 +01001158 os.makedirs(temp_dir, exist_ok=True)
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +01001159 if options.hash:
1160 # Download r8-<hash>.jar from
1161 # https://storage.googleapis.com/r8-releases/raw/.
1162 target = 'r8-{}.jar'.format(options.hash)
1163 update_prebuilds_in_android.download_hash(
1164 temp_dir, 'com/android/tools/r8/' + options.hash, target)
1165 as_utils.MoveFile(
1166 os.path.join(temp_dir, target), os.path.join(temp_dir, 'r8lib.jar'),
1167 quiet=options.quiet)
Morten Krogh-Jespersen51db2b02020-11-11 12:49:26 +01001168 elif version_is_built_jar(options.version):
1169 # Download r8-<version>.jar from
1170 # https://storage.googleapis.com/r8-releases/raw/.
1171 target = 'r8-{}.jar'.format(options.version)
1172 update_prebuilds_in_android.download_version(
1173 temp_dir, 'com/android/tools/r8/' + options.version, target)
1174 as_utils.MoveFile(
1175 os.path.join(temp_dir, target), os.path.join(temp_dir, 'r8lib.jar'),
1176 quiet=options.quiet)
Rico Wind1b52acf2021-03-21 12:36:55 +01001177 elif options.version == 'main':
Ian Zerny161ff742022-01-20 12:39:40 +01001178 if not options.no_build:
Rico Windfc5ad672021-11-15 13:14:36 +01001179 gradle.RunGradle(['R8Retrace', 'r8', '-Pno_internal'])
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +01001180 build_r8lib = False
1181 for shrinker in options.shrinker:
1182 if is_minified_r8(shrinker):
1183 build_r8lib = True
1184 if build_r8lib:
1185 gradle.RunGradle(['r8lib', '-Pno_internal'])
1186 # Make a copy of r8.jar and r8lib.jar such that they stay the same for
1187 # the entire execution of this script.
1188 if 'r8-nolib' in options.shrinker or 'r8-nolib-full' in options.shrinker:
1189 assert os.path.isfile(utils.R8_JAR), 'Cannot build without r8.jar'
1190 shutil.copyfile(utils.R8_JAR, os.path.join(temp_dir, 'r8.jar'))
1191 if 'r8' in options.shrinker or 'r8-full' in options.shrinker:
1192 assert os.path.isfile(utils.R8LIB_JAR), 'Cannot build without r8lib.jar'
1193 shutil.copyfile(utils.R8LIB_JAR, os.path.join(temp_dir, 'r8lib.jar'))
1194
1195 result_per_shrinker_per_app = []
1196 for app in options.apps:
1197 if app.skip:
1198 continue
1199 result_per_shrinker_per_app.append(
1200 (app, get_results_for_app(app, options, temp_dir)))
Morten Krogh-Jespersenf098b422020-11-11 13:53:52 +01001201 errors = log_results_for_apps(result_per_shrinker_per_app, options)
1202 if errors > 0:
1203 dest = 'gs://r8-test-results/r8-libs/' + str(int(time.time()))
1204 utils.upload_file_to_cloud_storage(os.path.join(temp_dir, 'r8lib.jar'), dest)
1205 print('R8lib saved to %s' % dest)
1206 return errors
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +01001207
1208
1209def success(message):
1210 CGREEN = '\033[32m'
1211 CEND = '\033[0m'
1212 print(CGREEN + message + CEND)
1213
1214
1215def warn(message):
1216 CRED = '\033[91m'
1217 CEND = '\033[0m'
1218 print(CRED + message + CEND)
1219
1220
1221if __name__ == '__main__':
1222 sys.exit(main(sys.argv[1:]))