Increase coverage of libartpalette-system native API.

- Call PaletteAshmemCreateRegion and PaletteAshmemSetProtRegion, which
  don't get exercised on memfd capable kernels.

- Call PaletteNotify{Begin,End}JniInvocation regardless of what the
  ShouldReport gate function says. Start a VM to give them a valid
  JNIEnv argument.

- Add a CTS test to run dex2oat with a new special flag to make it call
  PaletteNotify{Start,End}Dex2oatCompilation regardless of what the
  ShouldReport gate function says. This way they get valid fd's for the
  oat and vdex files.

Test: m cts cts-tradefed
      cts-tradefed run commandAndExit cts \
        --module art_standalone_dex2oat_cts_tests
      cts-tradefed run commandAndExit cts \
        --module art_standalone_libartpalette_tests
  with log messages in the hook functions in palette_android_partner.cc
  to verify that they are called.
Test: art/tools/run-gtests.sh \
        /apex/com.android.art/bin/art/{x86,x86_64}/art_libartpalette_tests
  in device chroot test environment
Test: m test-art-host-gtest-art_libartpalette_tests
Bug: 206657952
Change-Id: I91f3182f15d234dbaca2a4357442efd2e957373f
diff --git a/dex2oat/Android.bp b/dex2oat/Android.bp
index 5bc986b..254df02 100644
--- a/dex2oat/Android.bp
+++ b/dex2oat/Android.bp
@@ -577,3 +577,19 @@
     ],
     test_config: "art_standalone_dex2oat_tests.xml",
 }
+
+// Counterpart to art_standalone_dex2oat_tests for tests that go into CTS.
+art_cc_test {
+    name: "art_standalone_dex2oat_cts_tests",
+    defaults: ["art_standalone_gtest_defaults"],
+    srcs: ["dex2oat_cts_test.cc"],
+    data: [
+        ":art-gtest-jars-Main",
+        ":art-gtest-jars-MainStripped",
+        ":art-gtest-jars-MultiDex",
+        ":art-gtest-jars-MultiDexModifiedSecondary",
+        ":art-gtest-jars-Nested",
+    ],
+    test_config: "art_standalone_dex2oat_cts_tests.xml",
+    test_suites: ["cts"],
+}
diff --git a/dex2oat/art_standalone_dex2oat_cts_tests.xml b/dex2oat/art_standalone_dex2oat_cts_tests.xml
new file mode 100644
index 0000000..b61c3f3
--- /dev/null
+++ b/dex2oat/art_standalone_dex2oat_cts_tests.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs art_standalone_dex2oat_cts_tests.">
+    <option name="test-suite-tag" value="cts" />
+    <option name="config-descriptor:metadata" key="component" value="art" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+    <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+        <option name="cleanup" value="true" />
+        <option name="push" value="art_standalone_dex2oat_cts_tests->/data/local/tmp/art_standalone_dex2oat_cts_tests/art_standalone_dex2oat_cts_tests" />
+        <option name="append-bitness" value="true" />
+    </target_preparer>
+
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+        <option name="cleanup" value="true" />
+        <option name="push" value="art-gtest-jars-Main.jar->/data/local/tmp/art_standalone_dex2oat_cts_tests/art-gtest-jars-Main.jar" />
+        <option name="push" value="art-gtest-jars-MainStripped.jar->/data/local/tmp/art_standalone_dex2oat_cts_tests/art-gtest-jars-MainStripped.jar" />
+        <option name="push" value="art-gtest-jars-MultiDex.jar->/data/local/tmp/art_standalone_dex2oat_cts_tests/art-gtest-jars-MultiDex.jar" />
+        <option name="push" value="art-gtest-jars-MultiDexModifiedSecondary.jar->/data/local/tmp/art_standalone_dex2oat_cts_tests/art-gtest-jars-MultiDexModifiedSecondary.jar" />
+        <option name="push" value="art-gtest-jars-Nested.jar->/data/local/tmp/art_standalone_dex2oat_cts_tests/art-gtest-jars-Nested.jar" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp/art_standalone_dex2oat_cts_tests" />
+        <option name="module-name" value="art_standalone_dex2oat_cts_tests" />
+        <option name="ld-library-path-32" value="/apex/com.android.art/lib" />
+        <option name="ld-library-path-64" value="/apex/com.android.art/lib64" />
+    </test>
+
+    <!-- When this test is run in a Mainline context (e.g. with `mts-tradefed`), only enable it if
+         one of the Mainline modules below is present on the device used for testing. -->
+    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+        <!-- ART Mainline Module (internal version). -->
+        <option name="mainline-module-package-name" value="com.google.android.art" />
+        <!-- ART Mainline Module (external (AOSP) version). -->
+        <option name="mainline-module-package-name" value="com.android.art" />
+    </object>
+
+    <!-- Only run tests if the device under test is SDK version 31 (Android 12) or above. -->
+    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk31ModuleController" />
+</configuration>
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index a3bab85..ee65241 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -546,7 +546,8 @@
         check_linkage_conditions_(false),
         crash_on_linkage_violation_(false),
         compile_individually_(false),
-        profile_load_attempted_(false) {}
+        profile_load_attempted_(false),
+        should_report_dex2oat_compilation_(false) {}
 
   ~Dex2Oat() {
     // Log completion time before deleting the runtime_, because this accesses
@@ -1202,6 +1203,9 @@
       thread_count_ = 1;
     }
 
+    PaletteShouldReportDex2oatCompilation(&should_report_dex2oat_compilation_);
+    AssignTrueIfExists(args, M::ForcePaletteCompilationHooks, &should_report_dex2oat_compilation_);
+
     ProcessOptions(parser_options.get());
   }
 
@@ -2404,10 +2408,9 @@
 
   class ScopedDex2oatReporting {
    public:
-    explicit ScopedDex2oatReporting(const Dex2Oat& dex2oat) {
-      bool should_report = false;
-      PaletteShouldReportDex2oatCompilation(&should_report);
-      if (should_report) {
+    explicit ScopedDex2oatReporting(const Dex2Oat& dex2oat) :
+        should_report_(dex2oat.should_report_dex2oat_compilation_) {
+      if (should_report_) {
         if (dex2oat.zip_fd_ != -1) {
           zip_dup_fd_.reset(DupCloexecOrError(dex2oat.zip_fd_));
           if (zip_dup_fd_ < 0) {
@@ -2439,9 +2442,7 @@
 
     ~ScopedDex2oatReporting() {
       if (!error_reporting_) {
-        bool should_report = false;
-        PaletteShouldReportDex2oatCompilation(&should_report);
-        if (should_report) {
+        if (should_report_) {
           PaletteNotifyEndDex2oatCompilation(zip_dup_fd_,
                                              image_dup_fd_,
                                              oat_dup_fd_,
@@ -2466,6 +2467,7 @@
     android::base::unique_fd zip_dup_fd_;
     android::base::unique_fd image_dup_fd_;
     bool error_reporting_ = false;
+    bool should_report_;
   };
 
  private:
@@ -2952,6 +2954,9 @@
   // Whether or we attempted to load the profile (if given).
   bool profile_load_attempted_;
 
+  // Whether PaletteNotify{Start,End}Dex2oatCompilation should be called.
+  bool should_report_dex2oat_compilation_;
+
   DISALLOW_IMPLICIT_CONSTRUCTORS(Dex2Oat);
 };
 
diff --git a/dex2oat/dex2oat_cts_test.cc b/dex2oat/dex2oat_cts_test.cc
new file mode 100644
index 0000000..41c7015
--- /dev/null
+++ b/dex2oat/dex2oat_cts_test.cc
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "dex2oat_environment_test.h"
+
+namespace art {
+
+class Dex2oatCtsTest : public Dex2oatEnvironmentTest {};
+
+// Run dex2oat with --enable-palette-compilation-hooks to force calls to
+// PaletteNotify{Start,End}Dex2oatCompilation.
+TEST_F(Dex2oatCtsTest, CompilationHooks) {
+  const std::string dex_location = GetTestDexFileName("Main");
+  const std::string oat_location = GetScratchDir() + "/base.oat";
+  const std::string vdex_location = GetScratchDir() + "/base.vdex";
+
+  std::vector<std::string> args;
+  args.emplace_back("--dex-file=" + dex_location);
+
+  std::unique_ptr<File> oat_file(OS::CreateEmptyFile(oat_location.c_str()));
+  ASSERT_NE(oat_file, nullptr) << oat_location;
+  args.emplace_back("--oat-fd=" + std::to_string(oat_file->Fd()));
+  args.emplace_back("--oat-location=" + oat_location);
+
+  std::unique_ptr<File> vdex_file(OS::CreateEmptyFile(vdex_location.c_str()));
+  ASSERT_NE(vdex_file, nullptr) << vdex_location;
+  args.emplace_back("--output-vdex-fd=" + std::to_string(vdex_file->Fd()));
+
+  args.emplace_back("--force-palette-compilation-hooks");
+
+  std::string output = "";
+  std::string error_msg;
+  int res = Dex2Oat(args, &output, &error_msg);
+  EXPECT_EQ(res, 0) << error_msg;
+  EXPECT_EQ(oat_file->FlushCloseOrErase(), 0);
+  EXPECT_EQ(vdex_file->FlushCloseOrErase(), 0);
+}
+
+}  // namespace art
diff --git a/dex2oat/dex2oat_options.cc b/dex2oat/dex2oat_options.cc
index 6749fc5..b6fa71e 100644
--- a/dex2oat/dex2oat_options.cc
+++ b/dex2oat/dex2oat_options.cc
@@ -437,7 +437,10 @@
           .IntoKey(M::ApexVersions)
       .Define("--force-jit-zygote")
           .WithHelp("Optimizes the app to be executed in an environment that uses JIT Zygote.")
-          .IntoKey(M::ForceJitZygote);
+          .IntoKey(M::ForceJitZygote)
+      .Define("--force-palette-compilation-hooks")
+          .WithHelp("Force PaletteNotify{Start,End}Dex2oatCompilation calls.")
+          .IntoKey(M::ForcePaletteCompilationHooks);
 
   AddCompilerOptionsArgumentParserOptions<Dex2oatArgumentMap>(*parser_builder);
 
diff --git a/dex2oat/dex2oat_options.def b/dex2oat/dex2oat_options.def
index d878088..43a2b22 100644
--- a/dex2oat/dex2oat_options.def
+++ b/dex2oat/dex2oat_options.def
@@ -102,5 +102,6 @@
 DEX2OAT_OPTIONS_KEY (std::string,                    PublicSdk)
 DEX2OAT_OPTIONS_KEY (Unit,                           ForceAllowOjInlines)
 DEX2OAT_OPTIONS_KEY (std::string,                    ApexVersions)
+DEX2OAT_OPTIONS_KEY (Unit,                           ForcePaletteCompilationHooks)
 
 #undef DEX2OAT_OPTIONS_KEY
diff --git a/libartpalette/Android.bp b/libartpalette/Android.bp
index 51a9dab..1516ec6 100644
--- a/libartpalette/Android.bp
+++ b/libartpalette/Android.bp
@@ -122,7 +122,10 @@
 art_cc_defaults {
     name: "art_libartpalette_tests_defaults",
     srcs: ["apex/palette_test.cc"],
-    shared_libs: ["libartpalette"],
+    shared_libs: [
+        "libartpalette",
+        "libnativehelper",
+    ],
 }
 
 // Version of ART gtest `art_libartpalette_tests` bundled with the ART APEX on target.
diff --git a/libartpalette/apex/palette_test.cc b/libartpalette/apex/palette_test.cc
index e6018ee..a604998 100644
--- a/libartpalette/apex/palette_test.cc
+++ b/libartpalette/apex/palette_test.cc
@@ -16,8 +16,10 @@
 
 #include "palette/palette.h"
 
-#include <unistd.h>
+#include <jni.h>
+#include <sys/mman.h>
 #include <sys/syscall.h>
+#include <unistd.h>
 
 #include "gtest/gtest.h"
 
@@ -55,3 +57,37 @@
   EXPECT_EQ(PALETTE_STATUS_OK, PaletteTraceEnd());
   EXPECT_EQ(PALETTE_STATUS_OK, PaletteTraceIntegerValue("Beans", /*value=*/ 3));
 }
+
+TEST_F(PaletteClientTest, Ashmem) {
+#ifndef ART_TARGET_ANDROID
+  GTEST_SKIP() << "ashmem is only supported on Android";
+#else
+  int fd;
+  EXPECT_EQ(PALETTE_STATUS_OK, PaletteAshmemCreateRegion("ashmem-test", 4096, &fd));
+  EXPECT_EQ(PALETTE_STATUS_OK, PaletteAshmemSetProtRegion(fd, PROT_READ | PROT_EXEC));
+  EXPECT_EQ(0, close(fd));
+#endif
+}
+
+TEST_F(PaletteClientTest, JniInvocation) {
+#ifndef ART_TARGET_ANDROID
+  GTEST_SKIP() << "Not starting a VM on host";
+#else
+  bool enabled;
+  EXPECT_EQ(PALETTE_STATUS_OK, PaletteShouldReportJniInvocations(&enabled));
+
+  JavaVMInitArgs init_args;
+  init_args.version = JNI_VERSION_1_6;
+  init_args.nOptions = 0;
+  init_args.options = nullptr;
+  init_args.ignoreUnrecognized = JNI_FALSE;
+  JavaVM* vm = nullptr;
+  JNIEnv* env = nullptr;
+  ASSERT_EQ(JNI_OK, JNI_CreateJavaVM(&vm, &env, &init_args));
+
+  PaletteNotifyBeginJniInvocation(env);
+  PaletteNotifyEndJniInvocation(env);
+
+  vm->DestroyJavaVM();
+#endif
+}