summaryrefslogtreecommitdiff
path: root/docs/resources.md
diff options
context:
space:
mode:
author Colin Cross <ccross@android.com> 2024-07-17 15:30:04 -0700
committer Colin Cross <ccross@android.com> 2024-07-17 16:59:11 -0700
commitc56c3f74857a1b584627763460bbc0933de869f3 (patch)
treef3a039f83dd6998b68348ddab176b556a988e16c /docs/resources.md
parent17f9dc5f76227bcbb6c2d2886c4323f15c8b9ee8 (diff)
Document how resources are built with and without resource processor
In preparation for switching the default of use_resource_processor to true document how Soong compiles resources with and without resource processor. Bug: 294256649 Test: documentation only Flag: EXEMPT documentation Change-Id: I7d5f90c70925138d7c142832423103e6e6840d60
Diffstat (limited to 'docs/resources.md')
-rw-r--r--docs/resources.md89
1 files changed, 89 insertions, 0 deletions
diff --git a/docs/resources.md b/docs/resources.md
new file mode 100644
index 000000000..c7cb0cf08
--- /dev/null
+++ b/docs/resources.md
@@ -0,0 +1,89 @@
+## Soong Android Resource Compilation
+
+The Android build process involves several steps to compile resources into a format that the Android app can use
+efficiently in android_library, android_app and android_test modules. See the
+[resources documentation](https://developer.android.com/guide/topics/resources/providing-resources) for general
+information on resources (with a focus on building with Gradle).
+
+For all modules, AAPT2 compiles resources provided by directories listed in the resource_dirs directory (which is
+implicitly set to `["res"]` if unset, but can be overridden by setting the `resource_dirs` property).
+
+## android_library with resource processor
+For an android_library with resource processor enabled (currently by setting `use_resource_processor: true`, but will be
+enabled by default in the future):
+- AAPT2 generates the `package-res.apk` file with a resource table that contains all resources from the current
+android_library module. `package-res.apk` files from transitive dependencies are passed to AAPT2 with the `-I` flag to
+resolve references to resources from dependencies.
+- AAPT2 generates an R.txt file that lists all the resources provided by the current android_library module.
+- ResourceProcessorBusyBox reads the `R.txt` file for the current android_library and produces an `R.jar` with an
+`R.class` in the package listed in the android_library's `AndroidManifest.xml` file that contains java fields for each
+resource ID. The resource IDs are non-final, as the final IDs will not be known until the resource table of the final
+android_app or android_test module is built.
+- The android_library's java and/or kotlin code is compiled with the generated `R.jar` in the classpath, along with the
+`R.jar` files from all transitive android_library dependencies.
+
+## android_app or android_test with resource processor
+For an android_app or android_test with resource processor enabled (currently by setting `use_resource_processor: true`,
+but will be enabled by default in the future):
+- AAPT2 generates the `package-res.apk` file with a resource table that contains all resources from the current
+android_app or android_test, as well as all transitive android_library modules referenced via `static_libs`. The
+current module is overlaid on dependencies so that resources from the current module replace resources from dependencies
+in the case of conflicts.
+- AAPT2 generates an R.txt file that lists all the resources provided by the current android_app or android_test, as
+well as all transitive android_library modules referenced via `static_libs`. The R.txt file contains the final resource
+ID for each resource.
+- ResourceProcessorBusyBox reads the `R.txt` file for the current android_app or android_test, as well as all transitive
+android_library modules referenced via `static_libs`, and produces an `R.jar` with an `R.class` in the package listed in
+the android_app or android_test's `AndroidManifest.xml` file that contains java fields for all local or transitive
+resource IDs. In addition, it creates an `R.class` in the package listed in each android_library dependency's
+`AndroidManifest.xml` file that contains final resource IDs for the resources that were found in that library.
+- The android_app or android_test's java and/or kotlin code is compiled with the current module's `R.jar` in the
+classpath, but not the `R.jar` files from transitive android_library dependencies. The `R.jar` file is also merged into
+the program classes that are dexed and placed in the final APK.
+
+## android_app, android_test or android_library without resource processor
+For an android_app, android_test or android_library without resource processor enabled (current the default, or
+explicitly set with `use_resource_processor: false`):
+- AAPT2 generates the `package-res.apk` file with a resource table that contains all resources from the current
+android_app, android_test or android_library module, as well as all transitive android_library modules referenced via
+`static_libs`. The current module is overlaid on dependencies so that resources from the current module replace
+resources from dependencies in the case of conflicts.
+- AAPT2 generates an `R.java` file in the package listed in each the current module's `AndroidManifest.xml` file that
+contains resource IDs for all resources from the current module as well as all transitive android_library modules
+referenced via `static_libs`. The same `R.java` containing all local and transitive resources is also duplicated into
+every package listed in an `AndroidManifest.xml` file in any static `android_library` dependency.
+- The module's java and/or kotlin code is compiled along with all the generated `R.java` files.
+
+
+## Downsides of legacy resource compilation without resource processor
+
+Compiling resources without using the resource processor results in a generated R.java source file for every transitive
+package that contains every transitive resource. For modules with large transitive dependency trees this can be tens of
+thousands of resource IDs duplicated in tens to a hundred java sources. These java sources all have to be compiled in
+every successive module in the dependency tree, and then the final R8 step has to drop hundreds of thousands of
+unreferenced fields. This results in significant build time and disk usage increases over building with resource
+processor.
+
+## Converting to compilation with resource processor
+
+### Reference resources using the package name of the module that includes them.
+Converting an android_library module to build with resource processor requires fixing any references to resources
+provided by android_library dependencies to reference the R classes using the package name found in the
+`AndroidManifest.xml` file of the dependency. For example, when referencing an androidx resource:
+```java
+View.inflate(mContext, R.layout.preference, null));
+```
+must be replaced with:
+```java
+View.inflate(mContext, androidx.preference.R.layout.preference, null));
+```
+
+### Use unique package names for each module in `AndroidManifest.xml`
+
+Each module will produce an `R.jar` containing an `R.class` in the package specified in it's `AndroidManifest.xml`.
+If multiple modules use the same package name they will produce conflicting `R.class` files, which can cause some
+resource IDs to appear to be missing.
+
+If existing code has multiple modules that contribute resources to the same package, one option is to move all the
+resources into a single resources-only `android_library` module with no code, and then depend on that from all the other
+modules. \ No newline at end of file