xref: /aosp_15_r20/build/soong/docs/native_code_coverage.md (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1## Native Code Coverage for Android
2
3## Scope
4
5These instructions are for Android developers to collect and inspect code
6coverage for C++ and Rust code on the Android platform.
7
8## Building with Native Code Coverage Instrumentation
9
10Identify the paths where native code-coverage instrumentation should be enabled
11and set up the following environment variables.
12
13```
14    export CLANG_COVERAGE=true
15    export NATIVE_COVERAGE_PATHS="<paths-to-instrument-for-coverage>"
16```
17
18`NATIVE_COVERAGE_PATHS` should be a list of paths. Any Android.bp module defined
19under these paths is instrumented for code-coverage. E.g:
20
21```
22export NATIVE_COVERAGE_PATHS="external/libcxx system/core/adb"
23```
24
25### Additional Notes
26
27-   Native Code coverage is not supported for host modules or `Android.mk`
28    modules.
29-   `NATIVE_COVERAGE_PATHS="*"` enables coverage instrumentation for all paths.
30-   Set `native_coverage: false` blueprint property to always disable code
31    coverage instrumentation for a module. This is useful if this module has
32    issues when building or running with coverage.
33-   `NATIVE_COVERAGE_EXCLUDE_PATHS` can be set to exclude subdirs under
34    `NATIVE_COVERAGE_PATHS` from coverage instrumentation. E.g.
35    `NATIVE_COVERAGE_PATHS=frameworks/native
36    NATIVE_COVERAGE_PATHS=frameworks/native/vulkan` will instrument all native
37    code under `frameworks/native` except`frameworks/native/vulkan`.
38
39## Running Tests
40
41### Collecting Profiles
42
43When an instrumented program is run, the profiles are stored to the path and
44name specified in the `LLVM_PROFILE_FILE` environment variable. On Android
45coverage builds it is set to `/data/misc/trace/clang-%p-%20m.profraw`.
46
47*   `%`p is replaced by the pid of the process
48*   `%m` by the hash of the library/binary
49*   The `20` in`%20m` creates a pool of 20 profraw files and "online" profile
50    merging is used to merge coverage to profiles onto this pool.
51
52Reference:`LLVM_PROFILE_FILE` can include additional specifiers as described
53[here](https://clang.llvm.org/docs/SourceBasedCodeCoverage.html#running-the-instrumented-program).
54
55For this and following steps, use the `acov-llvm.py` script:
56`$ANDROID_BUILD_TOP/development/scripts/acov-llvm.py`.
57
58There may be profiles in `/data/misc/trace` collected before the test is run.
59Clear this data before running the test.
60
61```
62    # Clear any coverage that's already written to /data/misc/trace
63    # and reset coverage for all daemons.
64    <host>$ acov-llvm.py clean-device
65
66    # Run the test.  The exact command depends on the nature of the test.
67    <device>$ /data/local/tmp/$MY_TEST
68```
69
70For tests that exercise a daemon/service running in another process, write out
71the coverage for those processes as well.
72
73```
74    # Flush coverage of all daemons/processes running on the device.
75    <host>$ acov-llvm.py flush
76
77    # Flush coverage for a particular daemon, say adbd.
78    <host>$ acov-llvm.py flush adbd
79```
80
81## Viewing Coverage Data (acov-llvm.py)
82
83To post-process and view coverage information we use the `acov-llvm.py report`
84command. It invokes two LLVM utilities `llvm-profdata` and `llvm-cov`. An
85advanced user can manually invoke these utilities for fine-grained control. This
86is discussed [below](#viewing-coverage-data-manual).
87
88To generate coverage report need the following parameters. These are dependent
89on the test/module:
90
911.  One or more binaries and shared libraries from which coverage was collected.
92    E.g.:
93
94    1.  ART mainline module contains a few libraries such as `libart.so`,
95        `libart-compiler.so`.
96    2.  Bionic tests exercise code in `libc.so` and `libm.so`.
97
98    We need the *unstripped* copies of these binaries. Source information
99    included in the debuginfo is used to process the coverage data.
100
1012.  One or more source directories under `$ANDROID_BUILD_TOP` for which coverage
102    needs to be reported.
103
104Invoke the report subcommand of acov-llvm.py to produce a html coverage summary:
105
106```
107    $ acov-llvm.py report \
108        -s <one-or-more-source-paths-in-$ANDROID_BUILD_TOP \
109        -b <one-or-more-(unstripped)-binaries-in-$OUT>
110```
111
112E.g.:
113
114```
115    $ acov-llvm.py report \
116        -s bionic \
117        -b \
118        $OUT/symbols/apex/com.android.runtime/lib/bionic/libc.so \
119        $OUT/symbols/apex/com.android.runtime/lib/bionic/libm.so
120```
121
122The script will produce a report in a temporary directory under
123`$ANDROID_BUILD_TOP`. It'll produce a log as below:
124
125```
126    generating coverage report in covreport-xxxxxx
127```
128
129A html report would be generated under `covreport-xxxxxx/html`.
130
131## Viewing Coverage Data (manual)
132
133`acov-llvm.py report` does a few operations under the hood which we can also
134manually invoke for flexibility.
135
136### Post-processing Coverage Files
137
138Fetch coverage files from the device and post-process them to a `.profdata` file
139as follows:
140
141```
142    # Fetch the coverage data from the device.
143    <host>$ cd coverage_data
144    <host>$ adb pull /data/misc/trace/ $TRACE_DIR_HOST
145
146    # Convert from .profraw format to the .profdata format.
147    <host>$ llvm-profdata merge --output=$MY_TEST.profdata \
148    $TRACE_DIR_HOST/clang-*.profraw
149```
150
151For added specificity, restrict the above command to just the <PID>s of the
152daemon or test processes of interest.
153
154```
155    <host>$ llvm-profdata merge --output=$MY_TEST.profdata \
156    $MY_TEST.profraw \
157    trace/clang-<pid1>.profraw trace/clang-<pid2>.profraw ...
158```
159
160### Generating Coverage report
161
162Documentation on Clang source-instrumentation-based coverage is available
163[here](https://clang.llvm.org/docs/SourceBasedCodeCoverage.html#creating-coverage-reports).
164The `llvm-cov` utility is used to show coverage from a `.profdata` file. The
165documentation for commonly used `llvm-cov` command-line arguments is available
166[here](https://llvm.org/docs/CommandGuide/llvm-cov.html#llvm-cov-report). (Try
167`llvm-cov show --help` for a complete list).
168
169#### `show` subcommand
170
171The `show` command displays the function and line coverage for each source file
172in the binary.
173
174```
175    <host>$ llvm-cov show \
176        --show-region-summary=false
177        --format=html --output-dir=coverage-html \
178        --instr-profile=$MY_TEST.profdata \
179        $MY_BIN \
180```
181
182*   In the above command, `$MY_BIN` should be the unstripped binary (i.e. with
183    debuginfo) since `llvm-cov` reads some debuginfo to process the coverage
184    data.
185
186    E.g.:
187
188    ~~~
189    ```
190    <host>$ llvm-cov report \
191        --instr-profile=adbd.profdata \
192        $LOCATION_OF_UNSTRIPPED_ADBD/adbd \
193        --show-region-summary=false
194    ```
195    ~~~
196
197*   The `-ignore-filename-regex=<regex>` option can be used to ignore files that
198    are not of interest. E.g: `-ignore-filename-regex="external/*"`
199
200*   Use the `--object=<BIN>` argument to specify additional binaries and shared
201    libraries whose coverage is included in this profdata. See the earlier
202    [section](#viewing-coverage-data-acov-llvm-py) for examples where more than
203    one binary may need to be used.
204
205    E.g., the following command is used for `bionic-unit-tests`, which tests
206    both `libc.so` and `libm.so`:
207
208    ~~~
209    ```
210    <host>$ llvm-cov report \
211        --instr-profile=bionic.profdata \
212        $OUT/.../libc.so \
213        --object=$OUT/.../libm.so
214    ```
215    ~~~
216
217*   `llvm-cov` also takes positional SOURCES argument to consider/display only
218    particular paths of interest. E.g:
219
220    ~~~
221    ```
222    <host>$ llvm-cov report \
223        --instr-profile=adbd.profdata \
224        $LOCATION_OF_ADBD/adbd \
225        --show-region-summary=false \
226        /proc/self/cwd/system/core/adb
227    ```
228    ~~~
229
230Note that the paths for the sources need to be prepended with
231'`/proc/self/cwd/`'. This is because Android C/C++ compilations run with
232`PWD=/proc/self/cwd` and consequently the source names are recorded with that
233prefix. Alternatively, the
234[`--path-equivalence`](https://llvm.org/docs/CommandGuide/llvm-cov.html#cmdoption-llvm-cov-show-path-equivalence)
235option to `llvm-cov` can be used.
236
237#### `report` subcommand
238
239The [`report`](https://llvm.org/docs/CommandGuide/llvm-cov.html#llvm-cov-report)
240subcommand summarizes the percentage of covered lines to the console. It takes
241options similar to the `show` subcommand.
242