Add override flag for systemservercompilerfilter

Introduce a phenotype flag hook to override the
device/default system server compiler filter setting, backed by
`runtime_native_boot.systemservercompilerfilter_override`.

Bug: 262583457
Test: atest odsign_e2e_tests_full
Change-Id: Ic6a8bcff236c44e51b6ff33e8e258495304b162f
diff --git a/odrefresh/odr_config.h b/odrefresh/odr_config.h
index 5261fe4..76375ac 100644
--- a/odrefresh/odr_config.h
+++ b/odrefresh/odr_config.h
@@ -41,6 +41,11 @@
 // everything if any property matching a prefix changes.
 constexpr const char* kCheckedSystemPropertyPrefixes[]{"dalvik.vm.", "ro.dalvik.vm."};
 
+// System property for the phenotype flag to override the device or default-configured
+// system server compiler filter setting.
+static constexpr char kSystemPropertySystemServerCompilerFilterOverride[] =
+    "persist.device_config.runtime_native_boot.systemservercompilerfilter_override";
+
 // The list of system properties that odrefresh ignores. They don't affect compilation results.
 const std::unordered_set<std::string> kIgnoredSystemProperties{
     "dalvik.vm.dex2oat-cpu-set",
@@ -68,7 +73,9 @@
 const android::base::NoDestructor<std::vector<SystemPropertyConfig>> kSystemProperties{
     {SystemPropertyConfig{.name = "persist.device_config.runtime_native_boot.enable_uffd_gc",
                           .default_value = "false"},
-     SystemPropertyConfig{.name = kPhDisableCompactDex, .default_value = "false"}}};
+     SystemPropertyConfig{.name = kPhDisableCompactDex, .default_value = "false"},
+     SystemPropertyConfig{.name = kSystemPropertySystemServerCompilerFilterOverride,
+                          .default_value = ""}}};
 
 // An enumeration of the possible zygote configurations on Android.
 enum class ZygoteKind : uint8_t {
diff --git a/odrefresh/odrefresh_main.cc b/odrefresh/odrefresh_main.cc
index 09f8f56..e62bc41 100644
--- a/odrefresh/odrefresh_main.cc
+++ b/odrefresh/odrefresh_main.cc
@@ -43,6 +43,7 @@
 using ::art::odrefresh::kCheckedSystemPropertyPrefixes;
 using ::art::odrefresh::kIgnoredSystemProperties;
 using ::art::odrefresh::kSystemProperties;
+using ::art::odrefresh::kSystemPropertySystemServerCompilerFilterOverride;
 using ::art::odrefresh::OdrCompilationLog;
 using ::art::odrefresh::OdrConfig;
 using ::art::odrefresh::OdrMetrics;
@@ -177,6 +178,7 @@
 
   if (config->GetSystemServerCompilerFilter().empty()) {
     std::string filter = GetProperty("dalvik.vm.systemservercompilerfilter", "");
+    filter = GetProperty(kSystemPropertySystemServerCompilerFilterOverride, filter);
     config->SetSystemServerCompilerFilter(filter);
   }
 
diff --git a/test/odsign/test-src/com/android/tests/odsign/OdrefreshHostTest.java b/test/odsign/test-src/com/android/tests/odsign/OdrefreshHostTest.java
index e67822e..2bd24f9 100644
--- a/test/odsign/test-src/com/android/tests/odsign/OdrefreshHostTest.java
+++ b/test/odsign/test-src/com/android/tests/odsign/OdrefreshHostTest.java
@@ -214,6 +214,72 @@
     }
 
     @Test
+    public void verifySystemServerCompilerFilterOverrideChangeTriggersCompilation()
+            throws Exception {
+        try {
+            // Disable phenotype flag syncing. Potentially, we can set
+            // `set_sync_disabled_for_tests` to `until_reboot`, but setting it to
+            // `persistent` prevents unrelated system crashes/restarts from affecting the
+            // test. `set_sync_disabled_for_tests` is reset in the `finally` block anyway.
+            getDevice()
+                    .executeShellV2Command("device_config set_sync_disabled_for_tests persistent");
+
+            // Simulate that the phenotype flag is set to the default value.
+            getDevice()
+                    .executeShellV2Command(
+                            "device_config put runtime_native_boot"
+                                + " systemservercompilerfilter_override");
+
+            long timeMs = mTestUtils.getCurrentTimeMs();
+            runOdrefresh();
+
+            // Artifacts should not be re-compiled.
+            assertArtifactsNotModifiedAfter(getZygoteArtifacts(), timeMs);
+            assertArtifactsNotModifiedAfter(getSystemServerArtifacts(), timeMs);
+
+            // Simulate that the phenotype flag is set to "speed".
+            getDevice()
+                    .executeShellV2Command(
+                            "device_config put runtime_native_boot"
+                                + " systemservercompilerfilter_override speed");
+
+            timeMs = mTestUtils.getCurrentTimeMs();
+            runOdrefresh();
+
+            // Artifacts should be re-compiled.
+            assertArtifactsModifiedAfter(getZygoteArtifacts(), timeMs);
+            assertArtifactsModifiedAfter(getSystemServerArtifacts(), timeMs);
+
+            // Run odrefresh again with the flag unchanged.
+            timeMs = mTestUtils.getCurrentTimeMs();
+            runOdrefresh();
+
+            // Artifacts should not be re-compiled.
+            assertArtifactsNotModifiedAfter(getZygoteArtifacts(), timeMs);
+            assertArtifactsNotModifiedAfter(getSystemServerArtifacts(), timeMs);
+
+            // Simulate that the phenotype flag is set to "verify".
+            getDevice()
+                    .executeShellV2Command(
+                            "device_config put runtime_native_boot"
+                                + " systemservercompilerfilter_override verify");
+
+            timeMs = mTestUtils.getCurrentTimeMs();
+            runOdrefresh();
+
+            // Artifacts should be re-compiled.
+            assertArtifactsModifiedAfter(getZygoteArtifacts(), timeMs);
+            assertArtifactsModifiedAfter(getSystemServerArtifacts(), timeMs);
+        } finally {
+            getDevice().executeShellV2Command("device_config set_sync_disabled_for_tests none");
+            getDevice()
+                    .executeShellV2Command(
+                            "device_config delete runtime_native_boot"
+                                + " systemservercompilerfilter_override");
+        }
+    }
+
+    @Test
     public void verifySystemPropertyMismatchTriggersCompilation() throws Exception {
         // Change a system property from empty to a value.
         getDevice().setProperty("dalvik.vm.foo", "1");