Index: testing/android/docs/gtest_implementation.md |
diff --git a/testing/android/docs/gtest_implementation.md b/testing/android/docs/gtest_implementation.md |
new file mode 100644 |
index 0000000000000000000000000000000000000000..b76a91fc7d4858d2e800e107385f67b83f2a4307 |
--- /dev/null |
+++ b/testing/android/docs/gtest_implementation.md |
@@ -0,0 +1,132 @@ |
+# How GTests work on Android |
+ |
+gtests are [googletest](https://github.com/google/googletest)-based C++ tests. |
+On Android, they run on a device. In most cases, they're packaged as APKs, but |
+there are a few cases where they're run as raw executables. The latter is |
+necessary in a few cases, particularly when manipulating signal handlers, but |
+isn't possible when the suite needs to call back through the JNI into Java code. |
+ |
+[TOC] |
+ |
+## APKs |
+ |
+### GN |
+ |
+Gtest APKs are built by default by the |
+[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) |
+template, e.g. |
+ |
+```python |
+test("sample_gtest") { |
+ # ... |
+} |
+``` |
+ |
+This uses gn's native |
+[shared_library](https://chromium.googlesource.com/chromium/src/+/master/tools/gn/docs/reference.md#shared_library_Declare-a-shared-library-target) |
+target type along with the |
+[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) |
+template to build an APK containing: |
+ |
+ - One or more .so files containing the native code on which the test suite |
+depends |
+ - One or more .dex files containing the Java code on which the test suite |
+depends |
+ - A [manifest](https://developer.android.com/guide/topics/manifest/manifest-intro.html) |
+file that contains `<instrumentation>` and `<activity>` elements (among others). |
+ |
+### Harness |
+ |
+GTest APKs are packaged with a harness that consists of: |
+ |
+ - [NativeTestInstrumentationTestRunner], an instrumentation entry point that |
+handles running one or more sequential instances of a test Activity. Typically, |
+unit test suites will only use one instance of the Activity and will run all of |
+the specified tests in it, while browser test suites will use multiple instances |
+and will only run one test per instance. |
+ - Three [Activity](https://developer.android.com/reference/android/app/Activity.html)-based |
+classes |
+([NativeUnitTestActivity](https://codesearch.chromium.org/chromium/src/testing/android/native_test/java/src/org/chromium/native_test/NativeUnitTestActivity.java), |
+[NativeUnitTestNativeActivity](https://codesearch.chromium.org/chromium/src/testing/android/native_test/java/src/org/chromium/native_test/NativeUnitTestNativeActivity.java), |
+and |
+[NativeBrowserTestActivity](https://codesearch.chromium.org/chromium/src/testing/android/native_test/java/src/org/chromium/native_test/NativeBrowserTestActivity.java)) |
+that primarily act as process entry points for individual test shards. |
+Only one is used in any given suite. |
+ - [NativeTest] and [NativeUnitTest], |
+which handle formatting arguments for googletest and transferring control across |
+the JNI. |
+ - [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), |
+the function on the native side, which initializes the native command-line, |
+redirects stdout either to a FIFO or a regular file, optionally waits for a |
+debugger to attach to the process, sets up the test data directories, and then |
+dispatches to googletest's `main` function. |
+ |
+### Runtime |
+ |
+ 1. The test runner calls `am instrument` with a bunch of arguments, |
+ includes several extras that are arguments to either |
+ [NativeTestInstrumentationTestRunner] or [NativeTest]. This results in an |
+ intent being sent to [NativeTestInstrumentationTestRunner]. |
+ 2. [NativeTestInstrumentationTestRunner] is created. In its onCreate, it |
+ parses its own arguments from the intent and retains all other arguments |
+ to be passed to the Activities it'll start later. It also creates a |
+ temporary file in the external storage directory for stdout. It finally |
+ starts itself. |
+ 3. [NativeTestInstrumentationTestRunner] is started. In its onStart, it prepares |
+ to receive notifications about the start and end of the test run from the |
+ Activities it's about to start. It then creates [ShardStarter] |
+ that will start the first test shard and adds that to the current |
+ [Handler](https://developer.android.com/reference/android/os/Handler.html). |
+ 4. The [ShardStarter] is executed, starting the test Activity. |
+ 5. The Activity starts, possibly doing some process initialization, and hands |
+ off to the [NativeTest]. |
+ 6. The [NativeTest] handles some initialization and informs the |
+ [NativeTestInstrumentationTestRunner] that it has started. On hearing this, |
+ the [NativeTestInstrumentationTestRunner] creates a [ShardMonitor] |
+ that will monitor the execution of the test Activity. |
+ 7. The [NativeTest] hands off to testing::android::RunTests. The tests run. |
+ 8. The [NativeTest] informs the [NativeTestInstrumentationTestRunner] that is has |
+ completed. On hearing this, the [ShardMonitor] creates a [ShardEnder]. |
+ 9. The [ShardEnder] is executed, killing the child process (if applicable), |
+ parsing the results from the stdout file, and either launching the next |
+ shard via [ShardStarter] (in which case the process returns to #4) or sending |
+ the results out to the test runner and finishing the instrumentation. |
+ |
+## Executables |
+ |
+### GN |
+ |
+Gtest executables are built by passing |
+`use_raw_android_executable = True` to the |
+[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) |
+template, e.g. |
+ |
+```python |
+test("sample_gtest_executable") { |
+ if (is_android) { |
+ use_raw_android_executable = true |
+ } |
+ # ... |
+} |
+``` |
+ |
+This uses gn's native |
+[executable](https://chromium.googlesource.com/chromium/src/+/master/tools/gn/docs/reference.md#executable_Declare-an-executable-target) |
+target type, then copies the resulting executable and any requisite shared libraries |
+to ```${root_out_dir}/${target_name}__dist``` (e.g. ```out/Debug/breakpad_unittests__dist```). |
+ |
+### Harness |
+ |
+Unlike APKs, gtest suites built as executables require no Android-specific harnesses. |
+ |
+### Runtime |
+ |
+The test runner simply executes the binary on the device directly and parses the |
+stdout on its own. |
+ |
+[NativeTest]: https://codesearch.chromium.org/chromium/src/testing/android/native_test/java/src/org/chromium/native_test/NativeTest.java |
+[NativeTestInstrumentationTestRunner]: https://codesearch.chromium.org/chromium/src/testing/android/native_test/java/src/org/chromium/native_test/NativeTestInstrumentationTestRunner.java |
+[NativeUnitTest]: https://codesearch.chromium.org/chromium/src/testing/android/native_test/java/src/org/chromium/native_test/NativeUnitTest.java |
+[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 |
+[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 |
+[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 |