Compat-framework on ravenwood

Flag: EXEMPT host test change only
Bug: 367706429
Test: $ANDROID_BUILD_TOP/frameworks/base/ravenwood/scripts/run-ravenwood-tests.sh
Change-Id: Ibef0180fe3e5acb919cb6cbab09574c508e6d894
Merged-In: Ibef0180fe3e5acb919cb6cbab09574c508e6d894
diff --git a/core/java/android/app/AppCompatCallbacks.java b/core/java/android/app/AppCompatCallbacks.java
index f2debfc..4ef8eb7 100644
--- a/core/java/android/app/AppCompatCallbacks.java
+++ b/core/java/android/app/AppCompatCallbacks.java
@@ -28,6 +28,7 @@
  *
  * @hide
  */
[email protected]
 public final class AppCompatCallbacks implements Compatibility.BehaviorChangeDelegate {
     private final long[] mDisabledChanges;
     private final long[] mLoggableChanges;
diff --git a/core/java/android/app/compat/ChangeIdStateCache.java b/core/java/android/app/compat/ChangeIdStateCache.java
index dea4e9c8..a185d6a 100644
--- a/core/java/android/app/compat/ChangeIdStateCache.java
+++ b/core/java/android/app/compat/ChangeIdStateCache.java
@@ -29,13 +29,24 @@
  * Handles caching of calls to {@link com.android.internal.compat.IPlatformCompat}
  * @hide
  */
[email protected]
 public final class ChangeIdStateCache
         extends PropertyInvalidatedCache<ChangeIdStateQuery, Boolean> {
     private static final String CACHE_KEY = "cache_key.is_compat_change_enabled";
     private static final int MAX_ENTRIES = 64;
-    private static boolean sDisabled = false;
+    private static boolean sDisabled = getDefaultDisabled();
     private volatile IPlatformCompat mPlatformCompat;
 
+
+    @android.ravenwood.annotation.RavenwoodReplace
+    private static boolean getDefaultDisabled() {
+        return false;
+    }
+
+    private static boolean getDefaultDisabled$ravenwood() {
+        return true; // TODO(b/376676753) Disable the cache for now.
+    }
+
     /** @hide */
     public ChangeIdStateCache() {
         super(MAX_ENTRIES, CACHE_KEY);
diff --git a/core/java/android/app/compat/ChangeIdStateQuery.java b/core/java/android/app/compat/ChangeIdStateQuery.java
index 7598d6c..26d9ab6 100644
--- a/core/java/android/app/compat/ChangeIdStateQuery.java
+++ b/core/java/android/app/compat/ChangeIdStateQuery.java
@@ -35,6 +35,7 @@
  * @hide
  */
 @Immutable
[email protected]
 final class ChangeIdStateQuery {
 
     static final int QUERY_BY_PACKAGE_NAME = 0;
diff --git a/core/java/android/app/compat/CompatChanges.java b/core/java/android/app/compat/CompatChanges.java
index d7b2ab4..643d4c9 100644
--- a/core/java/android/app/compat/CompatChanges.java
+++ b/core/java/android/app/compat/CompatChanges.java
@@ -39,6 +39,7 @@
  * @hide
  */
 @SystemApi
[email protected]
 public final class CompatChanges {
     private static final ChangeIdStateCache QUERY_CACHE = new ChangeIdStateCache();
 
diff --git a/core/java/android/app/compat/PackageOverride.java b/core/java/android/app/compat/PackageOverride.java
index ebc2945..ffc1eec 100644
--- a/core/java/android/app/compat/PackageOverride.java
+++ b/core/java/android/app/compat/PackageOverride.java
@@ -36,6 +36,7 @@
  * @hide
  */
 @SystemApi
[email protected]
 public final class PackageOverride {
 
     /** @hide */
diff --git a/core/java/com/android/internal/compat/AndroidBuildClassifier.java b/core/java/com/android/internal/compat/AndroidBuildClassifier.java
index 364db06..19f8889 100644
--- a/core/java/com/android/internal/compat/AndroidBuildClassifier.java
+++ b/core/java/com/android/internal/compat/AndroidBuildClassifier.java
@@ -22,6 +22,7 @@
  * Platform private class for determining the type of Android build installed.
  *
  */
[email protected]
 public class AndroidBuildClassifier {
 
     public boolean isDebuggableBuild() {
diff --git a/core/java/com/android/internal/compat/ChangeReporter.java b/core/java/com/android/internal/compat/ChangeReporter.java
index ded142c..bfa122b 100644
--- a/core/java/com/android/internal/compat/ChangeReporter.java
+++ b/core/java/com/android/internal/compat/ChangeReporter.java
@@ -42,6 +42,7 @@
  *
  * @hide
  */
[email protected]
 public final class ChangeReporter {
     private static final String TAG = "CompatChangeReporter";
     private static final Function<Integer, Set<ChangeReport>> NEW_CHANGE_REPORT_SET =
diff --git a/core/java/com/android/internal/compat/CompatibilityChangeConfig.java b/core/java/com/android/internal/compat/CompatibilityChangeConfig.java
index 182dba7..8fd914ae 100644
--- a/core/java/com/android/internal/compat/CompatibilityChangeConfig.java
+++ b/core/java/com/android/internal/compat/CompatibilityChangeConfig.java
@@ -28,6 +28,7 @@
  * Parcelable containing compat config overrides for a given application.
  * @hide
  */
[email protected]
 public final class CompatibilityChangeConfig implements Parcelable {
     private final ChangeConfig mChangeConfig;
 
diff --git a/core/java/com/android/internal/compat/CompatibilityChangeInfo.java b/core/java/com/android/internal/compat/CompatibilityChangeInfo.java
index 03fe455..505fd23 100644
--- a/core/java/com/android/internal/compat/CompatibilityChangeInfo.java
+++ b/core/java/com/android/internal/compat/CompatibilityChangeInfo.java
@@ -25,6 +25,7 @@
  *
  * @hide
  */
[email protected]
 public class CompatibilityChangeInfo implements Parcelable {
     private final long mChangeId;
     private final @Nullable String mName;
diff --git a/core/java/com/android/internal/compat/CompatibilityOverrideConfig.java b/core/java/com/android/internal/compat/CompatibilityOverrideConfig.java
index 9a02b7b..32206c9 100644
--- a/core/java/com/android/internal/compat/CompatibilityOverrideConfig.java
+++ b/core/java/com/android/internal/compat/CompatibilityOverrideConfig.java
@@ -28,6 +28,7 @@
  * Parcelable containing compat config overrides for a given application.
  * @hide
  */
[email protected]
 public final class CompatibilityOverrideConfig implements Parcelable {
     public final Map<Long, PackageOverride> overrides;
 
diff --git a/core/java/com/android/internal/compat/CompatibilityOverridesByPackageConfig.java b/core/java/com/android/internal/compat/CompatibilityOverridesByPackageConfig.java
index 8652bb6..998b48a 100644
--- a/core/java/com/android/internal/compat/CompatibilityOverridesByPackageConfig.java
+++ b/core/java/com/android/internal/compat/CompatibilityOverridesByPackageConfig.java
@@ -26,6 +26,7 @@
  * Parcelable containing compat config overrides by application.
  * @hide
  */
[email protected]
 public final class CompatibilityOverridesByPackageConfig implements Parcelable {
     public final Map<String, CompatibilityOverrideConfig> packageNameToOverrides;
 
diff --git a/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveByPackageConfig.java b/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveByPackageConfig.java
index b408d64..c0e2217 100644
--- a/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveByPackageConfig.java
+++ b/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveByPackageConfig.java
@@ -29,6 +29,7 @@
  * IDs.
  * @hide
  */
[email protected]
 public final class CompatibilityOverridesToRemoveByPackageConfig implements Parcelable {
     public final Map<String, CompatibilityOverridesToRemoveConfig> packageNameToOverridesToRemove;
 
diff --git a/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveConfig.java b/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveConfig.java
index e85afef..10461ec 100644
--- a/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveConfig.java
+++ b/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveConfig.java
@@ -30,6 +30,7 @@
  * <p>This class is separate from CompatibilityOverrideConfig since we only need change IDs.
  * @hide
  */
[email protected]
 public final class CompatibilityOverridesToRemoveConfig implements Parcelable {
     public final Set<Long> changeIds;
 
diff --git a/core/java/com/android/internal/compat/OverrideAllowedState.java b/core/java/com/android/internal/compat/OverrideAllowedState.java
index e408be2..f018c3a 100644
--- a/core/java/com/android/internal/compat/OverrideAllowedState.java
+++ b/core/java/com/android/internal/compat/OverrideAllowedState.java
@@ -27,6 +27,7 @@
 /**
  * This class contains all the possible override allowed states.
  */
[email protected]
 public final class OverrideAllowedState implements Parcelable {
     @IntDef({
             ALLOWED,
diff --git a/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java b/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java
index a69d2e4..3303d87 100644
--- a/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java
+++ b/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java
@@ -15,6 +15,12 @@
  */
 package com.android.internal.ravenwood;
 
+import static android.os.Build.VERSION_CODES.S;
+import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
+
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.Disabled;
+import android.compat.annotation.EnabledAfter;
 import android.ravenwood.annotation.RavenwoodKeepWholeClass;
 import android.ravenwood.annotation.RavenwoodRedirect;
 import android.ravenwood.annotation.RavenwoodRedirectionClass;
@@ -78,4 +84,20 @@
     public String getRavenwoodRuntimePath() {
         throw notSupportedOnDevice();
     }
+
+    /** @hide */
+    public static class CompatIdsForTest {
+        // Enabled by default
+        @ChangeId
+        public static final long TEST_COMPAT_ID_1 = 368131859L;
+
+        @Disabled
+        @ChangeId public static final long TEST_COMPAT_ID_2 = 368131701L;
+
+        @EnabledAfter(targetSdkVersion = S)
+        @ChangeId public static final long TEST_COMPAT_ID_3 = 368131659L;
+
+        @EnabledAfter(targetSdkVersion = UPSIDE_DOWN_CAKE)
+        @ChangeId public static final long TEST_COMPAT_ID_4 = 368132057L;
+    }
 }
diff --git a/ravenwood/Framework.bp b/ravenwood/Framework.bp
index d207738..99fc31b 100644
--- a/ravenwood/Framework.bp
+++ b/ravenwood/Framework.bp
@@ -214,7 +214,8 @@
 
 java_genrule {
     name: "services.core.ravenwood",
-    defaults: ["ravenwood-internal-only-visibility-genrule"],
+    // This is used by unit tests too (so tests will be able to access HSG-processed implementation)
+    // so it's visible to all.
     cmd: "cp $(in) $(out)",
     srcs: [
         ":services.core.ravenwood-base{ravenwood.jar}",
diff --git a/ravenwood/TEST_MAPPING b/ravenwood/TEST_MAPPING
index a1243e3..607592b 100644
--- a/ravenwood/TEST_MAPPING
+++ b/ravenwood/TEST_MAPPING
@@ -117,7 +117,11 @@
       "host": true
     },
     {
-      "name": "FrameworksServicesTestsRavenwood",
+      "name": "FrameworksServicesTestsRavenwood_Compat",
+      "host": true
+    },
+    {
+      "name": "FrameworksServicesTestsRavenwood_Uri",
       "host": true
     },
     {
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
index c5a9c7b..678a97b 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
@@ -30,9 +30,12 @@
 
 import android.annotation.Nullable;
 import android.app.ActivityManager;
+import android.app.AppCompatCallbacks;
 import android.app.Instrumentation;
 import android.app.ResourcesManager;
 import android.app.UiAutomation;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
 import android.content.res.Resources;
 import android.os.Binder;
 import android.os.Build;
@@ -41,6 +44,7 @@
 import android.os.Looper;
 import android.os.Process_ravenwood;
 import android.os.ServiceManager;
+import android.os.ServiceManager.ServiceNotFoundException;
 import android.os.SystemProperties;
 import android.provider.DeviceConfig_host;
 import android.system.ErrnoException;
@@ -58,6 +62,7 @@
 import com.android.ravenwood.common.RavenwoodRuntimeException;
 import com.android.ravenwood.common.SneakyThrow;
 import com.android.server.LocalServices;
+import com.android.server.compat.PlatformCompat;
 
 import org.junit.runner.Description;
 
@@ -331,6 +336,8 @@
 
         RavenwoodSystemServer.init(config);
 
+        initializeCompatIds(config);
+
         if (ENABLE_TIMEOUT_STACKS) {
             sPendingTimeout = sTimeoutExecutor.schedule(
                     RavenwoodRuntimeEnvironmentController::dumpStacks,
@@ -346,6 +353,31 @@
         Binder.restoreCallingIdentity(packBinderIdentityToken(false, config.mUid, config.mPid));
     }
 
+    private static void initializeCompatIds(RavenwoodConfig config) {
+        // Set up compat-IDs for the app side.
+        // TODO: Inside the system server, all the compat-IDs should be enabled,
+        // Due to the `AppCompatCallbacks.install(new long[0], new long[0])` call in
+        // SystemServer.
+
+        // Compat framework only uses the package name and the target SDK level.
+        ApplicationInfo appInfo = new ApplicationInfo();
+        appInfo.packageName = config.mTargetPackageName;
+        appInfo.targetSdkVersion = config.mTargetSdkLevel;
+
+        PlatformCompat platformCompat = null;
+        try {
+            platformCompat = (PlatformCompat) ServiceManager.getServiceOrThrow(
+                    Context.PLATFORM_COMPAT_SERVICE);
+        } catch (ServiceNotFoundException e) {
+            throw new RuntimeException(e);
+        }
+
+        var disabledChanges = platformCompat.getDisabledChanges(appInfo);
+        var loggableChanges = platformCompat.getLoggableChanges(appInfo);
+
+        AppCompatCallbacks.install(disabledChanges, loggableChanges);
+    }
+
     /**
      * De-initialize.
      */
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemServer.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemServer.java
index f198a08..438a2bf 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemServer.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemServer.java
@@ -17,7 +17,9 @@
 package android.platform.test.ravenwood;
 
 import android.content.ClipboardManager;
+import android.content.Context;
 import android.hardware.SerialManager;
+import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.ravenwood.example.BlueManager;
 import android.ravenwood.example.RedManager;
@@ -27,6 +29,8 @@
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.SystemServiceManager;
+import com.android.server.compat.PlatformCompat;
+import com.android.server.compat.PlatformCompatNative;
 import com.android.server.utils.TimingsTraceAndSlog;
 
 import java.util.List;
@@ -65,6 +69,14 @@
     private static SystemServiceManager sServiceManager;
 
     public static void init(RavenwoodConfig config) {
+        // Always start PlatformCompat, regardless of the requested services.
+        // PlatformCompat is not really a SystemService, so it won't receive boot phases / etc.
+        // This initialization code is copied from SystemServer.java.
+        PlatformCompat platformCompat = new PlatformCompat(config.mState.mSystemServerContext);
+        ServiceManager.addService(Context.PLATFORM_COMPAT_SERVICE, platformCompat);
+        ServiceManager.addService(Context.PLATFORM_COMPAT_NATIVE_SERVICE,
+                new PlatformCompatNative(platformCompat));
+
         // Avoid overhead if no services required
         if (config.mServicesRequired.isEmpty()) return;
 
diff --git a/ravenwood/tests/bivalenttest/Android.bp b/ravenwood/tests/bivalenttest/Android.bp
index 4895a1a..40e6672 100644
--- a/ravenwood/tests/bivalenttest/Android.bp
+++ b/ravenwood/tests/bivalenttest/Android.bp
@@ -58,6 +58,9 @@
 java_defaults {
     name: "ravenwood-bivalent-device-defaults",
     defaults: ["ravenwood-bivalent-defaults"],
+
+    target_sdk_version: "34", // For compat-framework tests
+
     // TODO(b/371215487): migrate bivalenttest.ravenizer tests to another architecture
     exclude_srcs: [
         "test/**/ravenizer/*.java",
diff --git a/ravenwood/tests/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/compat/RavenwoodCompatFrameworkTest.kt b/ravenwood/tests/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/compat/RavenwoodCompatFrameworkTest.kt
new file mode 100644
index 0000000..a95760d
--- /dev/null
+++ b/ravenwood/tests/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/compat/RavenwoodCompatFrameworkTest.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+package com.android.ravenwoodtest.bivalenttest.compat
+
+import android.app.compat.CompatChanges
+import android.os.Build
+import android.platform.test.ravenwood.RavenwoodConfig
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.internal.ravenwood.RavenwoodEnvironment.CompatIdsForTest
+import org.junit.Assert
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class RavenwoodCompatFrameworkTest {
+    companion object {
+        @JvmField // Expose as a raw field, not as a property.
+        @RavenwoodConfig.Config
+        val config = RavenwoodConfig.Builder()
+            .setTargetSdkLevel(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+            .build()
+    }
+
+    @Test
+    fun testEnabled() {
+        Assert.assertTrue(CompatChanges.isChangeEnabled(CompatIdsForTest.TEST_COMPAT_ID_1))
+    }
+
+    @Test
+    fun testDisabled() {
+        Assert.assertFalse(CompatChanges.isChangeEnabled(CompatIdsForTest.TEST_COMPAT_ID_2))
+    }
+
+    @Test
+    fun testEnabledAfterSForUApps() {
+        Assert.assertTrue(CompatChanges.isChangeEnabled(CompatIdsForTest.TEST_COMPAT_ID_3))
+    }
+
+    @Test
+    fun testEnabledAfterUForUApps() {
+        Assert.assertFalse(CompatChanges.isChangeEnabled(CompatIdsForTest.TEST_COMPAT_ID_4))
+    }
+}
\ No newline at end of file
diff --git a/ravenwood/texts/ravenwood-annotation-allowed-classes.txt b/ravenwood/texts/ravenwood-annotation-allowed-classes.txt
index 5d24c3a..39e0cf9 100644
--- a/ravenwood/texts/ravenwood-annotation-allowed-classes.txt
+++ b/ravenwood/texts/ravenwood-annotation-allowed-classes.txt
@@ -366,3 +366,9 @@
 
 android.os.IpcDataCache
 android.app.PropertyInvalidatedCache
+
+android.app.compat.*
+com.android.server.compat.*
+com.android.internal.compat.*
+android.app.AppCompatCallbacks
+
diff --git a/ravenwood/texts/ravenwood-services-policies.txt b/ravenwood/texts/ravenwood-services-policies.txt
index cc2fa60..530e5c8 100644
--- a/ravenwood/texts/ravenwood-services-policies.txt
+++ b/ravenwood/texts/ravenwood-services-policies.txt
@@ -1 +1,12 @@
 # Ravenwood "policy" file for services.core.
+
+# Auto-generated from XSD
+class com.android.server.compat.config.Change keepclass
+class com.android.server.compat.config.Config keepclass
+class com.android.server.compat.config.XmlParser keepclass
+class com.android.server.compat.overrides.ChangeOverrides keepclass
+class com.android.server.compat.overrides.OverrideValue keepclass
+class com.android.server.compat.overrides.Overrides keepclass
+class com.android.server.compat.overrides.RawOverrideValue keepclass
+class com.android.server.compat.overrides.XmlParser keepclass
+class com.android.server.compat.overrides.XmlWriter keepclass
\ No newline at end of file
diff --git a/services/core/java/com/android/server/compat/CompatChange.java b/services/core/java/com/android/server/compat/CompatChange.java
index a40dd79..c3d88e3 100644
--- a/services/core/java/com/android/server/compat/CompatChange.java
+++ b/services/core/java/com/android/server/compat/CompatChange.java
@@ -50,6 +50,7 @@
  *
  * <p>Note, this class is not thread safe so callers must ensure thread safety.
  */
[email protected]
 public final class CompatChange extends CompatibilityChangeInfo {
 
     /**
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index 79025d0..e89f43b 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -42,6 +42,7 @@
 import com.android.internal.compat.CompatibilityOverridesToRemoveConfig;
 import com.android.internal.compat.IOverrideValidator;
 import com.android.internal.compat.OverrideAllowedState;
+import com.android.internal.ravenwood.RavenwoodEnvironment;
 import com.android.server.compat.config.Change;
 import com.android.server.compat.config.Config;
 import com.android.server.compat.overrides.ChangeOverrides;
@@ -63,6 +64,7 @@
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Predicate;
 
 import javax.xml.datatype.DatatypeConfigurationException;
 
@@ -72,12 +74,16 @@
  * <p>It stores the default configuration for each change, and any per-package overrides that have
  * been configured.
  */
[email protected]
 final class CompatConfig {
     private static final String TAG = "CompatConfig";
     private static final String APP_COMPAT_DATA_DIR = "/data/misc/appcompat";
     private static final String STATIC_OVERRIDES_PRODUCT_DIR = "/product/etc/appcompat";
     private static final String OVERRIDES_FILE = "compat_framework_overrides.xml";
 
+    private static final String APP_COMPAT_DATA_DIR_RAVENWOOD = "/ravenwood-data/";
+    private static final String OVERRIDES_FILE_RAVENWOOD = "compat-config.xml";
+
     private final ConcurrentHashMap<Long, CompatChange> mChanges = new ConcurrentHashMap<>();
 
     private final OverrideValidatorImpl mOverrideValidator;
@@ -98,19 +104,32 @@
 
     static CompatConfig create(AndroidBuildClassifier androidBuildClassifier, Context context) {
         CompatConfig config = new CompatConfig(androidBuildClassifier, context);
-        config.initConfigFromLib(Environment.buildPath(
+        config.loadConfigFiles();
+        config.initOverrides();
+        config.invalidateCache();
+        return config;
+    }
+
+    @android.ravenwood.annotation.RavenwoodReplace
+    private void loadConfigFiles() {
+        initConfigFromLib(Environment.buildPath(
                 Environment.getRootDirectory(), "etc", "compatconfig"));
-        config.initConfigFromLib(Environment.buildPath(
+        initConfigFromLib(Environment.buildPath(
                 Environment.getRootDirectory(), "system_ext", "etc", "compatconfig"));
 
         List<ApexManager.ActiveApexInfo> apexes = ApexManager.getInstance().getActiveApexInfos();
         for (ApexManager.ActiveApexInfo apex : apexes) {
-            config.initConfigFromLib(Environment.buildPath(
+            initConfigFromLib(Environment.buildPath(
                     apex.apexDirectory, "etc", "compatconfig"));
         }
-        config.initOverrides();
-        config.invalidateCache();
-        return config;
+    }
+
+    @SuppressWarnings("unused")
+    private void loadConfigFiles$ravenwood() {
+        final var configDir = new File(
+                RavenwoodEnvironment.getInstance().getRavenwoodRuntimePath()
+                        + APP_COMPAT_DATA_DIR_RAVENWOOD);
+        initConfigFromLib(configDir, (file) -> file.getName().endsWith(OVERRIDES_FILE_RAVENWOOD));
     }
 
     /**
@@ -678,12 +697,25 @@
         return changeInfos;
     }
 
+    /**
+     * Load all config files in a given directory.
+     */
     void initConfigFromLib(File libraryDir) {
+        initConfigFromLib(libraryDir, (file) -> true);
+    }
+
+    /**
+     * Load config files in a given directory, but only the ones that match {@code includingFilter}.
+     */
+    void initConfigFromLib(File libraryDir, Predicate<File> includingFilter) {
         if (!libraryDir.exists() || !libraryDir.isDirectory()) {
             Slog.d(TAG, "No directory " + libraryDir + ", skipping");
             return;
         }
         for (File f : libraryDir.listFiles()) {
+            if (!includingFilter.test(f)) {
+                continue;
+            }
             Slog.d(TAG, "Found a config file: " + f.getPath());
             //TODO(b/138222363): Handle duplicate ids across config files.
             readConfig(f);
diff --git a/services/core/java/com/android/server/compat/OverrideValidatorImpl.java b/services/core/java/com/android/server/compat/OverrideValidatorImpl.java
index e3b6d03..362c697 100644
--- a/services/core/java/com/android/server/compat/OverrideValidatorImpl.java
+++ b/services/core/java/com/android/server/compat/OverrideValidatorImpl.java
@@ -45,6 +45,7 @@
 /**
  * Implementation of the policy for allowing compat change overrides.
  */
[email protected]
 public class OverrideValidatorImpl extends IOverrideValidator.Stub {
 
     private AndroidBuildClassifier mAndroidBuildClassifier;
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index df49aff..2186e2a 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -36,6 +36,7 @@
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Build;
+import android.os.PermissionEnforcer;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.UserHandle;
@@ -65,6 +66,7 @@
 /**
  * System server internal API for gating and reporting compatibility changes.
  */
[email protected]
 public class PlatformCompat extends IPlatformCompat.Stub {
 
     private static final String TAG = "Compatibility";
@@ -75,6 +77,7 @@
     private final AndroidBuildClassifier mBuildClassifier;
 
     public PlatformCompat(Context context) {
+        super(PermissionEnforcer.fromContext(context));
         mContext = context;
         mChangeReporter = new ChangeReporter(ChangeReporter.SOURCE_SYSTEM_SERVER);
         mBuildClassifier = new AndroidBuildClassifier();
@@ -84,6 +87,7 @@
     @VisibleForTesting
     PlatformCompat(Context context, CompatConfig compatConfig,
             AndroidBuildClassifier buildClassifier) {
+        super(PermissionEnforcer.fromContext(context));
         mContext = context;
         mChangeReporter = new ChangeReporter(ChangeReporter.SOURCE_SYSTEM_SERVER);
         mCompatConfig = compatConfig;
@@ -492,6 +496,7 @@
                 packageName, 0, Process.myUid(), userId);
     }
 
+    @android.ravenwood.annotation.RavenwoodReplace
     private void killPackage(String packageName) {
         int uid = LocalServices.getService(PackageManagerInternal.class).getPackageUid(packageName,
                 0, UserHandle.myUserId());
@@ -505,6 +510,13 @@
         killUid(UserHandle.getAppId(uid));
     }
 
+    @SuppressWarnings("unused")
+    private void killPackage$ravenwood(String packageName) {
+        // TODO Maybe crash if the package is the self.
+        Slog.w(TAG, "killPackage() is ignored on Ravenwood: packageName=" + packageName);
+    }
+
+    @android.ravenwood.annotation.RavenwoodReplace
     private void killUid(int appId) {
         final long identity = Binder.clearCallingIdentity();
         try {
@@ -519,6 +531,12 @@
         }
     }
 
+    @SuppressWarnings("unused")
+    private void killUid$ravenwood(int appId) {
+        // TODO Maybe crash if the UID is the self.
+        Slog.w(TAG, "killUid() is ignored on Ravenwood: appId=" + appId);
+    }
+
     private void checkAllCompatOverridesAreOverridable(Collection<Long> changeIds) {
         for (Long changeId : changeIds) {
             if (isKnownChangeId(changeId) && !mCompatConfig.isOverridable(changeId)) {
diff --git a/services/core/java/com/android/server/compat/PlatformCompatNative.java b/services/core/java/com/android/server/compat/PlatformCompatNative.java
index 5d7af65..7a3feb5 100644
--- a/services/core/java/com/android/server/compat/PlatformCompatNative.java
+++ b/services/core/java/com/android/server/compat/PlatformCompatNative.java
@@ -23,6 +23,7 @@
 /**
  * @hide
  */
[email protected]
 public class PlatformCompatNative extends IPlatformCompatNative.Stub {
     private final PlatformCompat mPlatformCompat;
 
diff --git a/services/core/java/com/android/server/compat/overrides/AppCompatOverridesParser.java b/services/core/java/com/android/server/compat/overrides/AppCompatOverridesParser.java
index e8762a3..0ec6879 100644
--- a/services/core/java/com/android/server/compat/overrides/AppCompatOverridesParser.java
+++ b/services/core/java/com/android/server/compat/overrides/AppCompatOverridesParser.java
@@ -46,6 +46,7 @@
  *
  * @hide
  */
[email protected]
 final class AppCompatOverridesParser {
     /**
      * Flag for specifying all compat change IDs owned by a namespace. See {@link
diff --git a/services/core/java/com/android/server/compat/overrides/AppCompatOverridesService.java b/services/core/java/com/android/server/compat/overrides/AppCompatOverridesService.java
index fe002ce..8637d2d 100644
--- a/services/core/java/com/android/server/compat/overrides/AppCompatOverridesService.java
+++ b/services/core/java/com/android/server/compat/overrides/AppCompatOverridesService.java
@@ -68,6 +68,7 @@
  *
  * @hide
  */
[email protected]
 public final class AppCompatOverridesService {
     private static final String TAG = "AppCompatOverridesService";
 
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index d336c99..c098868 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -149,21 +149,49 @@
     resource_zips: [":FrameworksServicesTests_apks_as_resources"],
 }
 
-android_ravenwood_test {
-    name: "FrameworksServicesTestsRavenwood",
+java_defaults {
+    name: "FrameworksServicesTestsRavenwood-defaults",
     libs: [
         "android.test.mock.stubs.system",
     ],
     static_libs: [
         "androidx.annotation_annotation",
         "androidx.test.rules",
-        "services.core",
         "flag-junit",
     ],
+    auto_gen_config: true,
+}
+
+// Unit tests for UriGrantManager, running on ravenwood.
+// Note UriGrantManager does not support Ravenwood (yet). We're just running the original
+// unit tests as is on Ravenwood. So here, we use the original "services.core", because
+// "services.core.ravenwood" doesn't have the target code.
+// (Compare to FrameworksServicesTestsRavenwood_Compat, which does support Ravenwood.)
+android_ravenwood_test {
+    name: "FrameworksServicesTestsRavenwood_Uri",
+    defaults: ["FrameworksServicesTestsRavenwood-defaults"],
+    team: "trendy_team_ravenwood",
+    static_libs: [
+        "services.core",
+    ],
     srcs: [
         "src/com/android/server/uri/**/*.java",
     ],
-    auto_gen_config: true,
+}
+
+// Unit tests for compat-framework.
+// Compat-framework does support Ravenwood, and it uses the ravenwood anottations,
+// so we link "services.core.ravenwood".
+android_ravenwood_test {
+    name: "FrameworksServicesTestsRavenwood_Compat",
+    defaults: ["FrameworksServicesTestsRavenwood-defaults"],
+    team: "trendy_team_ravenwood",
+    static_libs: [
+        "services.core.ravenwood",
+    ],
+    srcs: [
+        "src/com/android/server/compat/**/*.java",
+    ],
 }
 
 java_library {
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
index 36b163e..3d695a6 100644
--- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
@@ -18,12 +18,12 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertThrows;
 
 import android.app.compat.ChangeIdStateCache;
 import android.app.compat.PackageOverride;
diff --git a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
index 9accd49..79f0673 100644
--- a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
@@ -18,6 +18,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.never;
@@ -25,13 +26,15 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.mockito.internal.verification.VerificationModeFactory.times;
-import static org.testng.Assert.assertThrows;
 
 import android.compat.Compatibility.ChangeConfig;
+import android.content.AttributionSource;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.os.Build;
+import android.os.PermissionEnforcer;
+import android.permission.PermissionCheckerManager;
 
 import androidx.test.runner.AndroidJUnit4;
 
@@ -77,6 +80,22 @@
             .thenReturn(-1);
         when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
             .thenThrow(new PackageManager.NameNotFoundException());
+
+        var allGrantingPermissionEnforcer = new PermissionEnforcer() {
+            @Override
+            protected int checkPermission(String permission, AttributionSource source) {
+                return PermissionCheckerManager.PERMISSION_GRANTED;
+            }
+
+            @Override
+            protected int checkPermission(String permission, int pid, int uid) {
+                return PermissionCheckerManager.PERMISSION_GRANTED;
+            }
+        };
+
+        when(mContext.getSystemService(eq(Context.PERMISSION_ENFORCER_SERVICE)))
+                .thenReturn(allGrantingPermissionEnforcer);
+
         mCompatConfig = new CompatConfig(mBuildClassifier, mContext);
         mPlatformCompat = new PlatformCompat(mContext, mCompatConfig, mBuildClassifier);
         // Assume userdebug/eng non-final build
diff --git a/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java
index 24abc18..f549453 100644
--- a/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java
@@ -61,7 +61,6 @@
 import android.os.UserHandle;
 import android.platform.test.flag.junit.FlagsParameterization;
 import android.platform.test.flag.junit.SetFlagsRule;
-import android.platform.test.ravenwood.RavenwoodRule;
 import android.util.ArraySet;
 
 import org.junit.Before;
@@ -77,9 +76,6 @@
 
 @RunWith(Parameterized.class)
 public class UriGrantsManagerServiceTest {
-    @Rule
-    public final RavenwoodRule mRavenwood = new RavenwoodRule();
-
     /**
      * Why this class needs to test all combinations of
      * {@link android.security.Flags#FLAG_CONTENT_URI_PERMISSION_APIS}:
diff --git a/services/tests/servicestests/src/com/android/server/uri/UriPermissionTest.java b/services/tests/servicestests/src/com/android/server/uri/UriPermissionTest.java
index 611c514..fe66f73 100644
--- a/services/tests/servicestests/src/com/android/server/uri/UriPermissionTest.java
+++ b/services/tests/servicestests/src/com/android/server/uri/UriPermissionTest.java
@@ -37,18 +37,13 @@
 import static org.junit.Assert.assertTrue;
 
 import android.os.SystemClock;
-import android.platform.test.ravenwood.RavenwoodRule;
 
 import org.junit.Before;
-import org.junit.Rule;
 import org.junit.Test;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
 public class UriPermissionTest {
-    @Rule
-    public final RavenwoodRule mRavenwood = new RavenwoodRule();
-
     @Mock
     private UriGrantsManagerInternal mService;