Merge "[java] Restore ServiceManager#checkService() to return IBinder" into main
diff --git a/apct-tests/perftests/aconfig/src/android/os/flagging/AconfigPackagePerfTest.java b/apct-tests/perftests/aconfig/src/android/os/flagging/AconfigPackagePerfTest.java
index df6e3c8..e790874 100644
--- a/apct-tests/perftests/aconfig/src/android/os/flagging/AconfigPackagePerfTest.java
+++ b/apct-tests/perftests/aconfig/src/android/os/flagging/AconfigPackagePerfTest.java
@@ -43,7 +43,7 @@
 
     @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
-    @Parameterized.Parameters(name = "isPlatform={0}")
+    @Parameterized.Parameters(name = "isPlatform_{0}")
     public static Collection<Object[]> data() {
         return Arrays.asList(new Object[][] {{false}, {true}});
     }
@@ -60,10 +60,9 @@
         }
     }
 
-    @Parameterized.Parameter(0)
-
     // if this variable is true, then the test query flags from system/product/vendor
     // if this variable is false, then the test query flags from updatable partitions
+    @Parameterized.Parameter(0)
     public boolean mIsPlatform;
 
     @Test
diff --git a/apct-tests/perftests/core/src/android/content/pm/SystemFeaturesPerfTest.java b/apct-tests/perftests/core/src/android/content/pm/SystemFeaturesPerfTest.java
new file mode 100644
index 0000000..43f5453
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/content/pm/SystemFeaturesPerfTest.java
@@ -0,0 +1,96 @@
+/*
+ * 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 android.content.pm;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.pm.RoSystemFeatures;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class SystemFeaturesPerfTest {
+    // As each query is relatively cheap, add an inner iteration loop to reduce execution noise.
+    private static final int NUM_ITERATIONS = 10;
+
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+    @Test
+    public void hasSystemFeature_PackageManager() {
+        final PackageManager pm =
+                InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageManager();
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            for (int i = 0; i < NUM_ITERATIONS; ++i) {
+                pm.hasSystemFeature(PackageManager.FEATURE_WATCH);
+                pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK);
+                pm.hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS);
+                pm.hasSystemFeature(PackageManager.FEATURE_AUTOFILL);
+                pm.hasSystemFeature("com.android.custom.feature.1");
+                pm.hasSystemFeature("foo");
+                pm.hasSystemFeature("");
+            }
+        }
+    }
+
+    @Test
+    public void hasSystemFeature_SystemFeaturesCache() {
+        final PackageManager pm =
+                InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageManager();
+        final SystemFeaturesCache cache =
+                new SystemFeaturesCache(Arrays.asList(pm.getSystemAvailableFeatures()));
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            for (int i = 0; i < NUM_ITERATIONS; ++i) {
+                cache.maybeHasFeature(PackageManager.FEATURE_WATCH, 0);
+                cache.maybeHasFeature(PackageManager.FEATURE_LEANBACK, 0);
+                cache.maybeHasFeature(PackageManager.FEATURE_IPSEC_TUNNELS, 0);
+                cache.maybeHasFeature(PackageManager.FEATURE_AUTOFILL, 0);
+                cache.maybeHasFeature("com.android.custom.feature.1", 0);
+                cache.maybeHasFeature("foo", 0);
+                cache.maybeHasFeature("", 0);
+            }
+        }
+    }
+
+    @Test
+    public void hasSystemFeature_RoSystemFeatures() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            for (int i = 0; i < NUM_ITERATIONS; ++i) {
+                RoSystemFeatures.maybeHasFeature(PackageManager.FEATURE_WATCH, 0);
+                RoSystemFeatures.maybeHasFeature(PackageManager.FEATURE_LEANBACK, 0);
+                RoSystemFeatures.maybeHasFeature(PackageManager.FEATURE_IPSEC_TUNNELS, 0);
+                RoSystemFeatures.maybeHasFeature(PackageManager.FEATURE_AUTOFILL, 0);
+                RoSystemFeatures.maybeHasFeature("com.android.custom.feature.1", 0);
+                RoSystemFeatures.maybeHasFeature("foo", 0);
+                RoSystemFeatures.maybeHasFeature("", 0);
+            }
+        }
+    }
+}
diff --git a/boot/preloaded-classes b/boot/preloaded-classes
index b83bd4e..9926aef 100644
--- a/boot/preloaded-classes
+++ b/boot/preloaded-classes
@@ -6470,6 +6470,7 @@
 android.os.connectivity.WifiBatteryStats$1
 android.os.connectivity.WifiBatteryStats
 android.os.flagging.AconfigPackage
+android.os.flagging.PlatformAconfigPackage
 android.os.health.HealthKeys$Constant
 android.os.health.HealthKeys$Constants
 android.os.health.HealthKeys$SortedIntArray
diff --git a/config/preloaded-classes b/config/preloaded-classes
index e53c78f..bdd95f8 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -6474,6 +6474,7 @@
 android.os.connectivity.WifiBatteryStats$1
 android.os.connectivity.WifiBatteryStats
 android.os.flagging.AconfigPackage
+android.os.flagging.PlatformAconfigPackage
 android.os.health.HealthKeys$Constant
 android.os.health.HealthKeys$Constants
 android.os.health.HealthKeys$SortedIntArray
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 67f7bee..b5ac4e7 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -70,7 +70,6 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.nio.charset.Charset;
-import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.Executor;
@@ -1064,7 +1063,7 @@
             Log.e(TAG, "Save lock exception", e);
             success = false;
         } finally {
-            Arrays.fill(password, (byte) 0);
+            LockPatternUtils.zeroize(password);
         }
         return success;
     }
diff --git a/core/java/android/content/pm/SystemFeaturesCache.aidl b/core/java/android/content/pm/SystemFeaturesCache.aidl
new file mode 100644
index 0000000..18c1830
--- /dev/null
+++ b/core/java/android/content/pm/SystemFeaturesCache.aidl
@@ -0,0 +1,19 @@
+/*
+** Copyright 2025, 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 android.content.pm;
+
+parcelable SystemFeaturesCache;
diff --git a/core/java/android/content/pm/SystemFeaturesCache.java b/core/java/android/content/pm/SystemFeaturesCache.java
new file mode 100644
index 0000000..c41a7ab
--- /dev/null
+++ b/core/java/android/content/pm/SystemFeaturesCache.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2025 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 android.content.pm;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArrayMap;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+/**
+ * A simple cache for SDK-defined system feature versions.
+ *
+ * The dense representation minimizes any per-process memory impact (<1KB). The tradeoff is that
+ * custom, non-SDK defined features are not captured by the cache, for which we can rely on the
+ * usual IPC cache for related queries.
+ *
+ * @hide
+ */
+public final class SystemFeaturesCache implements Parcelable {
+
+    // Sentinel value used for SDK-declared features that are unavailable on the current device.
+    private static final int UNAVAILABLE_FEATURE_VERSION = Integer.MIN_VALUE;
+
+    // An array of versions for SDK-defined features, from [0, PackageManager.SDK_FEATURE_COUNT).
+    @NonNull
+    private final int[] mSdkFeatureVersions;
+
+    /**
+     * Populates the cache from the set of all available {@link FeatureInfo} definitions.
+     *
+     * System features declared in {@link PackageManager} will be entered into the cache based on
+     * availability in this feature set. Other custom system features will be ignored.
+     */
+    public SystemFeaturesCache(@NonNull ArrayMap<String, FeatureInfo> availableFeatures) {
+        this(availableFeatures.values());
+    }
+
+    @VisibleForTesting
+    public SystemFeaturesCache(@NonNull Collection<FeatureInfo> availableFeatures) {
+        // First set all SDK-defined features as unavailable.
+        mSdkFeatureVersions = new int[PackageManager.SDK_FEATURE_COUNT];
+        Arrays.fill(mSdkFeatureVersions, UNAVAILABLE_FEATURE_VERSION);
+
+        // Then populate SDK-defined feature versions from the full set of runtime features.
+        for (FeatureInfo fi : availableFeatures) {
+            int sdkFeatureIndex = PackageManager.maybeGetSdkFeatureIndex(fi.name);
+            if (sdkFeatureIndex >= 0) {
+                mSdkFeatureVersions[sdkFeatureIndex] = fi.version;
+            }
+        }
+    }
+
+    /** Only used by @{code CREATOR.createFromParcel(...)} */
+    private SystemFeaturesCache(@NonNull Parcel parcel) {
+        final int[] featureVersions = parcel.createIntArray();
+        if (featureVersions == null) {
+            throw new IllegalArgumentException(
+                    "Parceled SDK feature versions should never be null");
+        }
+        if (featureVersions.length != PackageManager.SDK_FEATURE_COUNT) {
+            throw new IllegalArgumentException(
+                    String.format(
+                            "Unexpected cached SDK feature count: %d (expected %d)",
+                            featureVersions.length, PackageManager.SDK_FEATURE_COUNT));
+        }
+        mSdkFeatureVersions = featureVersions;
+    }
+
+    /**
+     * @return Whether the given feature is available (for SDK-defined features), otherwise null.
+     */
+    public Boolean maybeHasFeature(@NonNull String featureName, int version) {
+        // Features defined outside of the SDK aren't cached.
+        int sdkFeatureIndex = PackageManager.maybeGetSdkFeatureIndex(featureName);
+        if (sdkFeatureIndex < 0) {
+            return null;
+        }
+
+        // As feature versions can in theory collide with our sentinel value, in the (extremely)
+        // unlikely event that the queried version matches the sentinel value, we can't distinguish
+        // between an unavailable feature and a feature with the defined sentinel value.
+        if (version == UNAVAILABLE_FEATURE_VERSION
+                && mSdkFeatureVersions[sdkFeatureIndex] == UNAVAILABLE_FEATURE_VERSION) {
+            return null;
+        }
+
+        return mSdkFeatureVersions[sdkFeatureIndex] >= version;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel parcel, int flags) {
+        parcel.writeIntArray(mSdkFeatureVersions);
+    }
+
+    @NonNull
+    public static final Parcelable.Creator<SystemFeaturesCache> CREATOR =
+            new Parcelable.Creator<SystemFeaturesCache>() {
+
+                @Override
+                public SystemFeaturesCache createFromParcel(Parcel parcel) {
+                    return new SystemFeaturesCache(parcel);
+                }
+
+                @Override
+                public SystemFeaturesCache[] newArray(int size) {
+                    return new SystemFeaturesCache[size];
+                }
+            };
+}
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index beb9a93..daaf760 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -76,6 +76,9 @@
     private static final String PROPERTY_GFX_DRIVER_PRERELEASE = "ro.gfx.driver.1";
     private static final String PROPERTY_GFX_DRIVER_BUILD_TIME = "ro.gfx.driver_build_time";
 
+    /// System properties related to EGL
+    private static final String PROPERTY_RO_HARDWARE_EGL = "ro.hardware.egl";
+
     // Metadata flags within the <application> tag in the AndroidManifest.xml file.
     private static final String METADATA_DRIVER_BUILD_TIME =
             "com.android.graphics.driver.build_time";
@@ -479,9 +482,11 @@
 
         final List<ResolveInfo> resolveInfos =
                 pm.queryIntentActivities(intent, PackageManager.MATCH_SYSTEM_ONLY);
-        if (resolveInfos.size() != 1) {
-            Log.v(TAG, "Invalid number of ANGLE packages. Required: 1, Found: "
-                    + resolveInfos.size());
+        if (resolveInfos.isEmpty()) {
+            Log.v(TAG, "No ANGLE packages installed.");
+            return "";
+        } else if (resolveInfos.size() > 1) {
+            Log.v(TAG, "Too many ANGLE packages found: " + resolveInfos.size());
             if (DEBUG) {
                 for (ResolveInfo resolveInfo : resolveInfos) {
                     Log.d(TAG, "Found ANGLE package: " + resolveInfo.activityInfo.packageName);
@@ -491,7 +496,7 @@
         }
 
         // Must be exactly 1 ANGLE PKG found to get here.
-        return resolveInfos.get(0).activityInfo.packageName;
+        return resolveInfos.getFirst().activityInfo.packageName;
     }
 
     /**
@@ -520,10 +525,12 @@
     }
 
     /**
-     * Determine whether ANGLE should be used, attempt to set up from apk first, if ANGLE can be
-     * set up from apk, pass ANGLE details down to the C++ GraphicsEnv class via
-     * GraphicsEnv::setAngleInfo(). If apk setup fails, attempt to set up to use system ANGLE.
-     * Return false if both fail.
+     * If ANGLE is not the system driver, determine whether ANGLE should be used, and if so, pass
+     * down the necessary details to the C++ GraphicsEnv class via GraphicsEnv::setAngleInfo().
+     * <p>
+     * If ANGLE is the system driver or the various flags indicate it should be used, attempt to
+     * set up ANGLE from the APK first, so the updatable libraries are used. If APK setup fails,
+     * attempt to set up the system ANGLE. Return false if both fail.
      *
      * @param context - Context of the application.
      * @param bundle - Bundle of the application.
@@ -534,15 +541,26 @@
      */
     private boolean setupAngle(Context context, Bundle bundle, PackageManager packageManager,
             String packageName) {
-        final String angleChoice = queryAngleChoice(context, bundle, packageName);
-        if (angleChoice.equals(ANGLE_GL_DRIVER_CHOICE_DEFAULT)) {
-            return false;
-        }
-        if (angleChoice.equals(ANGLE_GL_DRIVER_CHOICE_NATIVE)) {
-            nativeSetAngleInfo("", true, packageName, null);
-            return false;
+        final String eglDriverName = SystemProperties.get(PROPERTY_RO_HARDWARE_EGL);
+
+        // The ANGLE choice only makes sense if ANGLE is not the system driver.
+        if (!eglDriverName.equals(ANGLE_DRIVER_NAME)) {
+            final String angleChoice = queryAngleChoice(context, bundle, packageName);
+            if (angleChoice.equals(ANGLE_GL_DRIVER_CHOICE_DEFAULT)) {
+                return false;
+            }
+            if (angleChoice.equals(ANGLE_GL_DRIVER_CHOICE_NATIVE)) {
+                nativeSetAngleInfo("", true, packageName, null);
+                return false;
+            }
         }
 
+        // If we reach here, it means either:
+        // 1. system driver is not ANGLE, but ANGLE is requested.
+        // 2. system driver is ANGLE.
+        // In both cases, setup ANGLE info. We attempt to setup the APK first, so
+        // updated/development libraries are used if the APK is present, falling back to the system
+        // libraries otherwise.
         return setupAngleFromApk(context, bundle, packageManager, packageName)
                 || setupAngleFromSystem(context, bundle, packageName);
     }
@@ -580,7 +598,6 @@
         if (angleInfo == null) {
             anglePkgName = getAnglePackageName(packageManager);
             if (TextUtils.isEmpty(anglePkgName)) {
-                Log.v(TAG, "Failed to find ANGLE package.");
                 return false;
             }
 
diff --git a/core/java/android/security/flags.aconfig b/core/java/android/security/flags.aconfig
index 392b42d..ceee898b 100644
--- a/core/java/android/security/flags.aconfig
+++ b/core/java/android/security/flags.aconfig
@@ -42,6 +42,16 @@
 }
 
 flag {
+    name: "secure_array_zeroization"
+    namespace: "platform_security"
+    description: "Enable secure array zeroization"
+    bug: "320392352"
+    metadata {
+      purpose: PURPOSE_BUGFIX
+    }
+}
+
+flag {
     name: "deprecate_fsv_sig"
     namespace: "hardware_backed_security"
     description: "Feature flag for deprecating .fsv_sig"
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 9bd5237..d129762 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -61,6 +61,7 @@
 import android.util.SparseLongArray;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
 import com.android.server.LocalServices;
 
 import com.google.android.collect.Lists;
@@ -71,6 +72,7 @@
 import java.security.NoSuchAlgorithmException;
 import java.security.SecureRandom;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
@@ -288,6 +290,56 @@
 
     }
 
+    /**
+     * This exists temporarily due to trunk-stable policies.
+     * Please use ArrayUtils directly if you can.
+     */
+    public static byte[] newNonMovableByteArray(int length) {
+        if (!android.security.Flags.secureArrayZeroization()) {
+            return new byte[length];
+        }
+        return ArrayUtils.newNonMovableByteArray(length);
+    }
+
+    /**
+     * This exists temporarily due to trunk-stable policies.
+     * Please use ArrayUtils directly if you can.
+     */
+    public static char[] newNonMovableCharArray(int length) {
+        if (!android.security.Flags.secureArrayZeroization()) {
+            return new char[length];
+        }
+        return ArrayUtils.newNonMovableCharArray(length);
+    }
+
+    /**
+     * This exists temporarily due to trunk-stable policies.
+     * Please use ArrayUtils directly if you can.
+     */
+    public static void zeroize(byte[] array) {
+        if (!android.security.Flags.secureArrayZeroization()) {
+            if (array != null) {
+                Arrays.fill(array, (byte) 0);
+            }
+            return;
+        }
+        ArrayUtils.zeroize(array);
+    }
+
+    /**
+     * This exists temporarily due to trunk-stable policies.
+     * Please use ArrayUtils directly if you can.
+     */
+    public static void zeroize(char[] array) {
+        if (!android.security.Flags.secureArrayZeroization()) {
+            if (array != null) {
+                Arrays.fill(array, (char) 0);
+            }
+            return;
+        }
+        ArrayUtils.zeroize(array);
+    }
+
     @UnsupportedAppUsage
     public DevicePolicyManager getDevicePolicyManager() {
         if (mDevicePolicyManager == null) {
diff --git a/core/java/com/android/internal/widget/LockscreenCredential.java b/core/java/com/android/internal/widget/LockscreenCredential.java
index 54b9a22..92ce990 100644
--- a/core/java/com/android/internal/widget/LockscreenCredential.java
+++ b/core/java/com/android/internal/widget/LockscreenCredential.java
@@ -246,7 +246,7 @@
      */
     public void zeroize() {
         if (mCredential != null) {
-            Arrays.fill(mCredential, (byte) 0);
+            LockPatternUtils.zeroize(mCredential);
             mCredential = null;
         }
     }
@@ -346,7 +346,7 @@
             byte[] sha1 = MessageDigest.getInstance("SHA-1").digest(saltedPassword);
             byte[] md5 = MessageDigest.getInstance("MD5").digest(saltedPassword);
 
-            Arrays.fill(saltedPassword, (byte) 0);
+            LockPatternUtils.zeroize(saltedPassword);
             return HexEncoding.encodeToString(ArrayUtils.concat(sha1, md5));
         } catch (NoSuchAlgorithmException e) {
             throw new AssertionError("Missing digest algorithm: ", e);
diff --git a/core/jni/android_hardware_UsbDeviceConnection.cpp b/core/jni/android_hardware_UsbDeviceConnection.cpp
index b1221ee..68ef3d4 100644
--- a/core/jni/android_hardware_UsbDeviceConnection.cpp
+++ b/core/jni/android_hardware_UsbDeviceConnection.cpp
@@ -165,19 +165,25 @@
         return -1;
     }
 
-    jbyte* bufferBytes = NULL;
-    if (buffer) {
-        bufferBytes = (jbyte*)env->GetPrimitiveArrayCritical(buffer, NULL);
+    bool is_dir_in = (requestType & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN;
+    std::unique_ptr<jbyte[]> bufferBytes(new (std::nothrow) jbyte[length]);
+    if (!bufferBytes) {
+        jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+        return -1;
     }
 
-    jint result = usb_device_control_transfer(device, requestType, request,
-            value, index, bufferBytes + start, length, timeout);
-
-    if (bufferBytes) {
-        env->ReleasePrimitiveArrayCritical(buffer, bufferBytes, 0);
+    if (!is_dir_in && buffer) {
+        env->GetByteArrayRegion(buffer, start, length, bufferBytes.get());
     }
 
-    return result;
+    jint bytes_transferred = usb_device_control_transfer(device, requestType, request,
+            value, index, bufferBytes.get(), length, timeout);
+
+    if (bytes_transferred > 0 && is_dir_in) {
+        env->SetByteArrayRegion(buffer, start, bytes_transferred, bufferBytes.get());
+    }
+
+    return bytes_transferred;
 }
 
 static jint
diff --git a/core/tests/coretests/src/android/content/pm/SystemFeaturesCacheTest.java b/core/tests/coretests/src/android/content/pm/SystemFeaturesCacheTest.java
new file mode 100644
index 0000000..ce4aa42
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/SystemFeaturesCacheTest.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2025 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 android.content.pm;
+
+import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
+import static android.content.pm.PackageManager.FEATURE_WATCH;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.Parcel;
+import android.util.ArrayMap;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class SystemFeaturesCacheTest {
+
+    private SystemFeaturesCache mCache;
+
+    @Test
+    public void testNoFeatures() throws Exception {
+        SystemFeaturesCache cache = new SystemFeaturesCache(new ArrayMap<String, FeatureInfo>());
+        assertThat(cache.maybeHasFeature("", 0)).isNull();
+        assertThat(cache.maybeHasFeature(FEATURE_WATCH, 0)).isFalse();
+        assertThat(cache.maybeHasFeature(FEATURE_PICTURE_IN_PICTURE, 0)).isFalse();
+        assertThat(cache.maybeHasFeature("com.missing.feature", 0)).isNull();
+    }
+
+    @Test
+    public void testNonSdkFeature() throws Exception {
+        ArrayMap<String, FeatureInfo> features = new ArrayMap<>();
+        features.put("custom.feature", createFeature("custom.feature", 0));
+        SystemFeaturesCache cache = new SystemFeaturesCache(features);
+
+        assertThat(cache.maybeHasFeature("custom.feature", 0)).isNull();
+    }
+
+    @Test
+    public void testSdkFeature() throws Exception {
+        ArrayMap<String, FeatureInfo> features = new ArrayMap<>();
+        features.put(FEATURE_WATCH, createFeature(FEATURE_WATCH, 0));
+        SystemFeaturesCache cache = new SystemFeaturesCache(features);
+
+        assertThat(cache.maybeHasFeature(FEATURE_WATCH, 0)).isTrue();
+        assertThat(cache.maybeHasFeature(FEATURE_WATCH, -1)).isTrue();
+        assertThat(cache.maybeHasFeature(FEATURE_WATCH, 1)).isFalse();
+        assertThat(cache.maybeHasFeature(FEATURE_WATCH, Integer.MIN_VALUE)).isTrue();
+        assertThat(cache.maybeHasFeature(FEATURE_WATCH, Integer.MAX_VALUE)).isFalse();
+
+        // Other SDK-declared features should be reported as unavailable.
+        assertThat(cache.maybeHasFeature(FEATURE_PICTURE_IN_PICTURE, 0)).isFalse();
+    }
+
+    @Test
+    public void testSdkFeatureHasMinVersion() throws Exception {
+        ArrayMap<String, FeatureInfo> features = new ArrayMap<>();
+        features.put(FEATURE_WATCH, createFeature(FEATURE_WATCH, Integer.MIN_VALUE));
+        SystemFeaturesCache cache = new SystemFeaturesCache(features);
+
+        assertThat(cache.maybeHasFeature(FEATURE_WATCH, 0)).isFalse();
+
+        // If both the query and the feature version itself happen to use MIN_VALUE, we can't
+        // reliably indicate availability, so it should report an indeterminate result.
+        assertThat(cache.maybeHasFeature(FEATURE_WATCH, Integer.MIN_VALUE)).isNull();
+    }
+
+    @Test
+    public void testParcel() throws Exception {
+        ArrayMap<String, FeatureInfo> features = new ArrayMap<>();
+        features.put(FEATURE_WATCH, createFeature(FEATURE_WATCH, 0));
+        SystemFeaturesCache cache = new SystemFeaturesCache(features);
+
+        Parcel parcel = Parcel.obtain();
+        SystemFeaturesCache parceledCache;
+        try {
+            parcel.writeParcelable(cache, 0);
+            parcel.setDataPosition(0);
+            parceledCache = parcel.readParcelable(getClass().getClassLoader());
+        } finally {
+            parcel.recycle();
+        }
+
+        assertThat(parceledCache.maybeHasFeature(FEATURE_WATCH, 0))
+                .isEqualTo(cache.maybeHasFeature(FEATURE_WATCH, 0));
+        assertThat(parceledCache.maybeHasFeature(FEATURE_PICTURE_IN_PICTURE, 0))
+                .isEqualTo(cache.maybeHasFeature(FEATURE_PICTURE_IN_PICTURE, 0));
+        assertThat(parceledCache.maybeHasFeature("custom.feature", 0))
+                .isEqualTo(cache.maybeHasFeature("custom.feature", 0));
+    }
+
+    private static FeatureInfo createFeature(String name, int version) {
+        FeatureInfo fi = new FeatureInfo();
+        fi.name = name;
+        fi.version = version;
+        return fi;
+    }
+}
diff --git a/core/tests/coretests/src/android/os/OWNERS b/core/tests/coretests/src/android/os/OWNERS
index c45080f..5fd4ffc 100644
--- a/core/tests/coretests/src/android/os/OWNERS
+++ b/core/tests/coretests/src/android/os/OWNERS
@@ -10,6 +10,9 @@
 # PerformanceHintManager
 per-file PerformanceHintManagerTest.java = file:/ADPF_OWNERS
 
+# SystemHealthManager
+per-file SystemHealthManagerUnitTest.java = file:/ADPF_OWNERS
+
 # Caching
 per-file IpcDataCache* = file:/PERFORMANCE_OWNERS
 
diff --git a/libs/hwui/renderthread/HintSessionWrapper.h b/libs/hwui/renderthread/HintSessionWrapper.h
index 859cc57..4c96567 100644
--- a/libs/hwui/renderthread/HintSessionWrapper.h
+++ b/libs/hwui/renderthread/HintSessionWrapper.h
@@ -20,6 +20,7 @@
 #include <private/performance_hint_private.h>
 
 #include <future>
+#include <memory>
 #include <optional>
 #include <vector>
 
diff --git a/media/TEST_MAPPING b/media/TEST_MAPPING
index e52e0b1..6a21496 100644
--- a/media/TEST_MAPPING
+++ b/media/TEST_MAPPING
@@ -1,7 +1,10 @@
 {
   "presubmit": [
     {
-      "name": "CtsMediaBetterTogetherTestCases"
+      "name": "CtsMediaRouterTestCases"
+    },
+    {
+      "name": "CtsMediaSessionTestCases"
     },
     {
       "name": "mediaroutertest"
diff --git a/mime/Android.bp b/mime/Android.bp
index 20110f1..b609548 100644
--- a/mime/Android.bp
+++ b/mime/Android.bp
@@ -49,6 +49,17 @@
     ],
 }
 
+java_library {
+    name: "mimemap-testing-alt",
+    defaults: ["mimemap-defaults"],
+    static_libs: ["mimemap-testing-alt-res.jar"],
+    jarjar_rules: "jarjar-rules-alt.txt",
+    visibility: [
+        "//cts/tests/tests/mimemap:__subpackages__",
+        "//frameworks/base:__subpackages__",
+    ],
+}
+
 // The mimemap-res.jar and mimemap-testing-res.jar genrules produce a .jar that
 // has the resource file in a subdirectory res/ and testres/, respectively.
 // They need to be in different paths because one of them ends up in a
@@ -86,6 +97,19 @@
     cmd: "mkdir $(genDir)/testres/ && cp $(in) $(genDir)/testres/ && $(location soong_zip) -C $(genDir) -o $(out) -D $(genDir)/testres/",
 }
 
+// The same as mimemap-testing-res.jar except that the resources are placed in a different directory.
+// They get bundled with CTS so that CTS can compare a device's MimeMap implementation vs.
+// the stock Android one from when CTS was built.
+java_genrule {
+    name: "mimemap-testing-alt-res.jar",
+    tools: [
+        "soong_zip",
+    ],
+    srcs: [":mime.types.minimized-alt"],
+    out: ["mimemap-testing-alt-res.jar"],
+    cmd: "mkdir $(genDir)/testres-alt/ && cp $(in) $(genDir)/testres-alt/ && $(location soong_zip) -C $(genDir) -o $(out) -D $(genDir)/testres-alt/",
+}
+
 // Combination of all *mime.types.minimized resources.
 filegroup {
     name: "mime.types.minimized",
@@ -99,6 +123,19 @@
     ],
 }
 
+// Combination of all *mime.types.minimized resources.
+filegroup {
+    name: "mime.types.minimized-alt",
+    visibility: [
+        "//visibility:private",
+    ],
+    device_common_srcs: [
+        ":debian.mime.types.minimized-alt",
+        ":android.mime.types.minimized",
+        ":vendor.mime.types.minimized",
+    ],
+}
+
 java_genrule {
     name: "android.mime.types.minimized",
     visibility: [
diff --git a/mime/jarjar-rules-alt.txt b/mime/jarjar-rules-alt.txt
new file mode 100644
index 0000000..9a76443
--- /dev/null
+++ b/mime/jarjar-rules-alt.txt
@@ -0,0 +1 @@
+rule android.content.type.DefaultMimeMapFactory android.content.type.cts.StockAndroidAltMimeMapFactory
diff --git a/mime/jarjar-rules.txt b/mime/jarjar-rules.txt
index 145d1db..e1ea8e1 100644
--- a/mime/jarjar-rules.txt
+++ b/mime/jarjar-rules.txt
@@ -1 +1 @@
-rule android.content.type.DefaultMimeMapFactory android.content.type.cts.StockAndroidMimeMapFactory
\ No newline at end of file
+rule android.content.type.DefaultMimeMapFactory android.content.type.cts.StockAndroidMimeMapFactory
diff --git a/native/android/tests/system_health/OWNERS b/native/android/tests/system_health/OWNERS
new file mode 100644
index 0000000..e3bbee92
--- /dev/null
+++ b/native/android/tests/system_health/OWNERS
@@ -0,0 +1 @@
+include /ADPF_OWNERS
diff --git a/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/processor/ProtectedPluginProcessor.kt b/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/processor/ProtectedPluginProcessor.kt
index 6b54d89..9e704e2 100644
--- a/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/processor/ProtectedPluginProcessor.kt
+++ b/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/processor/ProtectedPluginProcessor.kt
@@ -24,6 +24,7 @@
 import javax.lang.model.element.Element
 import javax.lang.model.element.ElementKind
 import javax.lang.model.element.ExecutableElement
+import javax.lang.model.element.Modifier
 import javax.lang.model.element.PackageElement
 import javax.lang.model.element.TypeElement
 import javax.lang.model.type.TypeKind
@@ -165,11 +166,17 @@
                     // Method implementations
                     for (method in methods) {
                         val methodName = method.simpleName
+                        if (methods.any { methodName.startsWith("${it.simpleName}\$") }) {
+                            continue
+                        }
                         val returnTypeName = method.returnType.toString()
                         val callArgs = StringBuilder()
                         var isFirst = true
+                        val isStatic = method.modifiers.contains(Modifier.STATIC)
 
-                        line("@Override")
+                        if (!isStatic) {
+                            line("@Override")
+                        }
                         parenBlock("public $returnTypeName $methodName") {
                             // While copying the method signature for the proxy type, we also
                             // accumulate arguments for the nested callsite.
@@ -184,7 +191,8 @@
                         }
 
                         val isVoid = method.returnType.kind == TypeKind.VOID
-                        val nestedCall = "mInstance.$methodName($callArgs)"
+                        val methodContainer = if (isStatic) sourceName else "mInstance"
+                        val nestedCall = "$methodContainer.$methodName($callArgs)"
                         val callStatement =
                             when {
                                 isVoid -> "$nestedCall;"
diff --git a/packages/SystemUI/proguard_common.flags b/packages/SystemUI/proguard_common.flags
index 162d8ae..02b2bcf 100644
--- a/packages/SystemUI/proguard_common.flags
+++ b/packages/SystemUI/proguard_common.flags
@@ -1,5 +1,11 @@
 -include proguard_kotlin.flags
--keep class com.android.systemui.VendorServices
+
+# VendorServices implements CoreStartable and may be instantiated reflectively in
+# SystemUIApplication#startAdditionalStartable.
+# TODO(b/373579455): Rewrite this to a @UsesReflection keep annotation.
+-keep class com.android.systemui.VendorServices {
+  public void <init>();
+}
 
 # Needed to ensure callback field references are kept in their respective
 # owning classes when the downstream callback registrars only store weak refs.
diff --git a/packages/Vcn/service-b/Android.bp b/packages/Vcn/service-b/Android.bp
index 1370b06..97574e6 100644
--- a/packages/Vcn/service-b/Android.bp
+++ b/packages/Vcn/service-b/Android.bp
@@ -39,9 +39,7 @@
     name: "connectivity-utils-service-vcn-internal",
     sdk_version: "module_current",
     min_sdk_version: "30",
-    srcs: [
-        ":framework-connectivity-shared-srcs",
-    ],
+    srcs: ["service-utils/**/*.java"],
     libs: [
         "framework-annotations-lib",
         "unsupportedappusage",
diff --git a/packages/Vcn/service-b/service-utils/android/util/LocalLog.java b/packages/Vcn/service-b/service-utils/android/util/LocalLog.java
new file mode 100644
index 0000000..5955d93
--- /dev/null
+++ b/packages/Vcn/service-b/service-utils/android/util/LocalLog.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2025 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 android.util;
+
+import android.compat.annotation.UnsupportedAppUsage;
+import android.os.Build;
+import android.os.SystemClock;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.Iterator;
+
+/**
+ * @hide
+ */
+// Exported to Mainline modules; cannot use annotations
+// @android.ravenwood.annotation.RavenwoodKeepWholeClass
+// TODO: b/374174952 This is an exact copy of frameworks/base/core/java/android/util/LocalLog.java.
+// This file is only used in "service-connectivity-b-platform" before the VCN modularization flag
+// is fully ramped. When the flag is fully ramped and the development is finalized, this file can
+// be removed.
+public final class LocalLog {
+
+    private final Deque<String> mLog;
+    private final int mMaxLines;
+
+    /**
+     * {@code true} to use log timestamps expressed in local date/time, {@code false} to use log
+     * timestamped expressed with the elapsed realtime clock and UTC system clock. {@code false} is
+     * useful when logging behavior that modifies device time zone or system clock.
+     */
+    private final boolean mUseLocalTimestamps;
+
+    @UnsupportedAppUsage
+    public LocalLog(int maxLines) {
+        this(maxLines, true /* useLocalTimestamps */);
+    }
+
+    public LocalLog(int maxLines, boolean useLocalTimestamps) {
+        mMaxLines = Math.max(0, maxLines);
+        mLog = new ArrayDeque<>(mMaxLines);
+        mUseLocalTimestamps = useLocalTimestamps;
+    }
+
+    @UnsupportedAppUsage
+    public void log(String msg) {
+        if (mMaxLines <= 0) {
+            return;
+        }
+        final String logLine;
+        if (mUseLocalTimestamps) {
+            logLine = LocalDateTime.now() + " - " + msg;
+        } else {
+            logLine = Duration.ofMillis(SystemClock.elapsedRealtime())
+                    + " / " + Instant.now() + " - " + msg;
+        }
+        append(logLine);
+    }
+
+    private synchronized void append(String logLine) {
+        while (mLog.size() >= mMaxLines) {
+            mLog.remove();
+        }
+        mLog.add(logLine);
+    }
+
+    @UnsupportedAppUsage
+    public synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        dump(pw);
+    }
+
+    public synchronized void dump(PrintWriter pw) {
+        dump("", pw);
+    }
+
+    /**
+     * Dumps the content of local log to print writer with each log entry predeced with indent
+     *
+     * @param indent indent that precedes each log entry
+     * @param pw printer writer to write into
+     */
+    public synchronized void dump(String indent, PrintWriter pw) {
+        Iterator<String> itr = mLog.iterator();
+        while (itr.hasNext()) {
+            pw.printf("%s%s\n", indent, itr.next());
+        }
+    }
+
+    public synchronized void reverseDump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        reverseDump(pw);
+    }
+
+    public synchronized void reverseDump(PrintWriter pw) {
+        Iterator<String> itr = mLog.descendingIterator();
+        while (itr.hasNext()) {
+            pw.println(itr.next());
+        }
+    }
+
+    // @VisibleForTesting(otherwise = VisibleForTesting.NONE)
+    public synchronized void clear() {
+        mLog.clear();
+    }
+
+    public static class ReadOnlyLocalLog {
+        private final LocalLog mLog;
+        ReadOnlyLocalLog(LocalLog log) {
+            mLog = log;
+        }
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+        public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            mLog.dump(pw);
+        }
+        public void dump(PrintWriter pw) {
+            mLog.dump(pw);
+        }
+        public void reverseDump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            mLog.reverseDump(pw);
+        }
+        public void reverseDump(PrintWriter pw) {
+            mLog.reverseDump(pw);
+        }
+    }
+
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+    public ReadOnlyLocalLog readOnlyLocalLog() {
+        return new ReadOnlyLocalLog(this);
+    }
+}
\ No newline at end of file
diff --git a/packages/Vcn/service-b/service-utils/com/android/internal/util/WakeupMessage.java b/packages/Vcn/service-b/service-utils/com/android/internal/util/WakeupMessage.java
new file mode 100644
index 0000000..7db62f8
--- /dev/null
+++ b/packages/Vcn/service-b/service-utils/com/android/internal/util/WakeupMessage.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2025 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.internal.util;
+
+import android.app.AlarmManager;
+import android.content.Context;
+import android.os.Handler;
+import android.os.Message;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+ /**
+ * An AlarmListener that sends the specified message to a Handler and keeps the system awake until
+ * the message is processed.
+ *
+ * This is useful when using the AlarmManager direct callback interface to wake up the system and
+ * request that an object whose API consists of messages (such as a StateMachine) perform some
+ * action.
+ *
+ * In this situation, using AlarmManager.onAlarmListener by itself will wake up the system to send
+ * the message, but does not guarantee that the system will be awake until the target object has
+ * processed it. This is because as soon as the onAlarmListener sends the message and returns, the
+ * AlarmManager releases its wakelock and the system is free to go to sleep again.
+ */
+// TODO: b/374174952 This is an exact copy of
+// frameworks/base/core/java/com/android/internal/util/WakeupMessage.java.
+// This file is only used in "service-connectivity-b-platform" before the VCN modularization flag
+// is fully ramped. When the flag is fully ramped and the development is finalized, this file can
+// be removed.
+public class WakeupMessage implements AlarmManager.OnAlarmListener {
+    private final AlarmManager mAlarmManager;
+
+    @VisibleForTesting
+    protected final Handler mHandler;
+    @VisibleForTesting
+    protected final String mCmdName;
+    @VisibleForTesting
+    protected final int mCmd, mArg1, mArg2;
+    @VisibleForTesting
+    protected final Object mObj;
+    private final Runnable mRunnable;
+    private boolean mScheduled;
+
+    public WakeupMessage(Context context, Handler handler,
+            String cmdName, int cmd, int arg1, int arg2, Object obj) {
+        mAlarmManager = getAlarmManager(context);
+        mHandler = handler;
+        mCmdName = cmdName;
+        mCmd = cmd;
+        mArg1 = arg1;
+        mArg2 = arg2;
+        mObj = obj;
+        mRunnable = null;
+    }
+
+    public WakeupMessage(Context context, Handler handler, String cmdName, int cmd, int arg1) {
+        this(context, handler, cmdName, cmd, arg1, 0, null);
+    }
+
+    public WakeupMessage(Context context, Handler handler,
+            String cmdName, int cmd, int arg1, int arg2) {
+        this(context, handler, cmdName, cmd, arg1, arg2, null);
+    }
+
+    public WakeupMessage(Context context, Handler handler, String cmdName, int cmd) {
+        this(context, handler, cmdName, cmd, 0, 0, null);
+    }
+
+    public WakeupMessage(Context context, Handler handler, String cmdName, Runnable runnable) {
+        mAlarmManager = getAlarmManager(context);
+        mHandler = handler;
+        mCmdName = cmdName;
+        mCmd = 0;
+        mArg1 = 0;
+        mArg2 = 0;
+        mObj = null;
+        mRunnable = runnable;
+    }
+
+    private static AlarmManager getAlarmManager(Context context) {
+        return (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+    }
+
+    /**
+     * Schedule the message to be delivered at the time in milliseconds of the
+     * {@link android.os.SystemClock#elapsedRealtime SystemClock.elapsedRealtime()} clock and wakeup
+     * the device when it goes off. If schedule is called multiple times without the message being
+     * dispatched then the alarm is rescheduled to the new time.
+     */
+    public synchronized void schedule(long when) {
+        mAlarmManager.setExact(
+                AlarmManager.ELAPSED_REALTIME_WAKEUP, when, mCmdName, this, mHandler);
+        mScheduled = true;
+    }
+
+    /**
+     * Cancel all pending messages. This includes alarms that may have been fired, but have not been
+     * run on the handler yet.
+     */
+    public synchronized void cancel() {
+        if (mScheduled) {
+            mAlarmManager.cancel(this);
+            mScheduled = false;
+        }
+    }
+
+    @Override
+    public void onAlarm() {
+        // Once this method is called the alarm has already been fired and removed from
+        // AlarmManager (it is still partially tracked, but only for statistics). The alarm can now
+        // be marked as unscheduled so that it can be rescheduled in the message handler.
+        final boolean stillScheduled;
+        synchronized (this) {
+            stillScheduled = mScheduled;
+            mScheduled = false;
+        }
+        if (stillScheduled) {
+            Message msg;
+            if (mRunnable == null) {
+                msg = mHandler.obtainMessage(mCmd, mArg1, mArg2, mObj);
+            } else {
+                msg = Message.obtain(mHandler, mRunnable);
+            }
+            mHandler.dispatchMessage(msg);
+            msg.recycle();
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/Vcn/service-b/service-vcn-platform-jarjar-rules.txt b/packages/Vcn/service-b/service-vcn-platform-jarjar-rules.txt
index 3630727..6ec39d9 100644
--- a/packages/Vcn/service-b/service-vcn-platform-jarjar-rules.txt
+++ b/packages/Vcn/service-b/service-vcn-platform-jarjar-rules.txt
@@ -1,5 +1,2 @@
-rule android.util.IndentingPrintWriter android.net.vcn.module.repackaged.android.util.IndentingPrintWriter
 rule android.util.LocalLog android.net.vcn.module.repackaged.android.util.LocalLog
-rule com.android.internal.util.IndentingPrintWriter android.net.vcn.module.repackaged.com.android.internal.util.IndentingPrintWriter
-rule com.android.internal.util.MessageUtils android.net.vcn.module.repackaged.com.android.internal.util.MessageUtils
 rule com.android.internal.util.WakeupMessage android.net.vcn.module.repackaged.com.android.internal.util.WakeupMessage
\ No newline at end of file
diff --git a/services/core/java/com/android/server/BinaryTransparencyService.java b/services/core/java/com/android/server/BinaryTransparencyService.java
index 485bf31..020aed9 100644
--- a/services/core/java/com/android/server/BinaryTransparencyService.java
+++ b/services/core/java/com/android/server/BinaryTransparencyService.java
@@ -1559,7 +1559,7 @@
     private class PackageUpdatedReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
-            if (!intent.getAction().equals(Intent.ACTION_PACKAGE_ADDED)) {
+            if (!Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
                 return;
             }
 
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 286238e..0d0cdd8 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -438,9 +438,9 @@
         }
         LockscreenCredential credential =
                 LockscreenCredential.createUnifiedProfilePassword(newPassword);
-        Arrays.fill(newPasswordChars, '\u0000');
-        Arrays.fill(newPassword, (byte) 0);
-        Arrays.fill(randomLockSeed, (byte) 0);
+        LockPatternUtils.zeroize(newPasswordChars);
+        LockPatternUtils.zeroize(newPassword);
+        LockPatternUtils.zeroize(randomLockSeed);
         return credential;
     }
 
@@ -1537,7 +1537,7 @@
                         + userId);
             }
         } finally {
-            Arrays.fill(password, (byte) 0);
+            LockPatternUtils.zeroize(password);
         }
     }
 
@@ -1570,7 +1570,7 @@
         decryptionResult = cipher.doFinal(encryptedPassword);
         LockscreenCredential credential = LockscreenCredential.createUnifiedProfilePassword(
                 decryptionResult);
-        Arrays.fill(decryptionResult, (byte) 0);
+        LockPatternUtils.zeroize(decryptionResult);
         try {
             long parentSid = getGateKeeperService().getSecureUserId(
                     mUserManager.getProfileParent(userId).id);
@@ -2263,7 +2263,7 @@
         } catch (RemoteException e) {
             Slogf.wtf(TAG, e, "Failed to unlock CE storage for %s user %d", userType, userId);
         } finally {
-            Arrays.fill(secret, (byte) 0);
+            LockPatternUtils.zeroize(secret);
         }
     }
 
diff --git a/services/core/java/com/android/server/locksettings/UnifiedProfilePasswordCache.java b/services/core/java/com/android/server/locksettings/UnifiedProfilePasswordCache.java
index 21caf76..3d64f18 100644
--- a/services/core/java/com/android/server/locksettings/UnifiedProfilePasswordCache.java
+++ b/services/core/java/com/android/server/locksettings/UnifiedProfilePasswordCache.java
@@ -26,6 +26,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.widget.LockPatternUtils;
 import com.android.internal.widget.LockscreenCredential;
 
 import java.security.GeneralSecurityException;
@@ -154,7 +155,7 @@
             }
             LockscreenCredential result =
                     LockscreenCredential.createUnifiedProfilePassword(credential);
-            Arrays.fill(credential, (byte) 0);
+            LockPatternUtils.zeroize(credential);
             return result;
         }
     }
@@ -175,7 +176,7 @@
                 Slog.d(TAG, "Cannot delete key", e);
             }
             if (mEncryptedPasswords.contains(userId)) {
-                Arrays.fill(mEncryptedPasswords.get(userId), (byte) 0);
+                LockPatternUtils.zeroize(mEncryptedPasswords.get(userId));
                 mEncryptedPasswords.remove(userId);
             }
         }
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
index bf1b3c3..85dc811 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
@@ -162,7 +162,7 @@
             Log.e(TAG, "Unexpected exception thrown during KeySyncTask", e);
         } finally {
             if (mCredential != null) {
-                Arrays.fill(mCredential, (byte) 0); // no longer needed.
+                LockPatternUtils.zeroize(mCredential); // no longer needed.
             }
         }
     }
@@ -506,7 +506,7 @@
 
         try {
             byte[] hash = MessageDigest.getInstance(LOCK_SCREEN_HASH_ALGORITHM).digest(bytes);
-            Arrays.fill(bytes, (byte) 0);
+            LockPatternUtils.zeroize(bytes);
             return hash;
         } catch (NoSuchAlgorithmException e) {
             // Impossible, SHA-256 must be supported on Android.
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
index 54303c0..7d8300a 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
@@ -1082,7 +1082,7 @@
             int keyguardCredentialsType = lockPatternUtilsToKeyguardType(savedCredentialType);
             try (LockscreenCredential credential =
                     createLockscreenCredential(keyguardCredentialsType, decryptedCredentials)) {
-                Arrays.fill(decryptedCredentials, (byte) 0);
+                LockPatternUtils.zeroize(decryptedCredentials);
                 decryptedCredentials = null;
                 VerifyCredentialResponse verifyResponse =
                         lockSettingsService.verifyCredential(credential, userId, 0);
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverySessionStorage.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverySessionStorage.java
index 0e66746..f1ef333 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverySessionStorage.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverySessionStorage.java
@@ -19,8 +19,9 @@
 import android.annotation.Nullable;
 import android.util.SparseArray;
 
+import com.android.internal.widget.LockPatternUtils;
+
 import java.util.ArrayList;
-import java.util.Arrays;
 
 import javax.security.auth.Destroyable;
 
@@ -187,8 +188,8 @@
          */
         @Override
         public void destroy() {
-            Arrays.fill(mLskfHash, (byte) 0);
-            Arrays.fill(mKeyClaimant, (byte) 0);
+            LockPatternUtils.zeroize(mLskfHash);
+            LockPatternUtils.zeroize(mKeyClaimant);
         }
     }
 }
diff --git a/services/core/java/com/android/server/media/TEST_MAPPING b/services/core/java/com/android/server/media/TEST_MAPPING
index 43e2afd..dbf9915 100644
--- a/services/core/java/com/android/server/media/TEST_MAPPING
+++ b/services/core/java/com/android/server/media/TEST_MAPPING
@@ -1,7 +1,10 @@
 {
   "presubmit": [
     {
-      "name": "CtsMediaBetterTogetherTestCases"
+      "name": "CtsMediaRouterTestCases"
+    },
+    {
+      "name": "CtsMediaSessionTestCases"
     },
     {
       "name": "MediaRouterServiceTests"
diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java
index 14539d5..50db1e4 100644
--- a/services/core/java/com/android/server/rollback/RollbackStore.java
+++ b/services/core/java/com/android/server/rollback/RollbackStore.java
@@ -84,8 +84,12 @@
      */
     private static List<Rollback> loadRollbacks(File rollbackDataDir) {
         List<Rollback> rollbacks = new ArrayList<>();
-        rollbackDataDir.mkdirs();
-        for (File rollbackDir : rollbackDataDir.listFiles()) {
+        File[] rollbackDirs = rollbackDataDir.listFiles();
+        if (rollbackDirs == null) {
+            Slog.e(TAG, "Folder doesn't exist: " + rollbackDataDir);
+            return rollbacks;
+        }
+        for (File rollbackDir : rollbackDirs) {
             if (rollbackDir.isDirectory()) {
                 try {
                     rollbacks.add(loadRollback(rollbackDir));
diff --git a/services/core/java/com/android/server/stats/pull/AggregatedMobileDataStatsPuller.java b/services/core/java/com/android/server/stats/pull/AggregatedMobileDataStatsPuller.java
index 2088e41..3831352 100644
--- a/services/core/java/com/android/server/stats/pull/AggregatedMobileDataStatsPuller.java
+++ b/services/core/java/com/android/server/stats/pull/AggregatedMobileDataStatsPuller.java
@@ -142,11 +142,8 @@
     private final RateLimiter mRateLimiter;
 
     AggregatedMobileDataStatsPuller(@NonNull NetworkStatsManager networkStatsManager) {
-        if (DEBUG) {
-            if (Trace.isTagEnabled(Trace.TRACE_TAG_SYSTEM_SERVER)) {
-                Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER,
-                        TAG + "-AggregatedMobileDataStatsPullerInit");
-            }
+        if (DEBUG && Trace.isTagEnabled(Trace.TRACE_TAG_SYSTEM_SERVER)) {
+            Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, TAG + "-Init");
         }
 
         mRateLimiter = new RateLimiter(/* window= */ Duration.ofSeconds(1));
@@ -173,10 +170,16 @@
 
     public void noteUidProcessState(int uid, int state, long unusedElapsedRealtime,
                                     long unusedUptime) {
-        mMobileDataStatsHandler.post(
+        if (mRateLimiter.tryAcquire()) {
+            mMobileDataStatsHandler.post(
                 () -> {
                     noteUidProcessStateImpl(uid, state);
                 });
+        } else {
+            synchronized (mLock) {
+                mUidPreviousState.put(uid, state);
+            }
+        }
     }
 
     public int pullDataBytesTransfer(List<StatsEvent> data) {
@@ -209,29 +212,27 @@
     }
 
     private void noteUidProcessStateImpl(int uid, int state) {
-        if (mRateLimiter.tryAcquire()) {
-            // noteUidProcessStateImpl can be called back to back several times while
-            // the updateNetworkStats loops over several stats for multiple uids
-            // and during the first call in a batch of proc state change event it can
-            // contain info for uid with unknown previous state yet which can happen due to a few
-            // reasons:
-            // - app was just started
-            // - app was started before the ActivityManagerService
-            // as result stats would be created with state == ActivityManager.PROCESS_STATE_UNKNOWN
-            if (mNetworkStatsManager != null) {
-                updateNetworkStats(mNetworkStatsManager);
-            } else {
-                Slog.w(TAG, "noteUidProcessStateLocked() can not get mNetworkStatsManager");
-            }
+        // noteUidProcessStateImpl can be called back to back several times while
+        // the updateNetworkStats loops over several stats for multiple uids
+        // and during the first call in a batch of proc state change event it can
+        // contain info for uid with unknown previous state yet which can happen due to a few
+        // reasons:
+        // - app was just started
+        // - app was started before the ActivityManagerService
+        // as result stats would be created with state == ActivityManager.PROCESS_STATE_UNKNOWN
+        if (mNetworkStatsManager != null) {
+            updateNetworkStats(mNetworkStatsManager);
+        } else {
+            Slog.w(TAG, "noteUidProcessStateLocked() can not get mNetworkStatsManager");
         }
-        mUidPreviousState.put(uid, state);
+        synchronized (mLock) {
+            mUidPreviousState.put(uid, state);
+        }
     }
 
     private void updateNetworkStats(NetworkStatsManager networkStatsManager) {
-        if (DEBUG) {
-            if (Trace.isTagEnabled(Trace.TRACE_TAG_SYSTEM_SERVER)) {
-                Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, TAG + "-updateNetworkStats");
-            }
+        if (DEBUG && Trace.isTagEnabled(Trace.TRACE_TAG_SYSTEM_SERVER)) {
+            Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, TAG + "-updateNetworkStats");
         }
 
         final NetworkStats latestStats = networkStatsManager.getMobileUidStats();
@@ -256,20 +257,25 @@
     }
 
     private void updateNetworkStatsDelta(NetworkStats delta) {
+        if (DEBUG && Trace.isTagEnabled(Trace.TRACE_TAG_SYSTEM_SERVER)) {
+            Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, TAG + "-updateNetworkStatsDelta");
+        }
         synchronized (mLock) {
             for (NetworkStats.Entry entry : delta) {
-                if (entry.getRxPackets() == 0 && entry.getTxPackets() == 0) {
-                    continue;
-                }
-                MobileDataStats stats = getUidStatsForPreviousStateLocked(entry.getUid());
-                if (stats != null) {
-                    stats.addTxBytes(entry.getTxBytes());
-                    stats.addRxBytes(entry.getRxBytes());
-                    stats.addTxPackets(entry.getTxPackets());
-                    stats.addRxPackets(entry.getRxPackets());
+                if (entry.getRxPackets() != 0 || entry.getTxPackets() != 0) {
+                    MobileDataStats stats = getUidStatsForPreviousStateLocked(entry.getUid());
+                    if (stats != null) {
+                        stats.addTxBytes(entry.getTxBytes());
+                        stats.addRxBytes(entry.getRxBytes());
+                        stats.addTxPackets(entry.getTxPackets());
+                        stats.addRxPackets(entry.getRxPackets());
+                    }
                 }
             }
         }
+        if (DEBUG) {
+            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+        }
     }
 
     @GuardedBy("mLock")
@@ -298,18 +304,12 @@
     }
 
     private static boolean isEmpty(NetworkStats stats) {
-        long totalRxPackets = 0;
-        long totalTxPackets = 0;
         for (NetworkStats.Entry entry : stats) {
-            if (entry.getRxPackets() == 0 && entry.getTxPackets() == 0) {
-                continue;
+            if (entry.getRxPackets() != 0 || entry.getTxPackets() != 0) {
+                // at least one non empty entry located
+                return false;
             }
-            totalRxPackets += entry.getRxPackets();
-            totalTxPackets += entry.getTxPackets();
-            // at least one non empty entry located
-            break;
         }
-        final long totalPackets = totalRxPackets + totalTxPackets;
-        return totalPackets == 0;
+        return true;
     }
 }
diff --git a/services/core/java/com/android/server/wm/SnapshotPersistQueue.java b/services/core/java/com/android/server/wm/SnapshotPersistQueue.java
index 1c8c245..67f4e56 100644
--- a/services/core/java/com/android/server/wm/SnapshotPersistQueue.java
+++ b/services/core/java/com/android/server/wm/SnapshotPersistQueue.java
@@ -354,10 +354,8 @@
             bitmap.recycle();
 
             final File file = mPersistInfoProvider.getHighResolutionBitmapFile(mId, mUserId);
-            try {
-                FileOutputStream fos = new FileOutputStream(file);
+            try (FileOutputStream fos = new FileOutputStream(file)) {
                 swBitmap.compress(JPEG, COMPRESS_QUALITY, fos);
-                fos.close();
             } catch (IOException e) {
                 Slog.e(TAG, "Unable to open " + file + " for persisting.", e);
                 return false;
@@ -375,10 +373,8 @@
             swBitmap.recycle();
 
             final File lowResFile = mPersistInfoProvider.getLowResolutionBitmapFile(mId, mUserId);
-            try {
-                FileOutputStream lowResFos = new FileOutputStream(lowResFile);
+            try (FileOutputStream lowResFos = new FileOutputStream(lowResFile)) {
                 lowResBitmap.compress(JPEG, COMPRESS_QUALITY, lowResFos);
-                lowResFos.close();
             } catch (IOException e) {
                 Slog.e(TAG, "Unable to open " + lowResFile + " for persisting.", e);
                 return false;
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index dd5f613..1058a25 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -1371,6 +1371,7 @@
                         if (!tr.isAttached() || !tr.isVisibleRequested()
                                 || !tr.inPinnedWindowingMode()) return;
                         final ActivityRecord currTop = tr.getTopNonFinishingActivity();
+                        if (currTop == null) return;
                         if (currTop.inPinnedWindowingMode()) return;
                         Slog.e(TAG, "Enter-PIP was started but not completed, this is a Shell/SysUI"
                                 + " bug. This state breaks gesture-nav, so attempting clean-up.");
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index e4da389..4f9b1cc 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -9926,9 +9926,10 @@
             throw new SecurityException("Access denied to process: " + pid
                     + ", must have permission " + Manifest.permission.ACCESS_FPS_COUNTER);
         }
-
-        if (mRoot.anyTaskForId(taskId) == null) {
-            throw new IllegalArgumentException("no task with taskId: " + taskId);
+        synchronized (mGlobalLock) {
+            if (mRoot.anyTaskForId(taskId) == null) {
+                throw new IllegalArgumentException("no task with taskId: " + taskId);
+            }
         }
 
         mTaskFpsCallbackController.registerListener(taskId, callback);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/OWNERS b/services/tests/servicestests/src/com/android/server/accessibility/OWNERS
index b74281e..c824c39 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/OWNERS
+++ b/services/tests/servicestests/src/com/android/server/accessibility/OWNERS
@@ -1 +1,3 @@
+# Bug component: 44215
+
 include /core/java/android/view/accessibility/OWNERS