84 lines
2.8 KiB
Markdown
84 lines
2.8 KiB
Markdown
|
|
# Incremental Install
|
||
|
|
|
||
|
|
Incremental Install is a way of building & deploying an APK that tries to
|
||
|
|
minimize the time it takes to make a change and see that change running on
|
||
|
|
device. They work best with `is_component_build=true`, and do *not* require a
|
||
|
|
rooted device.
|
||
|
|
|
||
|
|
## Building
|
||
|
|
|
||
|
|
Add the gn arg:
|
||
|
|
|
||
|
|
incremental_install = true
|
||
|
|
|
||
|
|
This causes all apks to be built as incremental except for denylisted ones.
|
||
|
|
|
||
|
|
## Running
|
||
|
|
|
||
|
|
It is not enough to `adb install` them. You must use the generated wrapper
|
||
|
|
script:
|
||
|
|
|
||
|
|
out/Debug/bin/your_apk run
|
||
|
|
out/Debug/bin/run_chrome_public_test_apk # Automatically sets --fast-local-dev
|
||
|
|
|
||
|
|
# How it Works
|
||
|
|
|
||
|
|
## Overview
|
||
|
|
|
||
|
|
The basic idea is to sideload .dex and .so files to `/data/local/tmp` rather
|
||
|
|
than bundling them in the .apk. Then, when making a change, only the changed
|
||
|
|
.dex / .so needs to be pushed to the device.
|
||
|
|
|
||
|
|
Faster Builds:
|
||
|
|
|
||
|
|
* No `final_dex` step (where all .dex files are merged into one)
|
||
|
|
* No need to rebuild .apk for code-only changes (but required for resources)
|
||
|
|
* Apks sign faster because they are smaller.
|
||
|
|
|
||
|
|
Faster Installs:
|
||
|
|
|
||
|
|
* The .apk is smaller, and so faster to verify.
|
||
|
|
* No need to run `adb install` for code-only changes.
|
||
|
|
* Only changed .so / .dex files are pushed. MD5s of existing on-device files
|
||
|
|
are cached on host computer.
|
||
|
|
|
||
|
|
Slower Initial Runs:
|
||
|
|
|
||
|
|
* The first time you run an incremental .apk, the `DexOpt` needs to run on all
|
||
|
|
.dex files. This step is normally done during `adb install`, but is done on
|
||
|
|
start-up for incremental apks.
|
||
|
|
* DexOpt results are cached, so subsequent runs are faster.
|
||
|
|
* The slowdown varies significantly based on the Android version. Android O+
|
||
|
|
has almost no visible slow-down.
|
||
|
|
|
||
|
|
Caveats:
|
||
|
|
* Isolated processes (on L+) are incompatible with incremental install. As a
|
||
|
|
work-around, isolated processes are disabled when building incremental apks.
|
||
|
|
* Android resources, assets, and `loadable_modules` are not sideloaded (they
|
||
|
|
remain in the apk), so builds & installs that modify any of these are not as
|
||
|
|
fast as those that modify only .java / .cc.
|
||
|
|
* Since files are sideloaded to `/data/local/tmp`, you need to use the wrapper
|
||
|
|
scripts to uninstall them fully. E.g.:
|
||
|
|
```shell
|
||
|
|
out/Default/bin/chrome_public_apk uninstall
|
||
|
|
```
|
||
|
|
|
||
|
|
## The Code
|
||
|
|
|
||
|
|
All incremental apks have the same classes.dex, which is built from:
|
||
|
|
|
||
|
|
//build/android/incremental_install:bootstrap_java
|
||
|
|
|
||
|
|
They also have a transformed `AndroidManifest.xml`, which overrides the the
|
||
|
|
main application class and any instrumentation classes so that they instead
|
||
|
|
point to `BootstrapApplication`. This is built by:
|
||
|
|
|
||
|
|
//build/android/incremental_install/generate_android_manifest.py
|
||
|
|
|
||
|
|
Wrapper scripts and install logic is contained in:
|
||
|
|
|
||
|
|
//build/android/incremental_install/create_install_script.py
|
||
|
|
//build/android/incremental_install/installer.py
|
||
|
|
|
||
|
|
Finally, GN logic for incremental apks is sprinkled throughout.
|