xref: /aosp_15_r20/external/angle/build/android/docs/java_optimization.md (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1*8975f5c5SAndroid Build Coastguard Worker# Optimizing Java Code
2*8975f5c5SAndroid Build Coastguard Worker
3*8975f5c5SAndroid Build Coastguard WorkerThis doc describes how Java code is optimized in Chrome on Android and how to
4*8975f5c5SAndroid Build Coastguard Workerdeal with issues caused by the optimizer. For tips on how to write optimized
5*8975f5c5SAndroid Build Coastguard Workercode, see [//docs/speed/binary_size/optimization_advice.md#optimizing-java-code](/docs/speed/binary_size/optimization_advice.md#optimizing-java-code).
6*8975f5c5SAndroid Build Coastguard Worker
7*8975f5c5SAndroid Build Coastguard Worker[TOC]
8*8975f5c5SAndroid Build Coastguard Worker
9*8975f5c5SAndroid Build Coastguard Worker## ProGuard vs R8
10*8975f5c5SAndroid Build Coastguard Worker
11*8975f5c5SAndroid Build Coastguard WorkerProGuard is the original open-source tool used by many Android applications to
12*8975f5c5SAndroid Build Coastguard Workerperform whole-program bytecode optimization. [R8](https://r8.googlesource.com/r8),
13*8975f5c5SAndroid Build Coastguard Workeris a re-implementation that is used by Chrome (and the default for Android Studio).
14*8975f5c5SAndroid Build Coastguard WorkerThe terms "ProGuard" and "R8" are used interchangeably within Chromium but
15*8975f5c5SAndroid Build Coastguard Workergenerally they're meant to refer to the tool providing Java code optimizations.
16*8975f5c5SAndroid Build Coastguard Worker
17*8975f5c5SAndroid Build Coastguard Worker## What does ProGuard do?
18*8975f5c5SAndroid Build Coastguard Worker
19*8975f5c5SAndroid Build Coastguard Worker1. Shrinking: ProGuard will remove unused code. This is especially useful
20*8975f5c5SAndroid Build Coastguard Worker   when depending on third party libraries where only a few functions are used.
21*8975f5c5SAndroid Build Coastguard Worker
22*8975f5c5SAndroid Build Coastguard Worker2. Obfuscation: ProGuard will rename classes/fields/methods to use shorter
23*8975f5c5SAndroid Build Coastguard Worker   names. Obfuscation is used for minification purposes only (not security).
24*8975f5c5SAndroid Build Coastguard Worker
25*8975f5c5SAndroid Build Coastguard Worker3. Optimization: ProGuard performs a series of optimizations to shrink code
26*8975f5c5SAndroid Build Coastguard Worker   further through various approaches (ex. inlining, outlining, class merging,
27*8975f5c5SAndroid Build Coastguard Worker   etc).
28*8975f5c5SAndroid Build Coastguard Worker
29*8975f5c5SAndroid Build Coastguard Worker## Build Process
30*8975f5c5SAndroid Build Coastguard Worker
31*8975f5c5SAndroid Build Coastguard WorkerProGuard is enabled only for release builds of Chrome because it is a slow build
32*8975f5c5SAndroid Build Coastguard Workerstep and breaks Java debugging. It can also be enabled manually via the GN arg:
33*8975f5c5SAndroid Build Coastguard Worker```is_java_debug = false```
34*8975f5c5SAndroid Build Coastguard Worker
35*8975f5c5SAndroid Build Coastguard Worker### ProGuard configuration files
36*8975f5c5SAndroid Build Coastguard Worker
37*8975f5c5SAndroid Build Coastguard WorkerMost GN Java targets can specify ProGuard configuration files by setting the
38*8975f5c5SAndroid Build Coastguard Worker`proguard_configs` variable. [//base/android/proguard](/base/android/proguard)
39*8975f5c5SAndroid Build Coastguard Workercontains common flags shared by most Chrome applications.
40*8975f5c5SAndroid Build Coastguard Worker
41*8975f5c5SAndroid Build Coastguard Worker### GN build rules
42*8975f5c5SAndroid Build Coastguard Worker
43*8975f5c5SAndroid Build Coastguard WorkerWhen `is_java_debug = false` and a target has enabled ProGuard, the `proguard`
44*8975f5c5SAndroid Build Coastguard Workerstep generates the `.dex` files for the application. The `proguard` step takes
45*8975f5c5SAndroid Build Coastguard Workeras input a list of `.jar` files, runs R8/ProGuard on those `.jar` files, and
46*8975f5c5SAndroid Build Coastguard Workerproduces the final `.dex` file(s) that will be packaged into your `.apk`
47*8975f5c5SAndroid Build Coastguard Worker
48*8975f5c5SAndroid Build Coastguard Worker## Deobfuscation
49*8975f5c5SAndroid Build Coastguard Worker
50*8975f5c5SAndroid Build Coastguard WorkerObfuscation can be turned off for local builds while leaving ProGuard enabled
51*8975f5c5SAndroid Build Coastguard Workerby setting `enable_proguard_obfuscation = false` in GN args.
52*8975f5c5SAndroid Build Coastguard Worker
53*8975f5c5SAndroid Build Coastguard WorkerThere are two main methods for deobfuscating Java stack traces locally:
54*8975f5c5SAndroid Build Coastguard Worker1. Using APK wrapper scripts (stacks are automatically deobfuscated)
55*8975f5c5SAndroid Build Coastguard Worker  * `$OUT/bin/chrome_public_apk logcat`  # Run adb logcat
56*8975f5c5SAndroid Build Coastguard Worker  * `$OUT/bin/chrome_public_apk run`  # Launch chrome and run adb logcat
57*8975f5c5SAndroid Build Coastguard Worker
58*8975f5c5SAndroid Build Coastguard Worker2. Using `java_deobfuscate`
59*8975f5c5SAndroid Build Coastguard Worker  * build/android/stacktrace/java_deobfuscate.py $OUT/apks/ChromePublic.apk.mapping < logcat.txt`
60*8975f5c5SAndroid Build Coastguard Worker    * ProGuard mapping files are located beside APKs (ex.
61*8975f5c5SAndroid Build Coastguard Worker      `$OUT/apks/ChromePublic.apk` and `$OUT/apks/ChromePublic.apk.mapping`)
62*8975f5c5SAndroid Build Coastguard Worker
63*8975f5c5SAndroid Build Coastguard WorkerHelpful links for deobfuscation:
64*8975f5c5SAndroid Build Coastguard Worker
65*8975f5c5SAndroid Build Coastguard Worker* [Internal bits about how mapping files are archived][proguard-site]
66*8975f5c5SAndroid Build Coastguard Worker* [More detailed deobfuscation instructions][proguard-doc]
67*8975f5c5SAndroid Build Coastguard Worker* [Script for deobfuscating official builds][deob-official]
68*8975f5c5SAndroid Build Coastguard Worker
69*8975f5c5SAndroid Build Coastguard Worker[proguard-site]: http://goto.google.com/chrome-android-proguard
70*8975f5c5SAndroid Build Coastguard Worker[proguard-doc]: http://goto.google.com/chromejavadeobfuscation
71*8975f5c5SAndroid Build Coastguard Worker[deob-official]: http://goto.google.com/chrome-android-official-deobfuscation
72*8975f5c5SAndroid Build Coastguard Worker
73*8975f5c5SAndroid Build Coastguard Worker## Debugging common failures
74*8975f5c5SAndroid Build Coastguard Worker
75*8975f5c5SAndroid Build Coastguard WorkerProGuard failures are often hard to debug. This section aims to outline some of
76*8975f5c5SAndroid Build Coastguard Workerthe more common errors.
77*8975f5c5SAndroid Build Coastguard Worker
78*8975f5c5SAndroid Build Coastguard Worker### Classes expected to be discarded
79*8975f5c5SAndroid Build Coastguard Worker
80*8975f5c5SAndroid Build Coastguard WorkerThe `-checkdiscard` directive can be used to ensure that certain items are
81*8975f5c5SAndroid Build Coastguard Workerremoved by ProGuard. A common use of `-checkdiscard` it to ensure that ProGuard
82*8975f5c5SAndroid Build Coastguard Workeroptimizations do not regress in their ability to remove code, such as code
83*8975f5c5SAndroid Build Coastguard Workerintended only for debug builds, or generated JNI classes that are meant to be
84*8975f5c5SAndroid Build Coastguard Workerzero-overhead abstractions. Annotating a class with
85*8975f5c5SAndroid Build Coastguard Worker[@CheckDiscard][checkdiscard] will add a `-checkdiscard` rule automatically.
86*8975f5c5SAndroid Build Coastguard Worker
87*8975f5c5SAndroid Build Coastguard Worker[checkdiscard]: /build/android/java/src/org/chromium/build/annotations/CheckDiscard.java
88*8975f5c5SAndroid Build Coastguard Worker
89*8975f5c5SAndroid Build Coastguard Worker```
90*8975f5c5SAndroid Build Coastguard WorkerItem void org.chromium.base.library_loader.LibraryPrefetcherJni.<init>() was not discarded.
91*8975f5c5SAndroid Build Coastguard Workervoid org.chromium.base.library_loader.LibraryPrefetcherJni.<init>()
92*8975f5c5SAndroid Build Coastguard Worker|- is invoked from:
93*8975f5c5SAndroid Build Coastguard Worker|  void org.chromium.base.library_loader.LibraryPrefetcher.asyncPrefetchLibrariesToMemory()
94*8975f5c5SAndroid Build Coastguard Worker... more code path lines
95*8975f5c5SAndroid Build Coastguard Worker|- is referenced in keep rule:
96*8975f5c5SAndroid Build Coastguard Worker|  obj/chrome/android/chrome_public_apk/chrome_public_apk.resources.proguard.txt:104:1
97*8975f5c5SAndroid Build Coastguard Worker
98*8975f5c5SAndroid Build Coastguard WorkerError: Discard checks failed.
99*8975f5c5SAndroid Build Coastguard Worker```
100*8975f5c5SAndroid Build Coastguard Worker
101*8975f5c5SAndroid Build Coastguard WorkerThings to check
102*8975f5c5SAndroid Build Coastguard Worker  * Did you add code that is referenced by code path in the error message?
103*8975f5c5SAndroid Build Coastguard Worker  * If so, check the original class for why the `CheckDiscard` was added
104*8975f5c5SAndroid Build Coastguard Worker    originally and verify that the reason is still valid with your change (may
105*8975f5c5SAndroid Build Coastguard Worker    need git blame to do this).
106*8975f5c5SAndroid Build Coastguard Worker  * Try the extra debugging steps listed in the JNI section below.
107*8975f5c5SAndroid Build Coastguard Worker
108*8975f5c5SAndroid Build Coastguard Worker### JNI wrapper classes not discarded
109*8975f5c5SAndroid Build Coastguard Worker
110*8975f5c5SAndroid Build Coastguard WorkerProxy native methods (`@NativeMethods`) use generated wrapper classes to provide
111*8975f5c5SAndroid Build Coastguard Workeraccess to native methods. We rely on ProGuard to fully optimize the generated
112*8975f5c5SAndroid Build Coastguard Workercode so that native methods aren't a source of binary size bloat. The above
113*8975f5c5SAndroid Build Coastguard Workererror message is an example when a JNI wrapper class wasn't discarded (notice
114*8975f5c5SAndroid Build Coastguard Workerthe name of the offending class).
115*8975f5c5SAndroid Build Coastguard Worker  * The ProGuard rule pointed to in the error message isn't helpful (just tells
116*8975f5c5SAndroid Build Coastguard Worker    us a code path that reaches the not-inlined class).
117*8975f5c5SAndroid Build Coastguard Worker  * Common causes:
118*8975f5c5SAndroid Build Coastguard Worker    * Caching the result of `ClassNameJni.get()` in a member variable.
119*8975f5c5SAndroid Build Coastguard Worker    * Passing a native wrapper method reference instead of using a lambda (i.e.
120*8975f5c5SAndroid Build Coastguard Worker      `Jni.get()::methodName` vs. `() -> Jni.get.methodName()`).
121*8975f5c5SAndroid Build Coastguard Worker  * For more debugging info, add to `base/android/proguard/chromium_apk.flags`:
122*8975f5c5SAndroid Build Coastguard Worker      ```
123*8975f5c5SAndroid Build Coastguard Worker      -whyareyounotinlining class org.chromium.base.library_loader.LibraryPrefetcherJni {
124*8975f5c5SAndroid Build Coastguard Worker          <init>();
125*8975f5c5SAndroid Build Coastguard Worker      }
126*8975f5c5SAndroid Build Coastguard Worker      ```
127*8975f5c5SAndroid Build Coastguard Worker
128*8975f5c5SAndroid Build Coastguard Worker### Duplicate classes
129*8975f5c5SAndroid Build Coastguard Worker
130*8975f5c5SAndroid Build Coastguard Worker```
131*8975f5c5SAndroid Build Coastguard WorkerType YourClassName is defined multiple times: obj/jar1.jar:YourClassName.class, obj/jar2.jar:YourClassName.class
132*8975f5c5SAndroid Build Coastguard Worker```
133*8975f5c5SAndroid Build Coastguard Worker
134*8975f5c5SAndroid Build Coastguard WorkerCommon causes:
135*8975f5c5SAndroid Build Coastguard Worker  * Multiple targets with overlapping `srcjar_deps`:
136*8975f5c5SAndroid Build Coastguard Worker    * Each `.srcjar` can only be depended on by a single Java target in any
137*8975f5c5SAndroid Build Coastguard Worker      given APK target. `srcjar_deps` are just a convenient way to depend on
138*8975f5c5SAndroid Build Coastguard Worker      generated files and should be treated like source files rather than
139*8975f5c5SAndroid Build Coastguard Worker      `deps`.
140*8975f5c5SAndroid Build Coastguard Worker    * Solution: Wrap the `srcjar` in an `android_library` target or have only a
141*8975f5c5SAndroid Build Coastguard Worker      single Java target depend on the `srcjar` and have other targets depend on
142*8975f5c5SAndroid Build Coastguard Worker      the containing Java target instead.
143*8975f5c5SAndroid Build Coastguard Worker  * Accidentally enabling APK level generated files for multiple targets that
144*8975f5c5SAndroid Build Coastguard Worker    share generated code (ex. Trichrome or App Bundles):
145*8975f5c5SAndroid Build Coastguard Worker    * Solution: Make sure the generated file is only added once.
146*8975f5c5SAndroid Build Coastguard Worker
147*8975f5c5SAndroid Build Coastguard WorkerDebugging ProGuard failures isn't easy, so please message [email protected]
148*8975f5c5SAndroid Build Coastguard Workeror [file a bug](crbug.com/new) with `component=Build os=Android` for any
149*8975f5c5SAndroid Build Coastguard Workerissues related to Java code optimization.
150