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