blob: 40b78a51011a1ef17606c1a69878995cddd0ed11 [file] [log] [blame] [view]
jbudorick85ec08f2016-09-08 01:30:221# How GTests work on Android
2
3gtests are [googletest](https://github.com/google/googletest)-based C++ tests.
4On Android, they run on a device. In most cases, they're packaged as APKs, but
5there are a few cases where they're run as raw executables. The latter is
6necessary in a few cases, particularly when manipulating signal handlers, but
7isn't possible when the suite needs to call back through the JNI into Java code.
8
9[TOC]
10
11## APKs
12
13### GN
14
15Gtest APKs are built by default by the
16[test](https://codesearch.chromium.org/chromium/src/testing/test.gni?type=cs&q=file:%5Esrc%5C/testing%5C/test.gni$+template%5C("test"%5C)&sq=package:chromium)
17template, e.g.
18
19```python
20test("sample_gtest") {
21 # ...
22}
23```
24
25This uses gn's native
John Palmera8515fca2021-05-20 03:35:3226[shared_library](https://chromium.googlesource.com/chromium/src/+/main/tools/gn/docs/reference.md#shared_library_Declare-a-shared-library-target)
jbudorick85ec08f2016-09-08 01:30:2227target type along with the
28[unittest_apk](https://codesearch.chromium.org/chromium/src/build/config/android/rules.gni?type=cs&q=file:%5Esrc%5C/build%5C/config%5C/android%5C/rules.gni$+template%5C(%5C"unittest_apk%5C"%5C)&sq=package:chromium)
29template to build an APK containing:
30
31 - One or more .so files containing the native code on which the test suite
32depends
33 - One or more .dex files containing the Java code on which the test suite
34depends
35 - A [manifest](https://developer.android.com/guide/topics/manifest/manifest-intro.html)
36file that contains `<instrumentation>` and `<activity>` elements (among others).
37
38### Harness
39
40GTest APKs are packaged with a harness that consists of:
41
42 - [NativeTestInstrumentationTestRunner], an instrumentation entry point that
43handles running one or more sequential instances of a test Activity. Typically,
44unit test suites will only use one instance of the Activity and will run all of
45the specified tests in it, while browser test suites will use multiple instances
46and will only run one test per instance.
47 - Three [Activity](https://developer.android.com/reference/android/app/Activity.html)-based
48classes
49([NativeUnitTestActivity](https://codesearch.chromium.org/chromium/src/testing/android/native_test/java/src/org/chromium/native_test/NativeUnitTestActivity.java),
50[NativeUnitTestNativeActivity](https://codesearch.chromium.org/chromium/src/testing/android/native_test/java/src/org/chromium/native_test/NativeUnitTestNativeActivity.java),
51and
52[NativeBrowserTestActivity](https://codesearch.chromium.org/chromium/src/testing/android/native_test/java/src/org/chromium/native_test/NativeBrowserTestActivity.java))
53that primarily act as process entry points for individual test shards.
54Only one is used in any given suite.
55 - [NativeTest] and [NativeUnitTest],
56which handle formatting arguments for googletest and transferring control across
57the JNI.
58 - [testing::android::RunTests](https://codesearch.chromium.org/chromium/src/testing/android/native_test/native_test_launcher.cc?q=file:%5Esrc%5C/testing%5C/android%5C/native_test%5C/native_test_launcher.cc$+RunTests&sq=package:chromium),
59the function on the native side, which initializes the native command-line,
60redirects stdout either to a FIFO or a regular file, optionally waits for a
61debugger to attach to the process, sets up the test data directories, and then
62dispatches to googletest's `main` function.
63
64### Runtime
65
66 1. The test runner calls `am instrument` with a bunch of arguments,
67 includes several extras that are arguments to either
68 [NativeTestInstrumentationTestRunner] or [NativeTest]. This results in an
69 intent being sent to [NativeTestInstrumentationTestRunner].
70 2. [NativeTestInstrumentationTestRunner] is created. In its onCreate, it
71 parses its own arguments from the intent and retains all other arguments
72 to be passed to the Activities it'll start later. It also creates a
73 temporary file in the external storage directory for stdout. It finally
74 starts itself.
75 3. [NativeTestInstrumentationTestRunner] is started. In its onStart, it prepares
76 to receive notifications about the start and end of the test run from the
77 Activities it's about to start. It then creates [ShardStarter]
78 that will start the first test shard and adds that to the current
79 [Handler](https://developer.android.com/reference/android/os/Handler.html).
80 4. The [ShardStarter] is executed, starting the test Activity.
81 5. The Activity starts, possibly doing some process initialization, and hands
82 off to the [NativeTest].
83 6. The [NativeTest] handles some initialization and informs the
84 [NativeTestInstrumentationTestRunner] that it has started. On hearing this,
85 the [NativeTestInstrumentationTestRunner] creates a [ShardMonitor]
86 that will monitor the execution of the test Activity.
87 7. The [NativeTest] hands off to testing::android::RunTests. The tests run.
88 8. The [NativeTest] informs the [NativeTestInstrumentationTestRunner] that is has
89 completed. On hearing this, the [ShardMonitor] creates a [ShardEnder].
90 9. The [ShardEnder] is executed, killing the child process (if applicable),
91 parsing the results from the stdout file, and either launching the next
92 shard via [ShardStarter] (in which case the process returns to #4) or sending
93 the results out to the test runner and finishing the instrumentation.
94
95## Executables
96
97### GN
98
99Gtest executables are built by passing
100`use_raw_android_executable = True` to the
101[test](https://codesearch.chromium.org/chromium/src/testing/test.gni?type=cs&q=file:%5Esrc%5C/testing%5C/test.gni$+template%5C("test"%5C)&sq=package:chromium)
102template, e.g.
103
104```python
105test("sample_gtest_executable") {
106 if (is_android) {
107 use_raw_android_executable = true
108 }
109 # ...
110}
111```
112
113This uses gn's native
John Palmera8515fca2021-05-20 03:35:32114[executable](https://chromium.googlesource.com/chromium/src/+/main/tools/gn/docs/reference.md#executable_Declare-an-executable-target)
jbudorick85ec08f2016-09-08 01:30:22115target type, then copies the resulting executable and any requisite shared libraries
116to ```${root_out_dir}/${target_name}__dist``` (e.g. ```out/Debug/breakpad_unittests__dist```).
117
118### Harness
119
120Unlike APKs, gtest suites built as executables require no Android-specific harnesses.
121
122### Runtime
123
124The test runner simply executes the binary on the device directly and parses the
125stdout on its own.
126
127[NativeTest]: https://codesearch.chromium.org/chromium/src/testing/android/native_test/java/src/org/chromium/native_test/NativeTest.java
128[NativeTestInstrumentationTestRunner]: https://codesearch.chromium.org/chromium/src/testing/android/native_test/java/src/org/chromium/native_test/NativeTestInstrumentationTestRunner.java
129[NativeUnitTest]: https://codesearch.chromium.org/chromium/src/testing/android/native_test/java/src/org/chromium/native_test/NativeUnitTest.java
130[ShardEnder]: https://codesearch.chromium.org/chromium/src/testing/android/native_test/java/src/org/chromium/native_test/NativeTestInstrumentationTestRunner.java?q=file:NativeTestInstrumentationTestRunner.java+class:ShardEnder&sq=package:chromium
131[ShardMonitor]: https://codesearch.chromium.org/chromium/src/testing/android/native_test/java/src/org/chromium/native_test/NativeTestInstrumentationTestRunner.java?q=file:NativeTestInstrumentationTestRunner.java+class:ShardMonitor&sq=package:chromium
132[ShardStarter]: https://codesearch.chromium.org/chromium/src/testing/android/native_test/java/src/org/chromium/native_test/NativeTestInstrumentationTestRunner.java?q=file:NativeTestInstrumentationTestRunner.java+class:ShardStarter&sq=package:chromium