Merge "nfc(api): Add OEM extension surface" into main
diff --git a/api/coverage/tools/ExtractFlaggedApis.kt b/api/coverage/tools/ExtractFlaggedApis.kt
index caa1929..d5adfd0 100644
--- a/api/coverage/tools/ExtractFlaggedApis.kt
+++ b/api/coverage/tools/ExtractFlaggedApis.kt
@@ -16,51 +16,69 @@
 
 package android.platform.coverage
 
+import com.android.tools.metalava.model.ClassItem
+import com.android.tools.metalava.model.MethodItem
 import com.android.tools.metalava.model.text.ApiFile
 import java.io.File
 import java.io.FileWriter
 
 /** Usage: extract-flagged-apis <api text file> <output .pb file> */
 fun main(args: Array<String>) {
-    var cb = ApiFile.parseApi(listOf(File(args[0])))
-    var builder = FlagApiMap.newBuilder()
+    val cb = ApiFile.parseApi(listOf(File(args[0])))
+    val builder = FlagApiMap.newBuilder()
     for (pkg in cb.getPackages().packages) {
-        var packageName = pkg.qualifiedName()
+        val packageName = pkg.qualifiedName()
         pkg.allClasses()
             .filter { it.methods().size > 0 }
             .forEach {
-                for (method in it.methods()) {
-                    val flagValue =
-                        method.modifiers
-                            .findAnnotation("android.annotation.FlaggedApi")
-                            ?.findAttribute("value")
-                            ?.value
-                            ?.value()
-                    if (flagValue != null && flagValue is String) {
-                        var api =
-                            JavaMethod.newBuilder()
-                                .setPackageName(packageName)
-                                .setClassName(it.fullName())
-                                .setMethodName(method.name())
-                        for (param in method.parameters()) {
-                            api.addParameters(param.type().toTypeString())
-                        }
-                        if (builder.containsFlagToApi(flagValue)) {
-                            var updatedApis =
-                                builder
-                                    .getFlagToApiOrThrow(flagValue)
-                                    .toBuilder()
-                                    .addJavaMethods(api)
-                                    .build()
-                            builder.putFlagToApi(flagValue, updatedApis)
-                        } else {
-                            var apis = FlaggedApis.newBuilder().addJavaMethods(api).build()
-                            builder.putFlagToApi(flagValue, apis)
-                        }
-                    }
-                }
+                extractFlaggedApisFromClass(it, it.methods(), packageName, builder)
+                extractFlaggedApisFromClass(it, it.constructors(), packageName, builder)
             }
     }
     val flagApiMap = builder.build()
     FileWriter(args[1]).use { it.write(flagApiMap.toString()) }
 }
+
+fun extractFlaggedApisFromClass(
+    classItem: ClassItem,
+    methods: List<MethodItem>,
+    packageName: String,
+    builder: FlagApiMap.Builder
+) {
+    val classFlag =
+        classItem.modifiers
+            .findAnnotation("android.annotation.FlaggedApi")
+            ?.findAttribute("value")
+            ?.value
+            ?.value() as? String
+    for (method in methods) {
+        val methodFlag =
+            method.modifiers
+                .findAnnotation("android.annotation.FlaggedApi")
+                ?.findAttribute("value")
+                ?.value
+                ?.value() as? String
+                ?: classFlag
+        val api =
+            JavaMethod.newBuilder()
+                .setPackageName(packageName)
+                .setClassName(classItem.fullName())
+                .setMethodName(method.name())
+        for (param in method.parameters()) {
+            api.addParameters(param.type().toTypeString())
+        }
+        if (methodFlag != null) {
+            addFlaggedApi(builder, api, methodFlag)
+        }
+    }
+}
+
+fun addFlaggedApi(builder: FlagApiMap.Builder, api: JavaMethod.Builder, flag: String) {
+    if (builder.containsFlagToApi(flag)) {
+        val updatedApis = builder.getFlagToApiOrThrow(flag).toBuilder().addJavaMethods(api).build()
+        builder.putFlagToApi(flag, updatedApis)
+    } else {
+        val apis = FlaggedApis.newBuilder().addJavaMethods(api).build()
+        builder.putFlagToApi(flag, apis)
+    }
+}
diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS
index ff1ea4f..712f3e5 100644
--- a/core/java/android/app/OWNERS
+++ b/core/java/android/app/OWNERS
@@ -42,6 +42,7 @@
 # ActivityThread
 per-file ActivityThread.java = file:/services/core/java/com/android/server/am/OWNERS
 per-file ActivityThread.java = file:/services/core/java/com/android/server/wm/OWNERS
+per-file ActivityThread.java = file:RESOURCES_OWNERS
 
 # Alarm
 per-file *Alarm* = file:/apex/jobscheduler/OWNERS
diff --git a/core/java/android/app/RESOURCES_OWNERS b/core/java/android/app/RESOURCES_OWNERS
index 5582803..fe37c0c 100644
--- a/core/java/android/app/RESOURCES_OWNERS
+++ b/core/java/android/app/RESOURCES_OWNERS
@@ -1,3 +1,5 @@
-rtmitchell@google.com
-toddke@google.com
+zyy@google.com
+jakmcbane@google.com
+branliu@google.com
+markpun@google.com
 patb@google.com
diff --git a/core/java/android/appwidget/OWNERS b/core/java/android/appwidget/OWNERS
index 554b0de..1910833 100644
--- a/core/java/android/appwidget/OWNERS
+++ b/core/java/android/appwidget/OWNERS
@@ -1,4 +1,5 @@
-pinyaoting@google.com
+fengjial@google.com
 sihua@google.com
+pinyaoting@google.com
 suprabh@google.com
 sunnygoyal@google.com
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 8a55616..445880c 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3188,6 +3188,16 @@
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: This device is capable of launching apps in automotive display
+     * compatibility mode.
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_CAR_DISPLAY_COMPATIBILITY =
+            "android.software.car.display_compatibility";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature(String, int)}: If this feature is supported, the device supports
      * {@link android.security.identity.IdentityCredentialStore} implemented in secure hardware
      * at the given feature version.
diff --git a/core/java/android/net/IVpnManager.aidl b/core/java/android/net/IVpnManager.aidl
index f302378..5149967 100644
--- a/core/java/android/net/IVpnManager.aidl
+++ b/core/java/android/net/IVpnManager.aidl
@@ -60,6 +60,12 @@
     LegacyVpnInfo getLegacyVpnInfo(int userId);
     boolean updateLockdownVpn();
 
+    /** Profile store APIs */
+    byte[] getFromVpnProfileStore(String name);
+    boolean putIntoVpnProfileStore(String name, in byte[] blob);
+    boolean removeFromVpnProfileStore(String name);
+    String[] listFromVpnProfileStore(String prefix);
+
     /** General system APIs */
     VpnConfig getVpnConfig(int userId);
     void factoryReset();
diff --git a/core/java/android/net/VpnManager.java b/core/java/android/net/VpnManager.java
index ff47f3f..c50bc56 100644
--- a/core/java/android/net/VpnManager.java
+++ b/core/java/android/net/VpnManager.java
@@ -717,4 +717,81 @@
             throw e.rethrowFromSystemServer();
         }
     }
+
+    /**
+     * Get the vpn profile owned by the calling uid with the given name from the vpn database.
+     *
+     * <p>Note this method should not be used for platform VPN profiles. </p>
+     *
+     * @param name The name of the profile to retrieve.
+     * @return the unstructured blob for the matching vpn profile.
+     * Returns null if no profile with a matching name was found.
+     * @hide
+     */
+    @Nullable
+    public byte[] getFromVpnProfileStore(@NonNull String name) {
+        try {
+            return mService.getFromVpnProfileStore(name);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Put the given vpn profile owned by the calling uid with the given name into the vpn database.
+     * Existing profiles with the same name will be replaced.
+     *
+     * <p>Note this method should not be used for platform VPN profiles.
+     * To update a platform VPN, use provisionVpnProfile() instead. </p>
+     *
+     * @param name The name of the profile to put.
+     * @param blob The profile.
+     * @return true if the profile was successfully added. False otherwise.
+     * @hide
+     */
+    public boolean putIntoVpnProfileStore(@NonNull String name, @NonNull byte[] blob) {
+        try {
+            return mService.putIntoVpnProfileStore(name, blob);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Removes the vpn profile owned by the calling uid with the given name from the vpn database.
+     *
+     * <p>Note this method should not be used for platform VPN profiles.
+     * To remove a platform VPN, use deleteVpnProfile() instead.</p>
+     *
+     * @param name The name of the profile to be removed.
+     * @return true if a profile was removed. False if no profile with a matching name was found.
+     * @hide
+     */
+    public boolean removeFromVpnProfileStore(@NonNull String name) {
+        try {
+            return mService.removeFromVpnProfileStore(name);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Returns a list of the name suffixes of the vpn profiles owned by the calling uid in the vpn
+     * database matching the given prefix, sorted in ascending order.
+     *
+     * <p>Note this method should not be used for platform VPN profiles. </p>
+     *
+     * @param prefix The prefix to match.
+     * @return an array of strings representing the name suffixes stored in the profile database
+     * matching the given prefix. The return value may be empty but never null.
+     * @hide
+     */
+    @NonNull
+    public String[] listFromVpnProfileStore(@NonNull String prefix) {
+        try {
+            return mService.listFromVpnProfileStore(prefix);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 04d6f61..f785cca 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -210,6 +210,7 @@
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
         public boolean hasSwappedOutPss;
 
+        // LINT.IfChange
         /** @hide */
         public static final int HEAP_UNKNOWN = 0;
         /** @hide */
@@ -311,6 +312,7 @@
         public static final int OTHER_ART_APP = 30;
         /** @hide */
         public static final int OTHER_ART_BOOT = 31;
+        // LINT.ThenChange(/system/memory/libmeminfo/include/meminfo/androidprocheaps.h)
         /** @hide */
         public static final int OTHER_DVK_STAT_ART_START = OTHER_ART_APP - NUM_OTHER_STATS;
         /** @hide */
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 8e860c3..0c70750 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -572,6 +572,11 @@
             }
             res.mReadWriteHelper = ReadWriteHelper.DEFAULT;
         }
+
+        if (res.mNativePtr == 0) {
+            Log.e(TAG, "Obtained Parcel object has null native pointer. Invalid state.");
+        }
+
         return res;
     }
 
diff --git a/core/java/android/service/voice/OWNERS b/core/java/android/service/voice/OWNERS
index 763c79e..5f9f6bd 100644
--- a/core/java/android/service/voice/OWNERS
+++ b/core/java/android/service/voice/OWNERS
@@ -3,5 +3,4 @@
 include /core/java/android/app/assist/OWNERS
 
 # The owner here should not be assist owner
-liangyuchen@google.com
 adudani@google.com
diff --git a/core/java/com/android/internal/net/ConnectivityBlobStore.java b/core/java/com/android/internal/net/ConnectivityBlobStore.java
index 1b18485..f8eb5be 100644
--- a/core/java/com/android/internal/net/ConnectivityBlobStore.java
+++ b/core/java/com/android/internal/net/ConnectivityBlobStore.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.content.ContentValues;
 import android.database.Cursor;
+import android.database.DatabaseUtils;
 import android.database.SQLException;
 import android.database.sqlite.SQLiteDatabase;
 import android.os.Binder;
@@ -153,8 +154,11 @@
         final List<String> names = new ArrayList<String>();
         try (Cursor cursor = mDb.query(TABLENAME,
                 new String[] {"name"} /* columns */,
-                "owner=? AND name LIKE ?" /* selection */,
-                new String[] {Integer.toString(ownerUid), prefix + "%"} /* selectionArgs */,
+                "owner=? AND name LIKE ? ESCAPE '\\'" /* selection */,
+                new String[] {
+                        Integer.toString(ownerUid),
+                        DatabaseUtils.escapeForLike(prefix) + "%"
+                } /* selectionArgs */,
                 null /* groupBy */,
                 null /* having */,
                 "name ASC" /* orderBy */)) {
diff --git a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
index dbe4fba..9fc7ddb 100644
--- a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
@@ -415,8 +415,10 @@
      */
     private ParseResult<ParsingPackage> parseMonolithicPackage(ParseInput input, File apkFile,
             int flags) {
+        // The signature parsing will be done later in method parseBaseApk.
+        int liteParseFlags = flags & ~PARSE_COLLECT_CERTIFICATES;
         final ParseResult<PackageLite> liteResult =
-                ApkLiteParseUtils.parseMonolithicPackageLite(input, apkFile, flags);
+                ApkLiteParseUtils.parseMonolithicPackageLite(input, apkFile, liteParseFlags);
         if (liteResult.isError()) {
             return input.error(liteResult);
         }
diff --git a/core/jni/OWNERS b/core/jni/OWNERS
index 3aca751..d687ef3 100644
--- a/core/jni/OWNERS
+++ b/core/jni/OWNERS
@@ -1,6 +1,5 @@
 # Camera
-per-file *Camera*,*camera* = cychen@google.com, epeev@google.com, etalvala@google.com
-per-file *Camera*,*camera* = shuzhenwang@google.com, yinchiayeh@google.com, zhijunhe@google.com
+per-file *Camera*,*camera* = file:platform/frameworks/av:/camera/OWNERS
 
 # Connectivity
 per-file android_net_* = codewiz@google.com, jchalard@google.com, lorenzo@google.com, reminv@google.com, satk@google.com
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index a98f947..9593fe58 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -46,6 +46,7 @@
 #include "jni.h"
 #include <dmabufinfo/dmabuf_sysfs_stats.h>
 #include <dmabufinfo/dmabufinfo.h>
+#include <meminfo/androidprocheaps.h>
 #include <meminfo/procmeminfo.h>
 #include <meminfo/sysmeminfo.h>
 #include <memtrack/memtrack.h>
@@ -57,56 +58,7 @@
 namespace android
 {
 
-enum {
-    HEAP_UNKNOWN,
-    HEAP_DALVIK,
-    HEAP_NATIVE,
-
-    HEAP_DALVIK_OTHER,
-    HEAP_STACK,
-    HEAP_CURSOR,
-    HEAP_ASHMEM,
-    HEAP_GL_DEV,
-    HEAP_UNKNOWN_DEV,
-    HEAP_SO,
-    HEAP_JAR,
-    HEAP_APK,
-    HEAP_TTF,
-    HEAP_DEX,
-    HEAP_OAT,
-    HEAP_ART,
-    HEAP_UNKNOWN_MAP,
-    HEAP_GRAPHICS,
-    HEAP_GL,
-    HEAP_OTHER_MEMTRACK,
-
-    // Dalvik extra sections (heap).
-    HEAP_DALVIK_NORMAL,
-    HEAP_DALVIK_LARGE,
-    HEAP_DALVIK_ZYGOTE,
-    HEAP_DALVIK_NON_MOVING,
-
-    // Dalvik other extra sections.
-    HEAP_DALVIK_OTHER_LINEARALLOC,
-    HEAP_DALVIK_OTHER_ACCOUNTING,
-    HEAP_DALVIK_OTHER_ZYGOTE_CODE_CACHE,
-    HEAP_DALVIK_OTHER_APP_CODE_CACHE,
-    HEAP_DALVIK_OTHER_COMPILER_METADATA,
-    HEAP_DALVIK_OTHER_INDIRECT_REFERENCE_TABLE,
-
-    // Boot vdex / app dex / app vdex
-    HEAP_DEX_BOOT_VDEX,
-    HEAP_DEX_APP_DEX,
-    HEAP_DEX_APP_VDEX,
-
-    // App art, boot art.
-    HEAP_ART_APP,
-    HEAP_ART_BOOT,
-
-    _NUM_HEAP,
-    _NUM_EXCLUSIVE_HEAP = HEAP_OTHER_MEMTRACK+1,
-    _NUM_CORE_HEAP = HEAP_NATIVE+1
-};
+using namespace android::meminfo;
 
 struct stat_fields {
     jfieldID pss_field;
@@ -146,18 +98,6 @@
 static jfieldID otherStats_field;
 static jfieldID hasSwappedOutPss_field;
 
-struct stats_t {
-    int pss;
-    int swappablePss;
-    int rss;
-    int privateDirty;
-    int sharedDirty;
-    int privateClean;
-    int sharedClean;
-    int swappedOut;
-    int swappedOutPss;
-};
-
 #define BINDER_STATS "/proc/binder/stats"
 
 static jlong android_os_Debug_getNativeHeapSize(JNIEnv *env, jobject clazz)
@@ -240,190 +180,14 @@
     return err;
 }
 
-static bool load_maps(int pid, stats_t* stats, bool* foundSwapPss)
-{
-    *foundSwapPss = false;
-    uint64_t prev_end = 0;
-    int prev_heap = HEAP_UNKNOWN;
-
-    std::string smaps_path = base::StringPrintf("/proc/%d/smaps", pid);
-    auto vma_scan = [&](const meminfo::Vma& vma) {
-        int which_heap = HEAP_UNKNOWN;
-        int sub_heap = HEAP_UNKNOWN;
-        bool is_swappable = false;
-        std::string name;
-        if (base::EndsWith(vma.name, " (deleted)")) {
-            name = vma.name.substr(0, vma.name.size() - strlen(" (deleted)"));
-        } else {
-            name = vma.name;
-        }
-
-        uint32_t namesz = name.size();
-        if (base::StartsWith(name, "[heap]")) {
-            which_heap = HEAP_NATIVE;
-        } else if (base::StartsWith(name, "[anon:libc_malloc]")) {
-            which_heap = HEAP_NATIVE;
-        } else if (base::StartsWith(name, "[anon:scudo:")) {
-            which_heap = HEAP_NATIVE;
-        } else if (base::StartsWith(name, "[anon:GWP-ASan")) {
-            which_heap = HEAP_NATIVE;
-        } else if (base::StartsWith(name, "[stack")) {
-            which_heap = HEAP_STACK;
-        } else if (base::StartsWith(name, "[anon:stack_and_tls:")) {
-            which_heap = HEAP_STACK;
-        } else if (base::EndsWith(name, ".so")) {
-            which_heap = HEAP_SO;
-            is_swappable = true;
-        } else if (base::EndsWith(name, ".jar")) {
-            which_heap = HEAP_JAR;
-            is_swappable = true;
-        } else if (base::EndsWith(name, ".apk")) {
-            which_heap = HEAP_APK;
-            is_swappable = true;
-        } else if (base::EndsWith(name, ".ttf")) {
-            which_heap = HEAP_TTF;
-            is_swappable = true;
-        } else if ((base::EndsWith(name, ".odex")) ||
-                (namesz > 4 && strstr(name.c_str(), ".dex") != nullptr)) {
-            which_heap = HEAP_DEX;
-            sub_heap = HEAP_DEX_APP_DEX;
-            is_swappable = true;
-        } else if (base::EndsWith(name, ".vdex")) {
-            which_heap = HEAP_DEX;
-            // Handle system@framework@boot and system/framework/boot|apex
-            if ((strstr(name.c_str(), "@boot") != nullptr) ||
-                    (strstr(name.c_str(), "/boot") != nullptr) ||
-                    (strstr(name.c_str(), "/apex") != nullptr)) {
-                sub_heap = HEAP_DEX_BOOT_VDEX;
-            } else {
-                sub_heap = HEAP_DEX_APP_VDEX;
-            }
-            is_swappable = true;
-        } else if (base::EndsWith(name, ".oat")) {
-            which_heap = HEAP_OAT;
-            is_swappable = true;
-        } else if (base::EndsWith(name, ".art") || base::EndsWith(name, ".art]")) {
-            which_heap = HEAP_ART;
-            // Handle system@framework@boot* and system/framework/boot|apex*
-            if ((strstr(name.c_str(), "@boot") != nullptr) ||
-                    (strstr(name.c_str(), "/boot") != nullptr) ||
-                    (strstr(name.c_str(), "/apex") != nullptr)) {
-                sub_heap = HEAP_ART_BOOT;
-            } else {
-                sub_heap = HEAP_ART_APP;
-            }
-            is_swappable = true;
-        } else if (base::StartsWith(name, "/dev/")) {
-            which_heap = HEAP_UNKNOWN_DEV;
-            if (base::StartsWith(name, "/dev/kgsl-3d0")) {
-                which_heap = HEAP_GL_DEV;
-            } else if (base::StartsWith(name, "/dev/ashmem/CursorWindow")) {
-                which_heap = HEAP_CURSOR;
-            } else if (base::StartsWith(name, "/dev/ashmem/jit-zygote-cache")) {
-                which_heap = HEAP_DALVIK_OTHER;
-                sub_heap = HEAP_DALVIK_OTHER_ZYGOTE_CODE_CACHE;
-            } else if (base::StartsWith(name, "/dev/ashmem")) {
-                which_heap = HEAP_ASHMEM;
-            }
-        } else if (base::StartsWith(name, "/memfd:jit-cache")) {
-          which_heap = HEAP_DALVIK_OTHER;
-          sub_heap = HEAP_DALVIK_OTHER_APP_CODE_CACHE;
-        } else if (base::StartsWith(name, "/memfd:jit-zygote-cache")) {
-          which_heap = HEAP_DALVIK_OTHER;
-          sub_heap = HEAP_DALVIK_OTHER_ZYGOTE_CODE_CACHE;
-        } else if (base::StartsWith(name, "[anon:")) {
-            which_heap = HEAP_UNKNOWN;
-            if (base::StartsWith(name, "[anon:dalvik-")) {
-                which_heap = HEAP_DALVIK_OTHER;
-                if (base::StartsWith(name, "[anon:dalvik-LinearAlloc")) {
-                    sub_heap = HEAP_DALVIK_OTHER_LINEARALLOC;
-                } else if (base::StartsWith(name, "[anon:dalvik-alloc space") ||
-                        base::StartsWith(name, "[anon:dalvik-main space")) {
-                    // This is the regular Dalvik heap.
-                    which_heap = HEAP_DALVIK;
-                    sub_heap = HEAP_DALVIK_NORMAL;
-                } else if (base::StartsWith(name,
-                            "[anon:dalvik-large object space") ||
-                        base::StartsWith(
-                            name, "[anon:dalvik-free list large object space")) {
-                    which_heap = HEAP_DALVIK;
-                    sub_heap = HEAP_DALVIK_LARGE;
-                } else if (base::StartsWith(name, "[anon:dalvik-non moving space")) {
-                    which_heap = HEAP_DALVIK;
-                    sub_heap = HEAP_DALVIK_NON_MOVING;
-                } else if (base::StartsWith(name, "[anon:dalvik-zygote space")) {
-                    which_heap = HEAP_DALVIK;
-                    sub_heap = HEAP_DALVIK_ZYGOTE;
-                } else if (base::StartsWith(name, "[anon:dalvik-indirect ref")) {
-                    sub_heap = HEAP_DALVIK_OTHER_INDIRECT_REFERENCE_TABLE;
-                } else if (base::StartsWith(name, "[anon:dalvik-jit-code-cache") ||
-                        base::StartsWith(name, "[anon:dalvik-data-code-cache")) {
-                    sub_heap = HEAP_DALVIK_OTHER_APP_CODE_CACHE;
-                } else if (base::StartsWith(name, "[anon:dalvik-CompilerMetadata")) {
-                    sub_heap = HEAP_DALVIK_OTHER_COMPILER_METADATA;
-                } else {
-                    sub_heap = HEAP_DALVIK_OTHER_ACCOUNTING;  // Default to accounting.
-                }
-            }
-        } else if (namesz > 0) {
-            which_heap = HEAP_UNKNOWN_MAP;
-        } else if (vma.start == prev_end && prev_heap == HEAP_SO) {
-            // bss section of a shared library
-            which_heap = HEAP_SO;
-        }
-
-        prev_end = vma.end;
-        prev_heap = which_heap;
-
-        const meminfo::MemUsage& usage = vma.usage;
-        if (usage.swap_pss > 0 && *foundSwapPss != true) {
-            *foundSwapPss = true;
-        }
-
-        uint64_t swapable_pss = 0;
-        if (is_swappable && (usage.pss > 0)) {
-            float sharing_proportion = 0.0;
-            if ((usage.shared_clean > 0) || (usage.shared_dirty > 0)) {
-                sharing_proportion = (usage.pss - usage.uss) / (usage.shared_clean + usage.shared_dirty);
-            }
-            swapable_pss = (sharing_proportion * usage.shared_clean) + usage.private_clean;
-        }
-
-        stats[which_heap].pss += usage.pss;
-        stats[which_heap].swappablePss += swapable_pss;
-        stats[which_heap].rss += usage.rss;
-        stats[which_heap].privateDirty += usage.private_dirty;
-        stats[which_heap].sharedDirty += usage.shared_dirty;
-        stats[which_heap].privateClean += usage.private_clean;
-        stats[which_heap].sharedClean += usage.shared_clean;
-        stats[which_heap].swappedOut += usage.swap;
-        stats[which_heap].swappedOutPss += usage.swap_pss;
-        if (which_heap == HEAP_DALVIK || which_heap == HEAP_DALVIK_OTHER ||
-                which_heap == HEAP_DEX || which_heap == HEAP_ART) {
-            stats[sub_heap].pss += usage.pss;
-            stats[sub_heap].swappablePss += swapable_pss;
-            stats[sub_heap].rss += usage.rss;
-            stats[sub_heap].privateDirty += usage.private_dirty;
-            stats[sub_heap].sharedDirty += usage.shared_dirty;
-            stats[sub_heap].privateClean += usage.private_clean;
-            stats[sub_heap].sharedClean += usage.shared_clean;
-            stats[sub_heap].swappedOut += usage.swap;
-            stats[sub_heap].swappedOutPss += usage.swap_pss;
-        }
-        return true;
-    };
-
-    return meminfo::ForEachVmaFromFile(smaps_path, vma_scan);
-}
-
 static jboolean android_os_Debug_getDirtyPagesPid(JNIEnv *env, jobject clazz,
         jint pid, jobject object)
 {
     bool foundSwapPss;
-    stats_t stats[_NUM_HEAP];
+    AndroidHeapStats stats[_NUM_HEAP];
     memset(&stats, 0, sizeof(stats));
 
-    if (!load_maps(pid, stats, &foundSwapPss)) {
+    if (!ExtractAndroidHeapStats(pid, stats, &foundSwapPss)) {
         return JNI_FALSE;
     }
 
diff --git a/core/tests/coretests/src/com/android/internal/net/ConnectivityBlobStoreTest.java b/core/tests/coretests/src/com/android/internal/net/ConnectivityBlobStoreTest.java
index 68545cf..ad4ccc9 100644
--- a/core/tests/coretests/src/com/android/internal/net/ConnectivityBlobStoreTest.java
+++ b/core/tests/coretests/src/com/android/internal/net/ConnectivityBlobStoreTest.java
@@ -153,4 +153,41 @@
         final String[] actual = connectivityBlobStore.list(TEST_NAME /* prefix */);
         assertArrayEquals(expected, actual);
     }
+
+    @Test
+    public void testList_underscoreInPrefix() throws Exception {
+        final String prefix = TEST_NAME + "_";
+        final String[] unsortedNames = new String[] {
+                prefix + "000",
+                TEST_NAME + "123",
+        };
+        // The '_' in the prefix should not be treated as a wildcard so the only match is "000".
+        final String[] expected = new String[] {"000"};
+        final ConnectivityBlobStore connectivityBlobStore = createConnectivityBlobStore();
+
+        for (int i = 0; i < unsortedNames.length; i++) {
+            assertTrue(connectivityBlobStore.put(unsortedNames[i], TEST_BLOB));
+        }
+        final String[] actual = connectivityBlobStore.list(prefix);
+        assertArrayEquals(expected, actual);
+    }
+
+    @Test
+    public void testList_percentInPrefix() throws Exception {
+        final String prefix = "%" + TEST_NAME + "%";
+        final String[] unsortedNames = new String[] {
+                TEST_NAME + "12345",
+                prefix + "0",
+                "abc" + TEST_NAME + "987",
+        };
+        // The '%' in the prefix should not be treated as a wildcard so the only match is "0".
+        final String[] expected = new String[] {"0"};
+        final ConnectivityBlobStore connectivityBlobStore = createConnectivityBlobStore();
+
+        for (int i = 0; i < unsortedNames.length; i++) {
+            assertTrue(connectivityBlobStore.put(unsortedNames[i], TEST_BLOB));
+        }
+        final String[] actual = connectivityBlobStore.list(prefix);
+        assertArrayEquals(expected, actual);
+    }
 }
diff --git a/media/OWNERS b/media/OWNERS
index 2e9276d..1e5a458 100644
--- a/media/OWNERS
+++ b/media/OWNERS
@@ -4,6 +4,7 @@
 essick@google.com
 etalvala@google.com
 hunga@google.com
+jchowdhary@google.com
 jmtrivi@google.com
 jsharkey@android.com
 lajos@google.com
diff --git a/media/java/android/media/AudioDescriptor.java b/media/java/android/media/AudioDescriptor.java
index 85a653c..b5cae2c 100644
--- a/media/java/android/media/AudioDescriptor.java
+++ b/media/java/android/media/AudioDescriptor.java
@@ -99,7 +99,7 @@
      * When encapsulation is required, only playback with {@link android.media.AudioTrack} API is
      * supported. But playback with {@link android.media.MediaPlayer} is not.
      * When an encapsulation type is required, the {@link AudioFormat} encoding selected when
-     * creating the {@link AudioTrack} must match the encapsulation type, e.g
+     * creating the {@link AudioTrack} must match the encapsulation type, e.g.
      * AudioFormat#ENCODING_IEC61937 for AudioProfile.AUDIO_ENCAPSULATION_TYPE_IEC61937.
      *
      * @return an integer representing the encapsulation type
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 3dfd572..cff5f20 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -3460,7 +3460,7 @@
 
     /* modes for setMode/getMode/setRoute/getRoute */
     /**
-     * Audio harware modes.
+     * Audio hardware modes.
      */
     /**
      * Invalid audio mode.
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 45bf5c4..2018a39 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -65,6 +65,7 @@
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.Supplier;
 
 /**
  MediaCodec class can be used to access low-level media codecs, i.e. encoder/decoder components.
@@ -2014,6 +2015,23 @@
         }
     }
 
+    // HACKY(b/325389296): aconfig flag accessors may not work in all contexts where MediaCodec API
+    // is used, so allow accessors to fail. In those contexts use a default value, normally false.
+
+    /* package private */
+    static boolean GetFlag(Supplier<Boolean> flagValueSupplier) {
+        return GetFlag(flagValueSupplier, false /* defaultValue */);
+    }
+
+    /* package private */
+    static boolean GetFlag(Supplier<Boolean> flagValueSupplier, boolean defaultValue) {
+        try {
+            return flagValueSupplier.get();
+        } catch (java.lang.RuntimeException e) {
+            return defaultValue;
+        }
+    }
+
     private boolean mHasSurface = false;
 
     /**
@@ -2346,7 +2364,7 @@
         }
 
         // at the moment no codecs support detachable surface
-        if (android.media.codec.Flags.nullOutputSurface()) {
+        if (GetFlag(() -> android.media.codec.Flags.nullOutputSurface())) {
             // Detached surface flag is only meaningful if surface is null. Otherwise, it is
             // ignored.
             if (surface == null && (flags & CONFIGURE_FLAG_DETACHED_SURFACE) != 0) {
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index abad460..8ff4305 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -23,6 +23,7 @@
 import static android.media.codec.Flags.FLAG_IN_PROCESS_SW_AUDIO_CODEC;
 import static android.media.codec.Flags.FLAG_NULL_OUTPUT_SURFACE;
 import static android.media.codec.Flags.FLAG_REGION_OF_INTEREST;
+import static android.media.MediaCodec.GetFlag;
 
 import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
@@ -827,10 +828,10 @@
                 features.add(new Feature(FEATURE_MultipleFrames,   (1 << 5), false));
                 features.add(new Feature(FEATURE_DynamicTimestamp, (1 << 6), false));
                 features.add(new Feature(FEATURE_LowLatency,       (1 << 7), true));
-                if (android.media.codec.Flags.dynamicColorAspects()) {
+                if (GetFlag(() -> android.media.codec.Flags.dynamicColorAspects())) {
                     features.add(new Feature(FEATURE_DynamicColorAspects, (1 << 8), true));
                 }
-                if (android.media.codec.Flags.nullOutputSurface()) {
+                if (GetFlag(() -> android.media.codec.Flags.nullOutputSurface())) {
                     features.add(new Feature(FEATURE_DetachedSurface,     (1 << 9), true));
                 }
 
@@ -851,10 +852,10 @@
                 features.add(new Feature(FEATURE_QpBounds, (1 << 3), false));
                 features.add(new Feature(FEATURE_EncodingStatistics, (1 << 4), false));
                 features.add(new Feature(FEATURE_HdrEditing, (1 << 5), false));
-                if (android.media.codec.Flags.hlgEditing()) {
+                if (GetFlag(() -> android.media.codec.Flags.hlgEditing())) {
                     features.add(new Feature(FEATURE_HlgEditing, (1 << 6), true));
                 }
-                if (android.media.codec.Flags.regionOfInterest()) {
+                if (GetFlag(() -> android.media.codec.Flags.regionOfInterest())) {
                     features.add(new Feature(FEATURE_Roi, (1 << 7), true));
                 }
 
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index f8e207c..d50b596 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -229,7 +229,6 @@
         extra_check_modules: ["SystemUILintChecker"],
         warning_checks: ["MissingApacheLicenseDetector"],
     },
-    skip_jarjar_repackage: true,
 }
 
 filegroup {
@@ -329,13 +328,12 @@
         "WindowManager-Shell",
         "LowLightDreamLib",
         "motion_tool_lib",
-        "androidx.core_core-animation-testing-nodeps",
+        "androidx.core_core-animation-testing",
         "androidx.compose.ui_ui",
         "flag-junit",
         "platform-test-annotations",
         "notification_flags_lib",
     ],
-    skip_jarjar_repackage: true,
 }
 
 android_library {
@@ -385,7 +383,6 @@
         test: true,
         extra_check_modules: ["SystemUILintChecker"],
     },
-    skip_jarjar_repackage: true,
 }
 
 android_app {
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java
index 085fc29..b05d2ae 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java
+++ b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java
@@ -387,6 +387,10 @@
         unregisterReceiver(mToggleMenuReceiver);
         mPrefs.unregisterOnSharedPreferenceChangeListener(mSharedPreferenceChangeListener);
         sInitialized = false;
+        if (mA11yMenuLayout != null) {
+            mA11yMenuLayout.clearLayout();
+            mA11yMenuLayout = null;
+        }
         return super.onUnbind(intent);
     }
 
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuOverlayLayout.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuOverlayLayout.java
index edd6a48..1be04f8 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuOverlayLayout.java
+++ b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuOverlayLayout.java
@@ -151,6 +151,14 @@
         return mLayout;
     }
 
+    public void clearLayout() {
+        if (mLayout != null) {
+            mWindowManager.removeView(mLayout);
+            mLayout.setOnTouchListener(null);
+            mLayout = null;
+        }
+    }
+
     /** Updates view layout with new layout parameters only. */
     public void updateViewLayout() {
         if (mLayout == null || mLayoutParameter == null) {
diff --git a/packages/SystemUI/animation/Android.bp b/packages/SystemUI/animation/Android.bp
index b900ea0..e945f1e 100644
--- a/packages/SystemUI/animation/Android.bp
+++ b/packages/SystemUI/animation/Android.bp
@@ -41,7 +41,7 @@
     ],
 
     static_libs: [
-        "androidx.core_core-animation-nodeps",
+        "androidx.core_core-animation",
         "androidx.core_core-ktx",
         "androidx.annotation_annotation",
         "SystemUIShaderLib",
@@ -62,7 +62,7 @@
     ],
 
     static_libs: [
-        "androidx.core_core-animation-nodeps",
+        "androidx.core_core-animation",
         "androidx.core_core-ktx",
         "androidx.annotation_annotation",
     ],
diff --git a/services/core/java/com/android/server/VpnManagerService.java b/services/core/java/com/android/server/VpnManagerService.java
index 1d1e2d9..626fa70 100644
--- a/services/core/java/com/android/server/VpnManagerService.java
+++ b/services/core/java/com/android/server/VpnManagerService.java
@@ -1007,6 +1007,71 @@
         }
     }
 
+    /**
+     * Get the vpn profile owned by the calling uid with the given name from the vpn database.
+     *
+     * <p>Note this method should not be used for platform VPN profiles. </p>
+     *
+     * @param name The name of the profile to retrieve.
+     * @return the unstructured blob for the matching vpn profile.
+     * Returns null if no profile with a matching name was found.
+     * @hide
+     */
+    @Override
+    @Nullable
+    public byte[] getFromVpnProfileStore(@NonNull String name) {
+        return mVpnProfileStore.get(name);
+    }
+
+    /**
+     * Put the given vpn profile owned by the calling uid with the given name into the vpn database.
+     * Existing profiles with the same name will be replaced.
+     *
+     * <p>Note this method should not be used for platform VPN profiles.
+     * To update a platform VPN, use provisionVpnProfile() instead. </p>
+     *
+     * @param name The name of the profile to put.
+     * @param blob The profile.
+     * @return true if the profile was successfully added. False otherwise.
+     * @hide
+     */
+    @Override
+    public boolean putIntoVpnProfileStore(@NonNull String name, @NonNull byte[] blob) {
+        return mVpnProfileStore.put(name, blob);
+    }
+
+    /**
+     * Removes the vpn profile owned by the calling uid with the given name from the vpn database.
+     *
+     * <p>Note this method should not be used for platform VPN profiles.
+     * To remove a platform VPN, use deleteVpnProfile() instead.</p>
+     *
+     * @param name The name of the profile to be removed.
+     * @return true if a profile was removed. False if no profile with a matching name was found.
+     * @hide
+     */
+    @Override
+    public boolean removeFromVpnProfileStore(@NonNull String name) {
+        return mVpnProfileStore.remove(name);
+    }
+
+    /**
+     * Returns a list of the name suffixes of the vpn profiles owned by the calling uid in the vpn
+     * database matching the given prefix, sorted in ascending order.
+     *
+     * <p>Note this method should not be used for platform VPN profiles. </p>
+     *
+     * @param prefix The prefix to match.
+     * @return an array of strings representing the name suffixes stored in the profile database
+     * matching the given prefix. The return value may be empty but never null.
+     * @hide
+     */
+    @Override
+    @NonNull
+    public String[] listFromVpnProfileStore(@NonNull String prefix) {
+        return mVpnProfileStore.list(prefix);
+    }
+
     private void ensureRunningOnHandlerThread() {
         if (mHandler.getLooper().getThread() != Thread.currentThread()) {
             throw new IllegalStateException(
diff --git a/services/core/java/com/android/server/am/LmkdStatsReporter.java b/services/core/java/com/android/server/am/LmkdStatsReporter.java
index 507fd9e..8266299 100644
--- a/services/core/java/com/android/server/am/LmkdStatsReporter.java
+++ b/services/core/java/com/android/server/am/LmkdStatsReporter.java
@@ -45,6 +45,7 @@
     private static final int LOW_MEM_AND_SWAP_UTIL = 6;
     private static final int LOW_FILECACHE_AFTER_THRASHING = 7;
     private static final int LOW_MEM = 8;
+    private static final int DIRECT_RECL_STUCK = 9;
 
     /**
      * Processes the LMK_KILL_OCCURRED packet data
@@ -109,6 +110,8 @@
                 return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__LOW_FILECACHE_AFTER_THRASHING;
             case LOW_MEM:
                 return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__LOW_MEM;
+            case DIRECT_RECL_STUCK:
+                return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__DIRECT_RECL_STUCK;
             default:
                 return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__UNKNOWN;
         }
diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
index 698f6ea..4eea8c6 100644
--- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
+++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
@@ -3708,6 +3708,7 @@
         public abstract T instantiateObject();
     }
 
+    @SuppressWarnings("ParcelableCreator")
     public static class ControllerActivityCounterImpl extends ControllerActivityCounter
             implements Parcelable {
         private final Clock mClock;
diff --git a/services/tests/VpnTests/java/com/android/server/VpnManagerServiceTest.java b/services/tests/VpnTests/java/com/android/server/VpnManagerServiceTest.java
index ecc70e3..8495de4 100644
--- a/services/tests/VpnTests/java/com/android/server/VpnManagerServiceTest.java
+++ b/services/tests/VpnTests/java/com/android/server/VpnManagerServiceTest.java
@@ -397,4 +397,35 @@
         // Even lockdown is enabled but no Vpn is created for SECONDARY_USER.
         assertNull(mService.getVpnLockdownAllowlist(SECONDARY_USER.id));
     }
+
+    @Test
+    public void testGetFromVpnProfileStore() {
+        final String name = Credentials.VPN + TEST_VPN_PKG;
+        mService.getFromVpnProfileStore(name);
+        verify(mVpnProfileStore).get(name);
+    }
+
+    @Test
+    public void testPutIntoVpnProfileStore() {
+        final String name = Credentials.VPN + TEST_VPN_PKG;
+        final VpnProfile vpnProfile = new VpnProfile(TEST_VPN_PKG);
+        final byte[] encodedProfile = vpnProfile.encode();
+
+        mService.putIntoVpnProfileStore(name, encodedProfile);
+        verify(mVpnProfileStore).put(name, encodedProfile);
+    }
+
+    @Test
+    public void testRemoveFromVpnProfileStore() {
+        final String name = Credentials.VPN + TEST_VPN_PKG;
+        mService.removeFromVpnProfileStore(name);
+        verify(mVpnProfileStore).remove(name);
+    }
+
+    @Test
+    public void testListFromVpnProfileStore() {
+        final String name = Credentials.VPN + TEST_VPN_PKG;
+        mService.listFromVpnProfileStore(name);
+        verify(mVpnProfileStore).list(name);
+    }
 }
diff --git a/services/tests/VpnTests/java/com/android/server/connectivity/VpnTest.java b/services/tests/VpnTests/java/com/android/server/connectivity/VpnTest.java
index 9115f95..08155c7 100644
--- a/services/tests/VpnTests/java/com/android/server/connectivity/VpnTest.java
+++ b/services/tests/VpnTests/java/com/android/server/connectivity/VpnTest.java
@@ -3158,13 +3158,6 @@
         assertEquals(profile, ikev2VpnProfile.toVpnProfile());
     }
 
-    private void assertTransportInfoMatches(NetworkCapabilities nc, int type) {
-        assertNotNull(nc);
-        VpnTransportInfo ti = (VpnTransportInfo) nc.getTransportInfo();
-        assertNotNull(ti);
-        assertEquals(type, ti.getType());
-    }
-
     // Make it public and un-final so as to spy it
     public class TestDeps extends Vpn.Dependencies {
         TestDeps() {}
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index fad8115..c333eb7 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -255,3 +255,89 @@
         "done && " +
         "$(location soong_zip) -o $(out) -C $(genDir)/res -D $(genDir)/res",
 }
+
+FLAKY_AND_IGNORED = [
+    "androidx.test.filters.FlakyTest",
+    "org.junit.Ignore",
+]
+// Used by content protection TEST_MAPPING
+test_module_config {
+    name: "FrameworksServicesTests_contentprotection",
+    base: "FrameworksServicesTests",
+    test_suites: ["general-tests"],
+    include_filters: ["com.android.server.contentprotection"],
+    exclude_annotations: FLAKY_AND_IGNORED,
+}
+
+test_module_config {
+    name: "FrameworksServicesTests_om",
+    base: "FrameworksServicesTests",
+    test_suites: ["general-tests"],
+    include_filters: ["com.android.server.om."],
+    exclude_annotations: FLAKY_AND_IGNORED,
+}
+
+// Used by contexthub TEST_MAPPING
+test_module_config {
+    name: "FrameworksServicesTests_contexthub_presubmit",
+    base: "FrameworksServicesTests",
+    test_suites: ["general-tests"],
+    include_filters: ["com.android.server.location.contexthub."],
+    // TODO(ron): are these right, does it run anything?
+    include_annotations: ["android.platform.test.annotations.Presubmit"],
+    exclude_annotations: FLAKY_AND_IGNORED,
+}
+
+test_module_config {
+    name: "FrameworksServicesTests_contexthub_postsubmit",
+    base: "FrameworksServicesTests",
+    test_suites: ["general-tests"],
+    include_filters: ["com.android.server.location.contexthub."],
+    // TODO(ron): are these right, does it run anything?
+    include_annotations: ["android.platform.test.annotations.Postsubmit"],
+    exclude_annotations: FLAKY_AND_IGNORED,
+}
+
+// Used by contentcapture
+test_module_config {
+    name: "FrameworksServicesTests_contentcapture",
+    base: "FrameworksServicesTests",
+    test_suites: ["general-tests"],
+    include_filters: ["com.android.server.contentcapture"],
+    exclude_annotations: FLAKY_AND_IGNORED,
+}
+
+test_module_config {
+    name: "FrameworksServicesTests_recoverysystem",
+    base: "FrameworksServicesTests",
+    test_suites: ["general-tests"],
+    include_filters: ["com.android.server.recoverysystem."],
+    exclude_annotations: ["androidx.test.filters.FlakyTest"],
+}
+
+// server pm TEST_MAPPING
+test_module_config {
+    name: "FrameworksServicesTests_pm_presubmit",
+    base: "FrameworksServicesTests",
+    test_suites: ["general-tests"],
+    include_annotations: ["android.platform.test.annotations.Presubmit"],
+    include_filters: ["com.android.server.pm."],
+    exclude_annotations: FLAKY_AND_IGNORED,
+}
+
+test_module_config {
+    name: "FrameworksServicesTests_pm_postsubmit",
+    base: "FrameworksServicesTests",
+    test_suites: ["general-tests"],
+    include_annotations: ["android.platform.test.annotations.Postsubmit"],
+    include_filters: ["com.android.server.pm."],
+    exclude_annotations: FLAKY_AND_IGNORED,
+}
+
+// server os TEST_MAPPING
+test_module_config {
+    name: "FrameworksServicesTests_os",
+    base: "FrameworksServicesTests",
+    test_suites: ["general-tests"],
+    include_filters: ["com.android.server.os."],
+}
diff --git a/services/tests/servicestests/src/com/android/server/contentcapture/TEST_MAPPING b/services/tests/servicestests/src/com/android/server/contentcapture/TEST_MAPPING
index 0ffa891..dae8f93 100644
--- a/services/tests/servicestests/src/com/android/server/contentcapture/TEST_MAPPING
+++ b/services/tests/servicestests/src/com/android/server/contentcapture/TEST_MAPPING
@@ -14,5 +14,11 @@
         }
       ]
     }
+  ],
+  "postsubmit": [
+    {
+      // b/331020193, Move to presubmit early april 2024
+      "name": "FrameworksServicesTests_contentcapture"
+    }
   ]
 }
diff --git a/services/tests/servicestests/src/com/android/server/contentprotection/TEST_MAPPING b/services/tests/servicestests/src/com/android/server/contentprotection/TEST_MAPPING
index 419508c..32729a8 100644
--- a/services/tests/servicestests/src/com/android/server/contentprotection/TEST_MAPPING
+++ b/services/tests/servicestests/src/com/android/server/contentprotection/TEST_MAPPING
@@ -14,5 +14,11 @@
         }
       ]
     }
+  ],
+  "postsubmit": [
+    {
+      // b/331020193, Move to presubmit early april 2024
+      "name": "FrameworksServicesTests_contentprotection"
+    }
   ]
 }
diff --git a/services/tests/servicestests/src/com/android/server/location/contexthub/TEST_MAPPING b/services/tests/servicestests/src/com/android/server/location/contexthub/TEST_MAPPING
index 6035250..dc8f934 100644
--- a/services/tests/servicestests/src/com/android/server/location/contexthub/TEST_MAPPING
+++ b/services/tests/servicestests/src/com/android/server/location/contexthub/TEST_MAPPING
@@ -20,12 +20,18 @@
   ],
   "postsubmit": [
     {
+      // b/331020193, Move to presubmit early april 2024
+      "name": "FrameworksServicesTests_contexthub_presubmit"
+    },
+    {
       "name": "FrameworksServicesTests",
       "options": [
         {
           "include-filter": "com.android.server.location.contexthub."
         },
         {
+          // I believe this include annotation is preventing tests from being run
+          // as there are no matching tests with the Postsubmit annotation.
           "include-annotation": "android.platform.test.annotations.Postsubmit"
         },
         {
diff --git a/services/tests/servicestests/src/com/android/server/om/TEST_MAPPING b/services/tests/servicestests/src/com/android/server/om/TEST_MAPPING
index 558e259..41c4383 100644
--- a/services/tests/servicestests/src/com/android/server/om/TEST_MAPPING
+++ b/services/tests/servicestests/src/com/android/server/om/TEST_MAPPING
@@ -16,5 +16,11 @@
         }
       ]
     }
+  ],
+  "postsubmit": [
+    {
+      // b/331020193, Move to presubmit early april 2024
+      "name": "FrameworksServicesTests_om"
+    }
   ]
 }
diff --git a/services/tests/servicestests/src/com/android/server/os/TEST_MAPPING b/services/tests/servicestests/src/com/android/server/os/TEST_MAPPING
index 5a46f8c4..06e7002 100644
--- a/services/tests/servicestests/src/com/android/server/os/TEST_MAPPING
+++ b/services/tests/servicestests/src/com/android/server/os/TEST_MAPPING
@@ -8,5 +8,11 @@
         }
       ]
     }
+  ],
+  "postsubmit": [
+    {
+      // b/331020193, Move to presubmit early april 2024
+      "name": "FrameworksServicesTests_os"
+    }
   ]
 }
diff --git a/services/tests/servicestests/src/com/android/server/pm/TEST_MAPPING b/services/tests/servicestests/src/com/android/server/pm/TEST_MAPPING
index 85a73bb..f4e724f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/TEST_MAPPING
+++ b/services/tests/servicestests/src/com/android/server/pm/TEST_MAPPING
@@ -20,21 +20,13 @@
   ],
   "postsubmit": [
     {
-      "name": "FrameworksServicesTests",
-      "options": [
-        {
-          "include-filter": "com.android.server.pm."
-        },
-        {
-          "include-annotation": "android.platform.test.annotations.Postsubmit"
-        },
-        {
-          "exclude-annotation": "androidx.test.filters.FlakyTest"
-        },
-        {
-          "exclude-annotation": "org.junit.Ignore"
-        }
-      ]
+      // Presubmit is intentional here while testing with SLO checker.
+      // b/331020193, Move to presubmit early april 2024
+      "name": "FrameworksServicesTests_pm_presubmit"
+    },
+    {
+      // Leave postsubmit here when migrating
+      "name": "FrameworksServicesTests_pm_postsubmit"
     }
   ]
 }
diff --git a/services/tests/servicestests/src/com/android/server/recoverysystem/TEST_MAPPING b/services/tests/servicestests/src/com/android/server/recoverysystem/TEST_MAPPING
index e9d8b2e..7e7393c 100644
--- a/services/tests/servicestests/src/com/android/server/recoverysystem/TEST_MAPPING
+++ b/services/tests/servicestests/src/com/android/server/recoverysystem/TEST_MAPPING
@@ -11,5 +11,11 @@
                 }
             ]
         }
+    ],
+    "postsubmit": [
+      {
+        // b/331020193, Move to presubmit early april 2024
+        "name": "FrameworksServicesTests_recoverysystem"
+      }
     ]
 }
\ No newline at end of file
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index 55a00fc..48fc2dc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -799,6 +799,7 @@
         verify(child).onConfigurationChanged(any());
     }
 
+    @SuppressWarnings("SelfComparison")
     @Test
     public void testCompareTo() {
         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
diff --git a/services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java b/services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java
index d9cbea9..ed89190 100644
--- a/services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java
+++ b/services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java
@@ -181,7 +181,7 @@
                 // We only need to look at the broadcast events that occurred before
                 // this notification related event.
                 while (dispatchTimestampsMs.size() > 0
-                        && dispatchTimestampsMs.peekFirst() < timestampMs) {
+                        && dispatchTimestampsMs.peekFirst() <= timestampMs) {
                     final long dispatchTimestampMs = dispatchTimestampsMs.peekFirst();
                     final long elapsedDurationMs = timestampMs - dispatchTimestampMs;
                     // Only increment the counts if the broadcast was sent not too long ago, as
diff --git a/test-legacy/Android.bp b/test-legacy/Android.bp
new file mode 100644
index 0000000..236d704
--- /dev/null
+++ b/test-legacy/Android.bp
@@ -0,0 +1,38 @@
+// Copyright (C) 2018 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 {
+    // See: http://go/android-license-faq
+    default_applicable_licenses: [
+        "Android-Apache-2.0",
+    ],
+}
+
+java_library {
+    name: "android.test.legacy",
+    sdk_version: "current",
+    libs: [
+        "android.test.mock.stubs",
+        "junit",
+    ],
+    static_libs: [
+        "android.test.base-minus-junit",
+        "android.test.runner-minus-junit",
+    ],
+    dist: {
+        targets: [
+            "sdk",
+        ],
+    },
+}
diff --git a/test-legacy/Android.mk b/test-legacy/Android.mk
deleted file mode 100644
index da9dc25..0000000
--- a/test-legacy/Android.mk
+++ /dev/null
@@ -1,50 +0,0 @@
-#
-# Copyright (C) 2018 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.
-#
-
-LOCAL_PATH:= $(call my-dir)
-
-# For unbundled build we'll use the prebuilt jar from prebuilts/sdk.
-ifeq (,$(TARGET_BUILD_APPS)$(filter true,$(TARGET_BUILD_PDK)))
-
-# Build the android.test.legacy library
-# =====================================
-# Built against the SDK so that it can be statically included in APKs
-# without breaking link type checks.
-#
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := android.test.legacy
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-MIT SPDX-license-identifier-Unicode-DFS
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../NOTICE
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_JAVA_LIBRARIES := junit android.test.mock.stubs
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    android.test.base-minus-junit \
-    android.test.runner-minus-junit \
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-$(call declare-license-metadata,$(full_classes_jar),\
-    SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-MIT SPDX-license-identifier-Unicode-DFS,\
-    notice,$(LOCAL_PATH)/../NOTICE,Android,frameworks/base)
-
-# Archive a copy of the classes.jar in SDK build.
-$(call dist-for-goals,sdk,$(full_classes_jar):android.test.legacy.jar)
-
-endif  # not TARGET_BUILD_APPS not TARGET_BUILD_PDK=true
diff --git a/tests/testables/OWNERS b/tests/testables/OWNERS
new file mode 100644
index 0000000..a6f1632
--- /dev/null
+++ b/tests/testables/OWNERS
@@ -0,0 +1 @@
+file:/packages/SystemUI/OWNERS
\ No newline at end of file