1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84

build / android / incremental_install / README.md [blame]

# 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
   ```
 * `AppComponentFactory.instantiateClassLoader()` is not supported.

## 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.