Add a "broken test ART APEX" Soong module.

Introduce test APEX module `test_broken_com.android.art`, to be used
in a test exercising ART Mainline Module rollbacks. Instead of the
regular `libart` module, this test APEX includes a `libart-broken`
module, a "broken" version of `libart` which delibaretely crashes
during the creation of a new VM (in `JNI_CreateJavaVM`), thus
trigerring a rollback of this test APEX.

Test: m test_broken_com.android.art
Bug: 204887479
Change-Id: I5ab50dffcf517e05c7008a881cde89c6ae0a12ca
diff --git a/build/apex/Android.bp b/build/apex/Android.bp
index c2e08d5..864f4ca 100644
--- a/build/apex/Android.bp
+++ b/build/apex/Android.bp
@@ -51,7 +51,7 @@
 // `art/Android.mk`.
 // TODO(b/121117762): Remove this note when both the ART Buildbot and Golem use
 // the ART APEX.
-art_runtime_base_native_shared_libs = [
+art_runtime_base_native_shared_libs_minus_libart = [
     // External API (having APEX stubs).
     "libdexfile",
     "libnativebridge",
@@ -63,7 +63,6 @@
     "libadbconnection",
     // TODO(b/124476339): Clean up the following libraries once "required"
     // dependencies work with APEX libraries.
-    "libart",
     "libart-compiler",
     "libartservice",
     "libdt_fd_forward",
@@ -76,6 +75,12 @@
     // when such a target exists
     "libarttools",
 ]
+// Actual version of ART runtime base libs, used in non-test ART APEXes.
+art_runtime_base_native_shared_libs = ["libart"] +
+    art_runtime_base_native_shared_libs_minus_libart
+// "Broken" version of ART runtime base libs, used for testing purposes.
+art_runtime_base_broken_native_shared_libs = ["libart-broken"] +
+    art_runtime_base_native_shared_libs_minus_libart
 
 art_runtime_base_native_device_only_shared_libs = [
     "libperfetto_hprof",
@@ -332,6 +337,28 @@
     installable: false,
 }
 
+// "Broken" test APEX, only used for testing, including module
+// `libart-broken` instead of `libart`.
+apex_test {
+    name: "test_broken_com.android.art",
+    defaults: ["com.android.art-defaults"],
+
+    // Only include native libraries in this test APEX. Don't include
+    // binaries (and maybe other artifacts) for now, as they pull
+    // the "non-broken" `libart` module into this test APEX and
+    // overwrite `libart-broken`. Maybe consider creating "broken"
+    // variants of binaries (and other artifacts)?
+    native_shared_libs: art_runtime_base_broken_native_shared_libs,
+    compile_multilib: "both",
+
+    key: "com.android.art.key",
+    manifest: "test_apex_manifest.json",
+    file_contexts: ":com.android.art-file_contexts",
+    certificate: ":com.android.art.certificate",
+    installable: false,
+    min_sdk_version: "31",
+}
+
 // Release version of the ART APEX module (not containing debug
 // variants nor tools), included in user builds. Also used for
 // storage-constrained devices in userdebug and eng builds.
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 9e39632..f219cc0 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -584,8 +584,9 @@
 // We always build dex2oat and dependencies, even if the host build is otherwise disabled, since
 // they are used to cross compile for the target.
 
-art_cc_library {
-    name: "libart",
+// Properties common to `libart` and `libart-broken`.
+art_cc_defaults {
+    name: "libart_common_defaults",
     defaults: [
         "libart_defaults",
         "libart_nativeunwind_defaults",
@@ -612,12 +613,31 @@
             },
         },
     },
+}
+
+// Release version of the ART runtime library.
+art_cc_library {
+    name: "libart",
+    defaults: ["libart_common_defaults"],
     apex_available: [
         "com.android.art",
         "com.android.art.debug",
     ],
 }
 
+// "Broken" version of the ART runtime library, used only for testing.
+art_cc_test_library {
+    name: "libart-broken",
+    defaults: ["libart_common_defaults"],
+    stem: "libart",
+    gtest: false,
+    cflags: ["-DART_CRASH_RUNTIME_DELIBERATELY"],
+    apex_available: [
+        "test_broken_com.android.art",
+    ],
+}
+
+// Debug version of the ART runtime library.
 art_cc_library {
     name: "libartd",
     defaults: [
diff --git a/runtime/jni/java_vm_ext.cc b/runtime/jni/java_vm_ext.cc
index e6e341a..053afc9 100644
--- a/runtime/jni/java_vm_ext.cc
+++ b/runtime/jni/java_vm_ext.cc
@@ -1229,6 +1229,13 @@
     return JNI_ERR;
   }
 
+  // When `ART_CRASH_RUNTIME_DELIBERATELY` is defined (which happens only in the
+  // case of a test APEX), we crash the runtime here on purpose, to test the
+  // behavior of rollbacks following a failed ART Mainline Module update.
+#ifdef ART_CRASH_RUNTIME_DELIBERATELY
+  LOG(FATAL) << "Runtime crashing deliberately for testing purposes.";
+#endif
+
   // Initialize native loader. This step makes sure we have
   // everything set up before we start using JNI.
   android::InitializeNativeLoader();