android_webview
apps
ash
base
build
3pp_common
android
bytecode
docs
README.md
build_config.md
class_verification_failures.md
coverage.md
java_asserts.md
java_optimization.md
java_toolchain.md
life_of_a_resource.md
lint.md
resources_in_java.md
static_analysis.md
gradle
gtest_apk
gyp
incremental_install
java
junit
native_flags
pylib
stacktrace
test
test_wrapper
tests
unused_resources
update_deps
AndroidManifest.xml
BUILD.gn
COMMON_METADATA
CheckInstallApk-debug.apk
DIR_METADATA
OWNERS
PRESUBMIT.py
adb_chrome_public_command_line
adb_command_line.py
adb_gdb
adb_install_apk.py
adb_logcat_monitor.py
adb_logcat_printer.py
adb_profile_chrome
adb_profile_chrome_startup
adb_reverse_forwarder.py
adb_system_webengine_command_line
adb_system_webview_command_line
android_only_explicit_jni_exports.lst
android_only_jni_exports.lst
apk_operations.py
apk_operations.pydeps
asan_symbolize.py
chromium-debug.keystore
chromium_annotations.flags
connect_lldb.sh
convert_dex_profile.py
convert_dex_profile_tests.py
dcheck_is_off.flags
devil_chromium.json
devil_chromium.py
devil_chromium.pydeps
diff_resource_sizes.py
dump_apk_resource_strings.py
envsetup.sh
fast_local_dev_server.py
fast_local_dev_server_test.py
generate_jacoco_report.py
generate_vscode_project.py
generate_wrap_sh.py
host_heartbeat.py
list_class_verification_failures.py
list_class_verification_failures_test.py
list_java_targets.py
method_count.py
provision_devices.py
pylintrc
resource_sizes.gni
resource_sizes.py
resource_sizes.pydeps
screenshot.py
test_runner.py
test_runner.pydeps
test_runner_test.py
tombstones.py
update_verification.py
video_recorder.py
apple
args
autoroll
chromeos
cipd
config
docs
fuchsia
gn_ast
internal
ios
linux
mac
private_code_test
rust
sanitizers
skia_gold_common
toolchain
util
win
.clang-tidy
.clangd
.git-blame-ignore-revs
.gitignore
.style.yapf
BUILD.gn
DEPS
DIR_METADATA
OWNERS
OWNERS.setnoparent
OWNERS.status
PRESUBMIT.py
PRESUBMIT_test.py
README.md
action_helpers.py
action_helpers_unittest.py
add_rts_filters.py
build-ctags.sh
build_config.h
buildflag.h
buildflag_header.gni
check_gn_headers.py
check_gn_headers_allowlist.txt
check_gn_headers_unittest.py
check_return_value.py
ciopfs.sha1
clobber.py
clobber_unittest.py
compiled_action.gni
compute_build_timestamp.py
copy_test_data_ios.py
cp.py
detect_host_arch.py
dotfile_settings.gni
download_nacl_toolchains.py
env_dump.py
extract_from_cab.py
extract_partition.py
find_depot_tools.py
fix_gn_headers.py
gdb-add-index
get_landmines.py
get_symlink_targets.py
gn_editor
gn_helpers.py
gn_helpers_unittest.py
gn_logs.gni
gn_run_binary.py
install-build-deps.py
install-build-deps.sh
install-chroot.sh
landmine_utils.py
landmines.py
locale_tool.py
mac_toolchain.py
metadata.json.in
nocompile.gni
noop.py
partitioned_shared_library.gni
precompile.cc
precompile.h
print_python_deps.py
protoc_java.py
protoc_java.pydeps
redirect_stdout.py
rm.py
sample_arg_file.gn
sanitize-mac-build-log.sed
sanitize-mac-build-log.sh
sanitize-win-build-log.sed
sanitize-win-build-log.sh
shim_headers.gni
symlink.gni
symlink.py
timestamp.gni
tree_truth.sh
update-linux-sandbox.sh
vs_toolchain.py
whitespace_file.txt
write_buildflag_header.py
xcode_binaries.yaml
zip_helpers.py
zip_helpers_unittest.py
build_overrides
buildtools
cc
chrome
chromecast
chromeos
clank
codelabs
components
content
crypto
dbus
device
docs
extensions
fuchsia_web
gin
google_apis
gpu
headless
infra
internal
ios
ios_internal
ipc
media
mojo
native_client
native_client_sdk
net
pdf
ppapi
printing
remoting
rlz
sandbox
services
signing_keys
skia
sql
storage
styleguide
testing
third_party
tools
ui
url
v8
webkit
.clang-format
.clang-tidy
.clangd
.git-blame-ignore-revs
.gitallowed
.gitattributes
.gitignore
.gitmodules
.gn
.mailmap
.rustfmt.toml
.vpython3
.yapfignore
ATL_OWNERS
AUTHORS
BUILD.gn
CODE_OF_CONDUCT.md
CPPLINT.cfg
CRYPTO_OWNERS
DEPS
DIR_METADATA
LICENSE
LICENSE.chromium_os
OWNERS
PRESUBMIT.py
PRESUBMIT_test.py
PRESUBMIT_test_mocks.py
README.md
WATCHLISTS
codereview.settings

Renamed chromium_code.flags to shared_with_cronet.flags, this makes it clearer that the configs in this file are shared and any configs that do not need to be shared should go in chromium_apk.flags. Bug: 338060678 Change-Id: I108e40079859f5d6a553a5c4a811878ca0cb1f45 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5502569 Auto-Submit: Peter Wen <wnwen@chromium.org> Commit-Queue: Etienne Dechamps <edechamps@google.com> Reviewed-by: Etienne Dechamps <edechamps@google.com> Reviewed-by: Andrew Grieve <agrieve@chromium.org> Cr-Commit-Position: refs/heads/main@{#1294888}
150 lines
6.5 KiB
Markdown
150 lines
6.5 KiB
Markdown
# Optimizing Java Code
|
|
|
|
This doc describes how Java code is optimized in Chrome on Android and how to
|
|
deal with issues caused by the optimizer. For tips on how to write optimized
|
|
code, see [//docs/speed/binary_size/optimization_advice.md#optimizing-java-code](/docs/speed/binary_size/optimization_advice.md#optimizing-java-code).
|
|
|
|
[TOC]
|
|
|
|
## ProGuard vs R8
|
|
|
|
ProGuard is the original open-source tool used by many Android applications to
|
|
perform whole-program bytecode optimization. [R8](https://r8.googlesource.com/r8),
|
|
is a re-implementation that is used by Chrome (and the default for Android Studio).
|
|
The terms "ProGuard" and "R8" are used interchangeably within Chromium but
|
|
generally they're meant to refer to the tool providing Java code optimizations.
|
|
|
|
## What does ProGuard do?
|
|
|
|
1. Shrinking: ProGuard will remove unused code. This is especially useful
|
|
when depending on third party libraries where only a few functions are used.
|
|
|
|
2. Obfuscation: ProGuard will rename classes/fields/methods to use shorter
|
|
names. Obfuscation is used for minification purposes only (not security).
|
|
|
|
3. Optimization: ProGuard performs a series of optimizations to shrink code
|
|
further through various approaches (ex. inlining, outlining, class merging,
|
|
etc).
|
|
|
|
## Build Process
|
|
|
|
ProGuard is enabled only for release builds of Chrome because it is a slow build
|
|
step and breaks Java debugging. It can also be enabled manually via the GN arg:
|
|
```is_java_debug = false```
|
|
|
|
### ProGuard configuration files
|
|
|
|
Most GN Java targets can specify ProGuard configuration files by setting the
|
|
`proguard_configs` variable. [//base/android/proguard](/base/android/proguard)
|
|
contains common flags shared by most Chrome applications.
|
|
|
|
### GN build rules
|
|
|
|
When `is_java_debug = false` and a target has enabled ProGuard, the `proguard`
|
|
step generates the `.dex` files for the application. The `proguard` step takes
|
|
as input a list of `.jar` files, runs R8/ProGuard on those `.jar` files, and
|
|
produces the final `.dex` file(s) that will be packaged into your `.apk`
|
|
|
|
## Deobfuscation
|
|
|
|
Obfuscation can be turned off for local builds while leaving ProGuard enabled
|
|
by setting `enable_proguard_obfuscation = false` in GN args.
|
|
|
|
There are two main methods for deobfuscating Java stack traces locally:
|
|
1. Using APK wrapper scripts (stacks are automatically deobfuscated)
|
|
* `$OUT/bin/chrome_public_apk logcat` # Run adb logcat
|
|
* `$OUT/bin/chrome_public_apk run` # Launch chrome and run adb logcat
|
|
|
|
2. Using `java_deobfuscate`
|
|
* build/android/stacktrace/java_deobfuscate.py $OUT/apks/ChromePublic.apk.mapping < logcat.txt`
|
|
* ProGuard mapping files are located beside APKs (ex.
|
|
`$OUT/apks/ChromePublic.apk` and `$OUT/apks/ChromePublic.apk.mapping`)
|
|
|
|
Helpful links for deobfuscation:
|
|
|
|
* [Internal bits about how mapping files are archived][proguard-site]
|
|
* [More detailed deobfuscation instructions][proguard-doc]
|
|
* [Script for deobfuscating official builds][deob-official]
|
|
|
|
[proguard-site]: http://goto.google.com/chrome-android-proguard
|
|
[proguard-doc]: http://goto.google.com/chromejavadeobfuscation
|
|
[deob-official]: http://goto.google.com/chrome-android-official-deobfuscation
|
|
|
|
## Debugging common failures
|
|
|
|
ProGuard failures are often hard to debug. This section aims to outline some of
|
|
the more common errors.
|
|
|
|
### Classes expected to be discarded
|
|
|
|
The `-checkdiscard` directive can be used to ensure that certain items are
|
|
removed by ProGuard. A common use of `-checkdiscard` it to ensure that ProGuard
|
|
optimizations do not regress in their ability to remove code, such as code
|
|
intended only for debug builds, or generated JNI classes that are meant to be
|
|
zero-overhead abstractions. Annotating a class with
|
|
[@CheckDiscard][checkdiscard] will add a `-checkdiscard` rule automatically.
|
|
|
|
[checkdiscard]: /build/android/java/src/org/chromium/build/annotations/CheckDiscard.java
|
|
|
|
```
|
|
Item void org.chromium.base.library_loader.LibraryPrefetcherJni.<init>() was not discarded.
|
|
void org.chromium.base.library_loader.LibraryPrefetcherJni.<init>()
|
|
|- is invoked from:
|
|
| void org.chromium.base.library_loader.LibraryPrefetcher.asyncPrefetchLibrariesToMemory()
|
|
... more code path lines
|
|
|- is referenced in keep rule:
|
|
| obj/chrome/android/chrome_public_apk/chrome_public_apk.resources.proguard.txt:104:1
|
|
|
|
Error: Discard checks failed.
|
|
```
|
|
|
|
Things to check
|
|
* Did you add code that is referenced by code path in the error message?
|
|
* If so, check the original class for why the `CheckDiscard` was added
|
|
originally and verify that the reason is still valid with your change (may
|
|
need git blame to do this).
|
|
* Try the extra debugging steps listed in the JNI section below.
|
|
|
|
### JNI wrapper classes not discarded
|
|
|
|
Proxy native methods (`@NativeMethods`) use generated wrapper classes to provide
|
|
access to native methods. We rely on ProGuard to fully optimize the generated
|
|
code so that native methods aren't a source of binary size bloat. The above
|
|
error message is an example when a JNI wrapper class wasn't discarded (notice
|
|
the name of the offending class).
|
|
* The ProGuard rule pointed to in the error message isn't helpful (just tells
|
|
us a code path that reaches the not-inlined class).
|
|
* Common causes:
|
|
* Caching the result of `ClassNameJni.get()` in a member variable.
|
|
* Passing a native wrapper method reference instead of using a lambda (i.e.
|
|
`Jni.get()::methodName` vs. `() -> Jni.get.methodName()`).
|
|
* For more debugging info, add to `base/android/proguard/chromium_apk.flags`:
|
|
```
|
|
-whyareyounotinlining class org.chromium.base.library_loader.LibraryPrefetcherJni {
|
|
<init>();
|
|
}
|
|
```
|
|
|
|
### Duplicate classes
|
|
|
|
```
|
|
Type YourClassName is defined multiple times: obj/jar1.jar:YourClassName.class, obj/jar2.jar:YourClassName.class
|
|
```
|
|
|
|
Common causes:
|
|
* Multiple targets with overlapping `srcjar_deps`:
|
|
* Each `.srcjar` can only be depended on by a single Java target in any
|
|
given APK target. `srcjar_deps` are just a convenient way to depend on
|
|
generated files and should be treated like source files rather than
|
|
`deps`.
|
|
* Solution: Wrap the `srcjar` in an `android_library` target or have only a
|
|
single Java target depend on the `srcjar` and have other targets depend on
|
|
the containing Java target instead.
|
|
* Accidentally enabling APK level generated files for multiple targets that
|
|
share generated code (ex. Trichrome or App Bundles):
|
|
* Solution: Make sure the generated file is only added once.
|
|
|
|
Debugging ProGuard failures isn't easy, so please message java@chromium.org
|
|
or [file a bug](crbug.com/new) with `component=Build os=Android` for any
|
|
issues related to Java code optimization.
|