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