1ABI Monitoring for Android Kernels
2==================================
3
4Overview
5--------
6In order to stabilize the in-kernel ABI of Android kernels, the ABI Monitoring
7tooling has been created to collect and compare ABI representations from
8existing kernel binaries (vmlinux + modules). The tools can be used to track
9and mitigate changes to said ABI. This document describes the tooling, the
10process of collecting and analyzing ABI representations and how such
11representations can be used to ensure stability of the in-kernel ABI. Lastly,
12this document gives some details about the process of contributing changes to
13the Android kernels.
14
15This directory contains the specific tools for the ABI analysis. It should be
16used as part of the build scripts that are provided by this repository (see
17`../build_abi.sh`).
18
19Process Description
20-------------------
21
22Analyzing the kernel's ABI is done in multiple steps. Most of the steps can be
23automated:
24
25 1. Acquire the toolchain, build scripts and kernel sources through `repo`
26 2. Provide any prerequisites (e.g. libabigail)
27 3. Build the kernel and its ABI representation
28 4. Analyze ABI differences between the build and a reference
29 5. Update the ABI representation (if required)
30 6. Working with symbol whitelists
31
32
33The following instructions work for any kernel that can be built using a
34supported toolchain (i.e. a prebuilt Clang toolchain). There exist [`repo`
35manifests](https://android.googlesource.com/kernel/manifest/+refs) for all
36Android common kernel branches, for some upstream branches (e.g.
37upstream-linux-4.19.y) and several device specific kernels that ensure the
38correct toolchain is used when building a kernel distribution.
39
40
41Using the ABI Monitoring tooling
42--------------------------------
43
44### 1. Acquire the toolchain, build scripts and kernel sources through repo
45
46Toolchain, build scripts (i.e. these scripts) and kernel sources can be
47acquired with `repo`. For detailed documentation, refer to the corresponding
48documentation on
49[source.android.com](https://source.android.com/setup/build/building-kernels).
50
51To illustrate the process, the following steps use `common-android-mainline`,
52an Android kernel branch that is kept up-to-date with the upstream Linux
53releases. In order to obtain this branch via `repo`, execute
54
55```
56  $ repo init -u https://android.googlesource.com/kernel/manifest -b common-android-mainline
57  $ repo sync
58```
59
60### 2. Provide any prerequisites
61
62**NOTE**: Googlers might want to follow the steps in
63[go/kernel-abi-monitoring](http://go/kernel-abi-monitoring) to use a prebuilt
64libabigail distribution.
65
66The ABI tooling makes use of [libabigail](https://sourceware.org/libabigail/),
67a library and collection of tools to analyze binaries. In order to use the
68tooling, users are required to provide a functional libabigail installation.
69The released version of your Linux distribution might not be a supported one;
70hence, it is recommended way to use the `bootstrap` script which can be found in
71this directory. The `bootstrap` script automates the process of acquiring and
72building a valid libabigail distribution and needs to be executed without any
73arguments like so:
74
75```
76  $ build/abi/bootstrap
77```
78
79The script will ensure the following system prerequisites are installed along
80with their dependencies:
81
82 - autoconf
83 - libtool
84 - libxml2-dev
85 - pkg-config
86 - python3
87
88**NOTE**: At the moment, only apt based package managers are supported, but
89`bootstrap` provides some hints to help users that have other package
90managers.
91
92The script continues with acquiring the sources for the correct versions of
93*elfutils* and *libabigail* and will build the required binaries. At the very
94end the script will print instructions to add the binaries to the local
95`${PATH}`. The output will look similar to:
96
97```
98  NOTE: Export the following environment before running the executables:
99
100  export PATH="/src/kernel/build/abi/abigail-inst/d7ae619f/bin:${PATH}"
101  export LD_LIBRARY_PATH="/src/kernel/build/abi/abigail-inst/d7ae619f/lib:/src/kernel/build/abi/abigail-inst/d7ae619f/lib/elfutils:${LD_LIBRARY_PATH}"
102```
103
104**NOTE**: It is probably a good idea to save these instructions to reuse the
105prebuilt binaries in a later session.
106
107Follow the instructions to enable the prerequisites in your environment.
108
109### 3. Build the kernel and its ABI representation
110
111At this point you are ready to build a kernel with the correct toolchain and to
112extract an ABI representation from its binaries (vmlinux + modules).
113
114Similar to the usual Android kernel build process (using `build.sh`), this step
115requires running `build_abi.sh`.
116
117```
118  $ BUILD_CONFIG=common/build.config.gki.aarch64 build/build_abi.sh
119```
120
121**NOTE**: `build_abi.sh` makes use of `build.sh` and therefore accepts the
122same environment variables to customize the build. It also *requires* the same
123variables that would need to be passed to `build.sh`, such as `BUILD_CONFIG`.
124
125That builds the kernel and extracts the ABI representation into the `out`
126directory. In this case `out/android-mainline/dist/abi.xml` would be a symbolic
127link to `out/android-mainline/dist/abi-<id>.xml`. `id` is computed from
128executing `git describe` against the kernel source tree.
129
130### 4. Analyze ABI differences between the build and a reference representation
131
132`build_abi.sh` is capable of analyzing and reporting any ABI differences when
133a reference is provided via the environment variable `ABI_DEFINITION`.
134`ABI_DEFINITION` should point to a reference file relative to the kernel source
135tree and can be specified on the command line or (more commonly) as a value in
136*build.config*. E.g.
137
138```
139  $ BUILD_CONFIG=common/build.config.gki.aarch64      \
140    ABI_DEFINITION=abi_gki_aarch64.xml                \
141    build/build_abi.sh
142```
143
144Above, the `build.config.gki.aarch64` defines the reference file (as
145*abi_gki_aarch64.xml*) and therefore the analysis has been completed. If an
146abidiff was executed, then `build_abi.sh` will print the location of the report
147and identify any ABI breakage. If breakages are detected, then `build_abi.sh`
148will terminate and return a non-zero exit code.
149
150### 5. Update the ABI representation (if required)
151
152To update the ABI dump, `build_abi.sh` can be invoked with the `--update` flag.
153It will update the corresponding abi.xml file that is defined via the
154build.config. It might also be useful to invoke the script with `--print-report`
155to print the differences the update fixes. The report is useful to include in
156the commit message when updating the abi.xml.
157
158### 6. Working with symbol whitelists
159
160`build_abi.sh` can be parameterized to filter symbols during extraction and
161comparison with KMI (Kernel Module Interface) whitelists. These are simple
162plain text files that list relevant ABI kernel symbols. E.g. a whitelist file
163with the following content would limit ABI analysis to the ELF symbols with the
164names `symbol1` and `symbol2`:
165
166```
167  [abi_whitelist]
168    symbol1
169    symbol2
170```
171
172**NOTE**: Please refer to the [libabigail
173documentation](https://sourceware.org/libabigail/manual/kmidiff.html#environment)
174for details about the KMI whitelist file format.
175
176Changes to other ELF symbols would not be considered any longer unless they are
177indirectly affecting symbols that are whitelisted. A whitelist file can be
178specified -- similar to the abi baseline file via `ABI_DEFINITION=` -- in the
179corresponding `build.config` configuration file with `KMI_WHITELIST=` as a file
180relative to the kernel source directory (`$KERNEL_DIR`). In order to allow a
181certain level of organization, additional whitelist files can be specified by
182using `ADDITIONAL_KMI_WHITELISTS=` in the `build.config`. Similarly, it refers
183to whitelists in the `$KERNEL_DIR` and multiple files need to be separated by
184whitespaces.
185
186In order to **create an initial whitelist or to update an existing one**, the
187script `extract_symbols` is provided. When run pointing at a `DIST_DIR` of an
188Android Kernel build, it will extract the symbols that are exported from
189vmlinux _and_ are required by any module in the tree.
190
191Consider `vmlinux` exporting the following symbols (usually done via the
192EXPORT_SYMBOL* macros):
193
194```
195  func1
196  func2
197  func3
198```
199
200Also, consider there are two modules `modA.ko` and `modB.ko` which require the
201following symbols (i.e. `undefined` entries in the symbol table):
202
203```
204  modA.ko:    func1 func2
205  modB.ko:    func2`
206```
207
208From an ABI stability point of view we need to keep `func1` and `func2` stable
209as these are used by an external module. On the contrary, while `func3` is
210exported it is not actively used (i.e. required) by any module. The whitelist
211would therefore contain `func1` and `func2` only.
212
213`extract_symbols` offers a flag to update an existing or create a new whitelist
214based on the above analysis: `--whitelist <path/to/abi_whitelist>`.
215
216In order to update an existing whitelist based on a built Kernel tree, run
217`extract_symbols` as follows. The example uses the *common-android-mainline*
218branch of the Android Common Kernels following the official [build
219documentation](https://source.android.com/setup/build/building-kernels) and
220updates the whitelist for the GKI aarch64 Kernel.
221
222```
223  (build the kernel)
224  $ BUILD_CONFIG=common/build.config.gki.aarch64 build/build.sh
225
226  (update/create the whitelist)
227  $ build/abi/extract_symbols out/android-mainline/dist --whitelist common/abi_gki_aarch64_whitelist
228```
229
230**NOTE**: Be aware that `extract_symbols` recursively discovers Kernel modules
231by extension (*.ko) and considers all found ones. Orphan Kernel modules from
232prior runs might lead to incorrect results. Hence, make sure the directory you
233pass on to `extract_symbols` contains only the vmlinux and the modules you want
234it to consider.
235
236
237Working with the lower level ABI tooling
238----------------------------------------
239
240Most users will need to use `build_abi.sh`. In some cases, it might be
241necessary to work with the lower level ABI tooling directly. There are
242currently two commands -- `dump_abi` and `diff_abi` -- that are available to
243collect and compare ABI files. These commands are used by `build_abi.sh`. See
244the following sections for their usages.
245
246### Creating ABI dumps from kernel trees
247
248Provided a linux kernel tree with built vmlinux and kernel modules, the tool
249`dump_abi` creates an ABI representation using the selected ABI tool. As of now
250there is only one option: 'libabigail' (default). A sample invocation looks as
251follows:
252
253```
254  $ dump_abi --linux-tree path/to/out --out-file /path/to/abi.xml
255```
256
257The file `abi.xml` will contain a combined textual ABI representation that can
258be observed from vmlinux and the kernel modules in the given directory. This
259file might be used for manual inspection, further analysis or as a reference
260file to enforce ABI stability.
261
262### Comparing ABI dumps
263
264ABI dumps created by `dump_abi` can be compared with `diff_abi`. Ensure to use
265the same abi-tool for `dump_abi` and `diff_abi`. A sample invocation looks like:
266
267```
268  $ diff_abi --baseline abi1.xml --new abi2.xml --report report.out
269```
270
271The report created is tool specific, but generally lists ABI changes detected
272that affect the kernel's module interface. The files specified as `baseline`
273and `new` are ABI representations collected with `dump_abi`. `diff_abi`
274propagates the exit code of the underlying tool and therefore returns a
275non-zero value in case the ABIs compared are incompatible.
276
277### Using KMI whitelists
278
279To filter dumps created with `dump_abi` or filter symbols compared with
280`diff_abi`, each of those tools provides a parameter `--kmi-whitelist` that
281takes a path to a KMI whitelist file:
282
283```
284  $ dump_abi --linux-tree path/to/out --out-file /path/to/abi.xml --kmi-whitelist /path/to/whitelist
285```
286
287Dealing with ABI breakages
288--------------------------
289
290As an example, the following patch introduces a very obvious ABI breakage:
291
292```
293  diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
294  index 5ed8f6292a53..f2ecb34c7645 100644
295  --- a/include/linux/mm_types.h
296  +++ b/include/linux/mm_types.h
297  @@ -339,6 +339,7 @@ struct core_state {
298   struct kioctx_table;
299   struct mm_struct {
300      struct {
301  +       int dummy;
302          struct vm_area_struct *mmap;            /* list of VMAs */
303          struct rb_root mm_rb;
304          u64 vmacache_seqnum;                   /* per-thread vmacache */
305```
306
307Running `build_abi.sh` again with this patch applied, the tooling will exit with
308a non-zero error code and will report an ABI difference similar to this:
309
310```
311  Leaf changes summary: 1 artifact changed
312  Changed leaf types summary: 1 leaf type changed
313  Removed/Changed/Added functions summary: 0 Removed, 0 Changed, 0 Added function
314  Removed/Changed/Added variables summary: 0 Removed, 0 Changed, 0 Added variable
315
316  'struct mm_struct at mm_types.h:372:1' changed:
317    type size changed from 6848 to 6912 (in bits)
318    there are data member changes:
319  [...]
320```
321
322### How to fix a broken ABI on Android Gerrit
323
324If you didn't intentionally break the kernel ABI, then you need to investigate
325via the Android Gerrit test log to identify the issue(s) reported by the tool. Most
326common causes of breakages are added or deleted functions, changed data
327structures or changes to the ABI by adding config options that lead to any of
328the aforementioned. Most likely you want to start with addressing the issues
329found by the tool.
330
331You can reproduce the KernelABI test locally by running the following command
332with the same arguments that you would have run `build/build.sh` with.
333
334Example command for the GKI kernels:
335<pre>
336  $ BUILD_CONFIG=common/build.config.gki.aarch64 build/<b>build_abi.sh</b>
337</pre>
338
339### Updating the Kernel ABI
340
341If you need to update the kernel ABI, then you must update the corresponding
342`abi.xml` file in the kernel source tree. This is most conveniently done by
343using `build/build_abi.sh` like so:
344
345<pre>
346  $ build/<b>build_abi.sh</b> --update --print-report
347</pre>
348
349with the same arguments that you would have run `build/build.sh` with. This
350updates the correct `abi.xml` in the source tree and prints the detected
351differences. It is recommended to include the printed report in the commit
352message (at least partially).
353
354
355Android Kernel Branches with predefined ABI
356-------------------------------------------
357
358Some kernel branches might come with golden ABI representations for Android as
359part of their source distribution. These ABI representations are supposed to be
360accurate and should reflect the result of `build_abi.sh` as if you would execute
361it on your own. As the ABI is heavily influenced by various kernel configuration
362options, these .xml files usually belong to a certain configuration. E.g. the
363`common-android-mainline` branch contains an `abi_gki_aarch64.xml` that
364corresponds to the build result when using the `build.config.gki.aarch64`. In
365particular, `build.config.gki.aarch64` also refers to this file as its
366`ABI_DEFINITION`.
367
368Such predefined ABI representations are used as a baseline definition when
369comparing with `diff_abi` (s.a.). E.g. to validate a kernel patch in regards to
370any changes to the ABI, create the ABI representation with the patch applied and
371use `diff_abi` to compare it to the expected ABI for that particular source tree
372/ configuration.
373
374Caveats and known issues
375------------------------
376- Version 1.7 of libabigail, that contains all currently required patches to
377  properly work on clang-built aarch64 Android kernels, has not been released
378  yet. Using a recent master is a sufficient workaround for that. The
379  `bootstrap` script refers to a sufficient commit from upstream.
380