xref: /aosp_15_r20/external/cronet/build/android/docs/life_of_a_resource.md (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1# Life of an Android Resource
2
3[TOC]
4
5## Overview
6
7This document describes how [Android Resources][android resources]
8are built in Chromium's build system. It does not mention native resources
9which are [processed differently][native resources].
10
11[android resources]: https://developer.android.com/guide/topics/resources/providing-resources
12[native resources]: https://www.chromium.org/developers/tools-we-use-in-chromium/grit/grit-users-guide
13
14The steps consume the following files as inputs:
15* `AndroidManifest.xml`
16  * Including `AndroidManifest.xml` files from libraries, which get merged
17    together
18* res/ directories
19
20The steps produce the following intermediate files:
21* `R.srcjar` (contains `R.java` files)
22* `R.txt`
23* `.resources.zip`
24
25The steps produce the following files within an `.apk`:
26* `AndroidManifest.xml` (a binary xml file)
27* `resources.arsc` (contains all values and configuration metadata)
28* `res/**` (drawables and layouts)
29* `classes.dex` (just a small portion of classes from generated `R.java` files)
30
31
32## The Build Steps
33
34Whenever you try to compile an apk or library target, resources go through the
35following steps:
36
37### 1. Constructs .build\_config files:
38
39Inputs:
40* GN target metadata
41* Other `.build_config.json` files
42
43Outputs:
44* Target-specific `.build_config.json` file
45
46`write_build_config.py` is run to record target metadata needed by future steps.
47For more details, see [build_config.md](build_config.md).
48
49
50### 2. Prepares resources:
51
52Inputs:
53* Target-specific `.build_config.json` file
54* Files listed as `sources`
55
56Outputs:
57* Target-specific `resources.zip` (contains all resources listed in `sources`).
58* Target-specific `R.txt` (list of all resources, including dependencies).
59
60`prepare_resources.py` zips up the target-specific resource files and generates
61`R.txt`. No optimizations, crunching, etc are done on the resources.
62
63**The following steps apply only to apk & bundle targets (not to library
64targets).**
65
66### 3. Create target-specific R.java files
67
68Inputs:
69* `R.txt` from dependencies.
70
71Outputs:
72* Target-specific (placeholder) `R.java` file.
73
74A target-specific `R.java` is generated for each `android_library()` target that
75sets `resources_package`. Resource IDs are not known at this phase, so all
76values are set as placeholders. This copy of `R` classes are discarded and
77replaced with new copies at step 4.
78
79Example placeholder R.java file:
80```java
81package org.chromium.mypackage;
82
83public final class R {
84    public static class anim  {
85        public static int abc_fade_in = 0;
86        public static int abc_fade_out = 0;
87        ...
88    }
89    ...
90}
91```
92
93### 4. Finalizes apk resources:
94
95Inputs:
96* Target-specific `.build_config.json` file
97* Dependencies' `R.txt` files
98* Dependencies' `resources.zip` files
99
100Output:
101* Packaged `resources zip` (named `foo.ap_`) containing:
102  * `AndroidManifest.xml` (as binary xml)
103  * `resources.arsc`
104  * `res/**`
105* Final `R.txt`
106  * Contains a list of resources and their ids (including of dependencies).
107* Final `R.java` files
108  * See [What are `R.java` files and how are they generated](
109  #how-r_java-files-are-generated)
110
111
112#### 4(a). Compiles resources:
113
114For each library / resources target your apk depends on, the following happens:
115* Use a regex (defined in the apk target) to remove select resources (optional).
116* Convert png images to webp for binary size (optional).
117* Move drawables in mdpi to non-mdpi directory ([why?](http://crbug.com/289843))
118* Use `aapt2 compile` to compile xml resources to binary xml (references to
119  other resources will now use the id rather than the name for faster lookup at
120  runtime).
121* `aapt2 compile` adds headers/metadata to 9-patch images about which parts of
122  the image are stretchable vs static.
123* `aapt2 compile` outputs a zip with the compiled resources (one for each
124  dependency).
125
126
127#### 4(b). Links resources:
128
129After each dependency is compiled into an intermediate `.zip`, all those zips
130are linked by the `aapt2 link` command which does the following:
131* Use the order of dependencies supplied so that some resources clober each
132  other.
133* Compile the `AndroidManifest.xml` to binary xml (references to resources are
134  now using ids rather than the string names)
135* Create a `resources.arsc` file that has the name and values of string
136  resources as well as the name and path of non-string resources (ie. layouts
137  and drawables).
138* Combine the compiled resources into one packaged resources apk (a zip file
139  with an `.ap_` extension) that has all the resources related files.
140
141
142#### 4(c). Optimizes resources:
143
144Targets can opt into the following optimizations:
1451) Resource name collapsing: Maps all resources to the same name. Access to
146   resources via `Resources.getIdentifier()` no longer work unless resources are
147   [allowlisted](#adding-resources-to-the-allowlist).
1482) Resource filename obfuscation: Renames resource file paths from e.g.:
149   `res/drawable/something.png` to `res/a`. Rename mapping is stored alongside
150   APKs / bundles in a `.pathmap` file. Renames are based on hashes, and so are
151   stable between builds (unless a new hash collision occurs).
1523) Unused resource removal: Referenced resources are extracted from the
153   optimized `.dex` and `AndroidManifest.xml`. Resources that are directly or
154   indirectly used by these files are removed.
155
156## App Bundles and Modules:
157
158Processing resources for bundles and modules is slightly different. Each module
159has its resources compiled and linked separately (ie: it goes through the
160entire process for each module). The modules are then combined to form a
161bundle. Moreover, during "Finalizing the apk resources" step, bundle modules
162produce a `resources.proto` file instead of a `resources.arsc` file.
163
164Resources in a dynamic feature module may reference resources in the base
165module. During the link step for feature module resources, the linked resources
166of the base module are passed in. However, linking against resources currently
167works only with `resources.arsc` format. Thus, when building the base module,
168resources are compiled as both `resources.arsc` and `resources.proto`.
169
170## Debugging resource related errors when resource names are obfuscated
171
172An example message from a stacktrace could be something like this:
173```
174java.lang.IllegalStateException: Could not find CoordinatorLayout descendant
175view with id org.chromium.chrome:id/0_resource_name_obfuscated to anchor view
176android.view.ViewStub{be192d5 G.E...... ......I. 0,0-0,0 #7f0a02ad
177app:id/0_resource_name_obfuscated}
178```
179
180`0_resource_name_obfuscated` is the resource name for all resources that had
181their name obfuscated/stripped during the optimize resources step. To help with
182debugging, the `R.txt` file is archived. The `R.txt` file contains a mapping
183from resource ids to resource names and can be used to get the original resource
184name from the id. In the above message the id is `0x7f0a02ad`.
185
186For local builds, `R.txt` files are output in the `out/*/apks` directory.
187
188For official builds, Googlers can get archived `R.txt` files next to archived
189apks.
190
191### Adding resources to the allowlist
192
193If a resource is accessed via `getIdentifier()` it needs to be allowed by an
194aapt2 resources config file. The config file looks like this:
195
196```
197<resource type>/<resource name>#no_obfuscate
198```
199eg:
200```
201string/app_name#no_obfuscate
202id/toolbar#no_obfuscate
203```
204
205The aapt2 config file is passed to the ninja target through the
206`resources_config_paths` variable. To add a resource to the allowlist, check
207where the config is for your target and add a new line for your resource. If
208none exist, create a new config file and pass its path in your target.
209
210### Webview resource ids
211
212The first two bytes of a resource id is the package id. For regular apks, this
213is `0x7f`. However, Webview is a shared library which gets loaded into other
214apks. The package id for webview resources is assigned dynamically at runtime.
215When webview is loaded it calls this [R file's][Base Module R.java File]
216`onResourcesLoaded()` function to have the correct package id. When
217deobfuscating webview resource ids, disregard the first two bytes in the id when
218looking it up in the `R.txt` file.
219
220Monochrome, when loaded as webview, rewrites the package ids of resources used
221by the webview portion to the correct value at runtime, otherwise, its resources
222have package id `0x7f` when run as a regular apk.
223
224[Base Module R.java File]: https://cs.chromium.org/chromium/src/out/android-Debug/gen/android_webview/system_webview_apk/generated_java/gen/base_module/R.java
225
226## How R.java files are generated
227
228`R.java` contain a set of nested static classes, each with static fields
229containing ids. These ids are used in java code to reference resources in
230the apk.
231
232There are three types of `R.java` files in Chrome.
2331. Root / Base Module `R.java` Files
2342. DFM `R.java` Files
2353. Per-Library `R.java` Files
236
237### Root / Base Module `R.java` Files
238Contain base android resources. All `R.java` files can access base module
239resources through inheritance.
240
241Example Root / Base Module `R.java` File:
242```java
243package gen.base_module;
244
245public final class R {
246    public static class anim  {
247        public static final int abc_fade_in = 0x7f010000;
248        public static final int abc_fade_out = 0x7f010001;
249        public static final int abc_slide_in_top = 0x7f010007;
250    }
251    public static class animator  {
252        public static final int design_appbar_state_list_animator = 0x7f020000;
253    }
254}
255```
256
257### DFM `R.java` Files
258Extend base module root `R.java` files. This allows DFMs to access their own
259resources as well as the base module's resources.
260
261Example DFM Root `R.java` File
262```java
263package gen.vr_module;
264
265public final class R {
266    public static class anim extends gen.base_module.R.anim {
267    }
268    public static class animator extends gen.base_module.R.animator  {
269        public static final int design_appbar_state_list_animator = 0x7f030000;
270    }
271}
272```
273
274### Per-Library `R.java` Files
275Generated for each `android_library()` target that sets `resources_package`.
276First a placeholder copy is generated in the `android_library()` step, and then
277a final copy is created during finalization.
278
279Example final per-library `R.java`:
280```java
281package org.chromium.chrome.vr;
282
283public final class R {
284    public static final class anim extends
285            gen.vr_module.R.anim {}
286    public static final class animator extends
287            gen.vr_module.R.animator {}
288}
289```
290