Merge "Remove stale profile from CredentialManager" into main
diff --git a/config/Android.bp b/config/Android.bp
index 6a6f848..dd681ca 100644
--- a/config/Android.bp
+++ b/config/Android.bp
@@ -33,3 +33,9 @@
     name: "preloaded-classes-denylist",
     srcs: ["preloaded-classes-denylist"],
 }
+
+prebuilt_etc {
+    name: "dirty-image-objects",
+    src: "dirty-image-objects",
+    filename: "dirty-image-objects",
+}
diff --git a/core/api/current.txt b/core/api/current.txt
index 48949f8..588396a 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -31980,7 +31980,7 @@
     field public static final int S_V2 = 32; // 0x20
     field public static final int TIRAMISU = 33; // 0x21
     field public static final int UPSIDE_DOWN_CAKE = 34; // 0x22
-    field @FlaggedApi("android.os.android_os_build_vanilla_ice_cream") public static final int VANILLA_ICE_CREAM = 10000; // 0x2710
+    field public static final int VANILLA_ICE_CREAM = 10000; // 0x2710
   }
 
   public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable {
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 1ac887b..5330fef 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -968,6 +968,7 @@
         boolean autoStopProfiler;
         boolean streamingOutput;
         int mClockType;
+        int mProfilerOutputVersion;
         boolean profiling;
         boolean handlingProfiling;
         public void setProfiler(ProfilerInfo profilerInfo) {
@@ -995,6 +996,7 @@
             autoStopProfiler = profilerInfo.autoStopProfiler;
             streamingOutput = profilerInfo.streamingOutput;
             mClockType = profilerInfo.clockType;
+            mProfilerOutputVersion = profilerInfo.profilerOutputVersion;
         }
         public void startProfiling() {
             if (profileFd == null || profiling) {
@@ -1002,9 +1004,11 @@
             }
             try {
                 int bufferSize = SystemProperties.getInt("debug.traceview-buffer-size-mb", 8);
+                int flags = 0;
+                flags = mClockType | ProfilerInfo.getFlagsForOutputVersion(mProfilerOutputVersion);
                 VMDebug.startMethodTracing(profileFile, profileFd.getFileDescriptor(),
-                        bufferSize * 1024 * 1024, mClockType, samplingInterval != 0,
-                        samplingInterval, streamingOutput);
+                        bufferSize * 1024 * 1024, flags, samplingInterval != 0, samplingInterval,
+                        streamingOutput);
                 profiling = true;
             } catch (RuntimeException e) {
                 Slog.w(TAG, "Profiling failed on path " + profileFile, e);
@@ -7052,6 +7056,7 @@
             mProfiler.autoStopProfiler = data.initProfilerInfo.autoStopProfiler;
             mProfiler.streamingOutput = data.initProfilerInfo.streamingOutput;
             mProfiler.mClockType = data.initProfilerInfo.clockType;
+            mProfiler.mProfilerOutputVersion = data.initProfilerInfo.profilerOutputVersion;
             if (data.initProfilerInfo.attachAgentDuringBind) {
                 agent = data.initProfilerInfo.agent;
             }
diff --git a/core/java/android/app/ProfilerInfo.java b/core/java/android/app/ProfilerInfo.java
index f7a3d78..bcae22a 100644
--- a/core/java/android/app/ProfilerInfo.java
+++ b/core/java/android/app/ProfilerInfo.java
@@ -32,7 +32,8 @@
  * {@hide}
  */
 public class ProfilerInfo implements Parcelable {
-
+    // Version of the profiler output
+    public static final int OUTPUT_VERSION_DEFAULT = 1;
     // CLOCK_TYPE_DEFAULT chooses the default used by ART. ART uses CLOCK_TYPE_DUAL by default (see
     // kDefaultTraceClockSource in art/runtime/runtime_globals.h).
     public static final int CLOCK_TYPE_DEFAULT = 0x000;
@@ -43,6 +44,9 @@
     public static final int CLOCK_TYPE_WALL = 0x010;
     public static final int CLOCK_TYPE_THREAD_CPU = 0x100;
     public static final int CLOCK_TYPE_DUAL = 0x110;
+    // The second and third bits of the flags field specify the trace format version. This should
+    // match with kTraceFormatVersionShift defined in art/runtime/trace.h.
+    public static final int TRACE_FORMAT_VERSION_SHIFT = 1;
 
     private static final String TAG = "ProfilerInfo";
 
@@ -83,8 +87,14 @@
      */
     public final int clockType;
 
+    /**
+     * Indicates the version of profiler output.
+     */
+    public final int profilerOutputVersion;
+
     public ProfilerInfo(String filename, ParcelFileDescriptor fd, int interval, boolean autoStop,
-            boolean streaming, String agent, boolean attachAgentDuringBind, int clockType) {
+            boolean streaming, String agent, boolean attachAgentDuringBind, int clockType,
+            int profilerOutputVersion) {
         profileFile = filename;
         profileFd = fd;
         samplingInterval = interval;
@@ -93,6 +103,7 @@
         this.clockType = clockType;
         this.agent = agent;
         this.attachAgentDuringBind = attachAgentDuringBind;
+        this.profilerOutputVersion = profilerOutputVersion;
     }
 
     public ProfilerInfo(ProfilerInfo in) {
@@ -104,6 +115,7 @@
         agent = in.agent;
         attachAgentDuringBind = in.attachAgentDuringBind;
         clockType = in.clockType;
+        profilerOutputVersion = in.profilerOutputVersion;
     }
 
     /**
@@ -125,13 +137,29 @@
     }
 
     /**
+     * Get the flags that need to be passed to VMDebug.startMethodTracing to specify the desired
+     * output format.
+     */
+    public static int getFlagsForOutputVersion(int version) {
+        // Only two version 1 and version 2 are supported. Just use the default if we see an unknown
+        // version.
+        if (version != 1 || version != 2) {
+            version = OUTPUT_VERSION_DEFAULT;
+        }
+
+        // The encoded version in the flags starts from 0, where as the version that we read from
+        // user starts from 1. So, subtract one before encoding it in the flags.
+        return (version - 1) << TRACE_FORMAT_VERSION_SHIFT;
+    }
+
+    /**
      * Return a new ProfilerInfo instance, with fields populated from this object,
      * and {@link agent} and {@link attachAgentDuringBind} as given.
      */
     public ProfilerInfo setAgent(String agent, boolean attachAgentDuringBind) {
         return new ProfilerInfo(this.profileFile, this.profileFd, this.samplingInterval,
                 this.autoStopProfiler, this.streamingOutput, agent, attachAgentDuringBind,
-                this.clockType);
+                this.clockType, this.profilerOutputVersion);
     }
 
     /**
@@ -172,6 +200,7 @@
         out.writeString(agent);
         out.writeBoolean(attachAgentDuringBind);
         out.writeInt(clockType);
+        out.writeInt(profilerOutputVersion);
     }
 
     /** @hide */
@@ -186,6 +215,7 @@
         proto.write(ProfilerInfoProto.STREAMING_OUTPUT, streamingOutput);
         proto.write(ProfilerInfoProto.AGENT, agent);
         proto.write(ProfilerInfoProto.CLOCK_TYPE, clockType);
+        proto.write(ProfilerInfoProto.PROFILER_OUTPUT_VERSION, profilerOutputVersion);
         proto.end(token);
     }
 
@@ -211,6 +241,7 @@
         agent = in.readString();
         attachAgentDuringBind = in.readBoolean();
         clockType = in.readInt();
+        profilerOutputVersion = in.readInt();
     }
 
     @Override
@@ -226,9 +257,9 @@
         return Objects.equals(profileFile, other.profileFile)
                 && autoStopProfiler == other.autoStopProfiler
                 && samplingInterval == other.samplingInterval
-                && streamingOutput == other.streamingOutput
-                && Objects.equals(agent, other.agent)
-                && clockType == other.clockType;
+                && streamingOutput == other.streamingOutput && Objects.equals(agent, other.agent)
+                && clockType == other.clockType
+                && profilerOutputVersion == other.profilerOutputVersion;
     }
 
     @Override
@@ -240,6 +271,7 @@
         result = 31 * result + (streamingOutput ? 1 : 0);
         result = 31 * result + Objects.hashCode(agent);
         result = 31 * result + clockType;
+        result = 31 * result + profilerOutputVersion;
         return result;
     }
 }
diff --git a/core/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java b/core/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java
index d681a2c..d1531a1 100644
--- a/core/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java
+++ b/core/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtils.java
@@ -162,12 +162,21 @@
         result.putInt(IP_VERSION_KEY, params.getIpVersion());
         result.putInt(ENCAP_TYPE_KEY, params.getEncapType());
 
-        // TODO: b/185941731 Make sure IkeSessionParamsUtils is automatically updated when a new
-        // IKE_OPTION is defined in IKE module and added in the IkeSessionParams
         final List<Integer> enabledIkeOptions = new ArrayList<>();
-        for (int option : IKE_OPTIONS) {
-            if (isIkeOptionValid(option) && params.hasIkeOption(option)) {
-                enabledIkeOptions.add(option);
+
+        try {
+            // TODO: b/328844044: Ideally this code should gate the behavior by checking the
+            // com.android.ipsec.flags.enabled_ike_options_api flag but that flag is not accessible
+            // right now. We should either update the code when the flag is accessible or remove the
+            // legacy behavior after VIC SDK finalization
+            enabledIkeOptions.addAll(params.getIkeOptions());
+        } catch (Exception e) {
+            // getIkeOptions throws. It means the API is not available
+            enabledIkeOptions.clear();
+            for (int option : IKE_OPTIONS) {
+                if (isIkeOptionValid(option) && params.hasIkeOption(option)) {
+                    enabledIkeOptions.add(option);
+                }
             }
         }
 
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 5871717..a7d17f5 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -17,7 +17,6 @@
 package android.os;
 
 import android.Manifest;
-import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -1228,7 +1227,6 @@
         /**
          * Vanilla Ice Cream.
          */
-        @FlaggedApi(Flags.FLAG_ANDROID_OS_BUILD_VANILLA_ICE_CREAM)
         public static final int VANILLA_ICE_CREAM = CUR_DEVELOPMENT;
     }
 
diff --git a/core/proto/android/app/profilerinfo.proto b/core/proto/android/app/profilerinfo.proto
index 86261ec..9941b83 100644
--- a/core/proto/android/app/profilerinfo.proto
+++ b/core/proto/android/app/profilerinfo.proto
@@ -36,4 +36,5 @@
     // Denotes an agent (and its parameters) to attach for profiling.
     optional string agent = 6;
     optional int32 clock_type = 7;
+    optional int32 profiler_output_version = 8;
 }
diff --git a/core/tests/FileSystemUtilsTest/TEST_MAPPING b/core/tests/FileSystemUtilsTest/TEST_MAPPING
index 89b3a7a..d41e981 100644
--- a/core/tests/FileSystemUtilsTest/TEST_MAPPING
+++ b/core/tests/FileSystemUtilsTest/TEST_MAPPING
@@ -1,5 +1,5 @@
 {
-  "postsubmit": [
+  "presubmit": [
     {
       "name": "FileSystemUtilsTests"
     }
diff --git a/core/tests/coretests/src/android/tracing/OWNERS b/core/tests/coretests/src/android/tracing/OWNERS
new file mode 100644
index 0000000..86a7e88
--- /dev/null
+++ b/core/tests/coretests/src/android/tracing/OWNERS
@@ -0,0 +1 @@
+include platform/development:/tools/winscope/OWNERS
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/OWNERS b/libs/WindowManager/Shell/OWNERS
index e346b51..58d692d 100644
--- a/libs/WindowManager/Shell/OWNERS
+++ b/libs/WindowManager/Shell/OWNERS
@@ -1,4 +1,4 @@
 xutan@google.com
 
 # Give submodule owners in shell resource approval
-per-file res*/*/*.xml = atsjenk@google.com, hwwang@google.com, jorgegil@google.com, lbill@google.com, madym@google.com, nmusgrave@google.com, pbdr@google.com, tkachenkoi@google.com
+per-file res*/*/*.xml = atsjenk@google.com, hwwang@google.com, jorgegil@google.com, lbill@google.com, madym@google.com, nmusgrave@google.com, pbdr@google.com, tkachenkoi@google.com, mpodolian@google.com, liranb@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/OWNERS
index ec09827..afddfab 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/OWNERS
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/OWNERS
@@ -1,3 +1,2 @@
 # WM shell sub-module pip owner
 hwwang@google.com
-mateuszc@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/OWNERS
index 6dabb3b..79d1793 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/OWNERS
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/OWNERS
@@ -1,4 +1,3 @@
 # WM shell sub-module pip owner
 hwwang@google.com
-mateuszc@google.com
 gabiyev@google.com
diff --git a/location/Android.bp b/location/Android.bp
index eb7cd01..5ba35ac 100644
--- a/location/Android.bp
+++ b/location/Android.bp
@@ -26,6 +26,7 @@
         "com.android.internal.location",
     ],
     libs: [
+        "android.location.flags-aconfig-java",
         "app-compat-annotations",
         "unsupportedappusage", // for android.compat.annotation.UnsupportedAppUsage
     ],
diff --git a/location/TEST_MAPPING b/location/TEST_MAPPING
index f5deb2b..10da632 100644
--- a/location/TEST_MAPPING
+++ b/location/TEST_MAPPING
@@ -2,12 +2,7 @@
   "presubmit": [
     {
       "name": "CtsLocationFineTestCases",
-      "options": [
-          {
-             // TODO: Wait for test to deflake - b/293934372
-             "exclude-filter":"android.location.cts.fine.ScanningSettingsTest"
-          }
-      ]
+      "options": []
     },
     {
       "name": "CtsLocationCoarseTestCases"
diff --git a/location/api/current.txt b/location/api/current.txt
index 0c23d8c..589e9b7 100644
--- a/location/api/current.txt
+++ b/location/api/current.txt
@@ -412,8 +412,8 @@
     field public static final int TYPE_GPS_L1CA = 257; // 0x101
     field public static final int TYPE_GPS_L2CNAV = 258; // 0x102
     field public static final int TYPE_GPS_L5CNAV = 259; // 0x103
-    field @FlaggedApi(Flags.FLAG_GNSS_API_NAVIC_L1) public static final int TYPE_IRN_L1 = 1795; // 0x703
-    field @FlaggedApi(Flags.FLAG_GNSS_API_NAVIC_L1) public static final int TYPE_IRN_L5 = 1794; // 0x702
+    field @FlaggedApi("android.location.flags.gnss_api_navic_l1") public static final int TYPE_IRN_L1 = 1795; // 0x703
+    field @FlaggedApi("android.location.flags.gnss_api_navic_l1") public static final int TYPE_IRN_L5 = 1794; // 0x702
     field @Deprecated public static final int TYPE_IRN_L5CA = 1793; // 0x701
     field public static final int TYPE_QZS_L1CA = 1025; // 0x401
     field public static final int TYPE_SBS = 513; // 0x201
diff --git a/location/api/system-current.txt b/location/api/system-current.txt
index b1cf96d..075fbb1 100644
--- a/location/api/system-current.txt
+++ b/location/api/system-current.txt
@@ -113,13 +113,13 @@
   }
 
   public final class GnssMeasurementRequest implements android.os.Parcelable {
-    method @FlaggedApi(Flags.FLAG_GNSS_API_MEASUREMENT_REQUEST_WORK_SOURCE) @NonNull public android.os.WorkSource getWorkSource();
+    method @FlaggedApi("android.location.flags.gnss_api_measurement_request_work_source") @NonNull public android.os.WorkSource getWorkSource();
     method public boolean isCorrelationVectorOutputsEnabled();
   }
 
   public static final class GnssMeasurementRequest.Builder {
     method @NonNull public android.location.GnssMeasurementRequest.Builder setCorrelationVectorOutputsEnabled(boolean);
-    method @FlaggedApi(Flags.FLAG_GNSS_API_MEASUREMENT_REQUEST_WORK_SOURCE) @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.location.GnssMeasurementRequest.Builder setWorkSource(@Nullable android.os.WorkSource);
+    method @FlaggedApi("android.location.flags.gnss_api_measurement_request_work_source") @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.location.GnssMeasurementRequest.Builder setWorkSource(@Nullable android.os.WorkSource);
   }
 
   public final class GnssReflectingPlane implements android.os.Parcelable {
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 17c4a77..4708db2 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -5230,6 +5230,13 @@
         setParameters(keys, values);
     }
 
+    private void logAndRun(String message, Runnable r) {
+        final String TAG = "MediaCodec";
+        android.util.Log.d(TAG, "enter: " + message);
+        r.run();
+        android.util.Log.d(TAG, "exit : " + message);
+    }
+
     /**
      * Sets an asynchronous callback for actionable MediaCodec events.
      *
@@ -5259,14 +5266,40 @@
                 // even if we were to extend this to be callable dynamically, it must
                 // be called when codec is flushed, so no messages are pending.
                 if (newHandler != mCallbackHandler) {
-                    mCallbackHandler.removeMessages(EVENT_SET_CALLBACK);
-                    mCallbackHandler.removeMessages(EVENT_CALLBACK);
+                    if (android.media.codec.Flags.setCallbackStall()) {
+                        logAndRun(
+                                "[new handler] removeMessages(SET_CALLBACK)",
+                                () -> {
+                                    mCallbackHandler.removeMessages(EVENT_SET_CALLBACK);
+                                });
+                        logAndRun(
+                                "[new handler] removeMessages(CALLBACK)",
+                                () -> {
+                                    mCallbackHandler.removeMessages(EVENT_CALLBACK);
+                                });
+                    } else {
+                        mCallbackHandler.removeMessages(EVENT_SET_CALLBACK);
+                        mCallbackHandler.removeMessages(EVENT_CALLBACK);
+                    }
                     mCallbackHandler = newHandler;
                 }
             }
         } else if (mCallbackHandler != null) {
-            mCallbackHandler.removeMessages(EVENT_SET_CALLBACK);
-            mCallbackHandler.removeMessages(EVENT_CALLBACK);
+            if (android.media.codec.Flags.setCallbackStall()) {
+                logAndRun(
+                        "[null handler] removeMessages(SET_CALLBACK)",
+                        () -> {
+                            mCallbackHandler.removeMessages(EVENT_SET_CALLBACK);
+                        });
+                logAndRun(
+                        "[null handler] removeMessages(CALLBACK)",
+                        () -> {
+                            mCallbackHandler.removeMessages(EVENT_CALLBACK);
+                        });
+            } else {
+                mCallbackHandler.removeMessages(EVENT_SET_CALLBACK);
+                mCallbackHandler.removeMessages(EVENT_CALLBACK);
+            }
         }
 
         if (mCallbackHandler != null) {
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 4f9917b..8a13c03 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -2099,9 +2099,14 @@
         }
         if (i == 0) {
             *initialOffset = offset;
+            if (CC_UNLIKELY(*initialOffset < 0)) {
+                if (errorDetailMsg) {
+                    *errorDetailMsg = "Error: offset/size in BufferInfo";
+                }
+                return BAD_VALUE;
+            }
         }
-        if (CC_UNLIKELY((offset >  UINT32_MAX)
-                || ((long)(offset + size) > UINT32_MAX)
+        if (CC_UNLIKELY(((ssize_t)(UINT32_MAX - offset) < (ssize_t)size)
                 || ((offset - *initialOffset) != *totalSize))) {
             if (errorDetailMsg) {
                 *errorDetailMsg = "Error: offset/size in BufferInfo";
diff --git a/packages/CrashRecovery/services/java/com/android/utils/ArrayUtils.java b/packages/CrashRecovery/services/java/com/android/utils/ArrayUtils.java
deleted file mode 100644
index fa4d6af..0000000
--- a/packages/CrashRecovery/services/java/com/android/utils/ArrayUtils.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * 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.utils;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-
-import java.io.File;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * Copied over from frameworks/base/core/java/com/android/internal/util/ArrayUtils.java
- *
- * @hide
- */
-public class ArrayUtils {
-    private ArrayUtils() { /* cannot be instantiated */ }
-    public static final File[] EMPTY_FILE = new File[0];
-
-
-    /**
-     * Return first index of {@code value} in {@code array}, or {@code -1} if
-     * not found.
-     */
-    public static <T> int indexOf(@Nullable T[] array, T value) {
-        if (array == null) return -1;
-        for (int i = 0; i < array.length; i++) {
-            if (Objects.equals(array[i], value)) return i;
-        }
-        return -1;
-    }
-
-    /** @hide */
-    public static @NonNull File[] defeatNullable(@Nullable File[] val) {
-        return (val != null) ? val : EMPTY_FILE;
-    }
-
-    /**
-     * Checks if given array is null or has zero elements.
-     */
-    public static boolean isEmpty(@Nullable int[] array) {
-        return array == null || array.length == 0;
-    }
-
-    /**
-     * True if the byte array is null or has length 0.
-     */
-    public static boolean isEmpty(@Nullable byte[] array) {
-        return array == null || array.length == 0;
-    }
-
-    /**
-     * Converts from List of bytes to byte array
-     * @param list
-     * @return byte[]
-     */
-    public static byte[] toPrimitive(List<byte[]> list) {
-        if (list.size() == 0) {
-            return new byte[0];
-        }
-        int byteLen = list.get(0).length;
-        byte[] array = new byte[list.size() * byteLen];
-        for (int i = 0; i < list.size(); i++) {
-            for (int j = 0; j < list.get(i).length; j++) {
-                array[i * byteLen + j] = list.get(i)[j];
-            }
-        }
-        return array;
-    }
-
-    /**
-     * Adds value to given array if not already present, providing set-like
-     * behavior.
-     */
-    public static @NonNull int[] appendInt(@Nullable int[] cur, int val) {
-        return appendInt(cur, val, false);
-    }
-
-    /**
-     * Adds value to given array.
-     */
-    public static @NonNull int[] appendInt(@Nullable int[] cur, int val,
-            boolean allowDuplicates) {
-        if (cur == null) {
-            return new int[] { val };
-        }
-        final int n = cur.length;
-        if (!allowDuplicates) {
-            for (int i = 0; i < n; i++) {
-                if (cur[i] == val) {
-                    return cur;
-                }
-            }
-        }
-        int[] ret = new int[n + 1];
-        System.arraycopy(cur, 0, ret, 0, n);
-        ret[n] = val;
-        return ret;
-    }
-}
diff --git a/packages/CrashRecovery/services/java/com/android/utils/BackgroundThread.java b/packages/CrashRecovery/services/java/com/android/utils/BackgroundThread.java
deleted file mode 100644
index afcf689..0000000
--- a/packages/CrashRecovery/services/java/com/android/utils/BackgroundThread.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- *  * 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.utils;
-
-import android.annotation.NonNull;
-import android.os.Handler;
-import android.os.HandlerThread;
-
-import com.android.internal.annotations.GuardedBy;
-
-import java.util.concurrent.Executor;
-
-/**
- * Thread for asynchronous event processing. This thread is configured as
- * {@link android.os.Process#THREAD_PRIORITY_BACKGROUND}, which means fewer CPU
- * resources will be dedicated to it, and it will "have less chance of impacting
- * the responsiveness of the user interface."
- * <p>
- * This thread is best suited for tasks that the user is not actively waiting
- * for, or for tasks that the user expects to be executed eventually.
- *
- * @see com.android.internal.os.BackgroundThread
- *
- * TODO: b/326916057 depend on modules-utils-backgroundthread instead
- * @hide
- */
-public final class BackgroundThread extends HandlerThread {
-    private static final Object sLock = new Object();
-
-    @GuardedBy("sLock")
-    private static BackgroundThread sInstance;
-    @GuardedBy("sLock")
-    private static Handler sHandler;
-    @GuardedBy("sLock")
-    private static HandlerExecutor sHandlerExecutor;
-
-    private BackgroundThread() {
-        super(BackgroundThread.class.getName(), android.os.Process.THREAD_PRIORITY_BACKGROUND);
-    }
-
-    @GuardedBy("sLock")
-    private static void ensureThreadLocked() {
-        if (sInstance == null) {
-            sInstance = new BackgroundThread();
-            sInstance.start();
-            sHandler = new Handler(sInstance.getLooper());
-            sHandlerExecutor = new HandlerExecutor(sHandler);
-        }
-    }
-
-    /**
-     * Get the singleton instance of this class.
-     *
-     * @return the singleton instance of this class
-     */
-    @NonNull
-    public static BackgroundThread get() {
-        synchronized (sLock) {
-            ensureThreadLocked();
-            return sInstance;
-        }
-    }
-
-    /**
-     * Get the singleton {@link Handler} for this class.
-     *
-     * @return the singleton {@link Handler} for this class.
-     */
-    @NonNull
-    public static Handler getHandler() {
-        synchronized (sLock) {
-            ensureThreadLocked();
-            return sHandler;
-        }
-    }
-
-    /**
-     * Get the singleton {@link Executor} for this class.
-     *
-     * @return the singleton {@link Executor} for this class.
-     */
-    @NonNull
-    public static Executor getExecutor() {
-        synchronized (sLock) {
-            ensureThreadLocked();
-            return sHandlerExecutor;
-        }
-    }
-}
diff --git a/packages/CrashRecovery/services/java/com/android/utils/FileUtils.java b/packages/CrashRecovery/services/java/com/android/utils/FileUtils.java
deleted file mode 100644
index e4923bf..0000000
--- a/packages/CrashRecovery/services/java/com/android/utils/FileUtils.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * 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.utils;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-
-import java.io.BufferedInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * Bits and pieces copied from hidden API of android.os.FileUtils.
- *
- * @hide
- */
-public class FileUtils {
-    /**
-     * Read a text file into a String, optionally limiting the length.
-     *
-     * @param file     to read (will not seek, so things like /proc files are OK)
-     * @param max      length (positive for head, negative of tail, 0 for no limit)
-     * @param ellipsis to add of the file was truncated (can be null)
-     * @return the contents of the file, possibly truncated
-     * @throws IOException if something goes wrong reading the file
-     * @hide
-     */
-    public static @Nullable String readTextFile(@Nullable File file, @Nullable int max,
-            @Nullable String ellipsis) throws IOException {
-        InputStream input = new FileInputStream(file);
-        // wrapping a BufferedInputStream around it because when reading /proc with unbuffered
-        // input stream, bytes read not equal to buffer size is not necessarily the correct
-        // indication for EOF; but it is true for BufferedInputStream due to its implementation.
-        BufferedInputStream bis = new BufferedInputStream(input);
-        try {
-            long size = file.length();
-            if (max > 0 || (size > 0 && max == 0)) {  // "head" mode: read the first N bytes
-                if (size > 0 && (max == 0 || size < max)) max = (int) size;
-                byte[] data = new byte[max + 1];
-                int length = bis.read(data);
-                if (length <= 0) return "";
-                if (length <= max) return new String(data, 0, length);
-                if (ellipsis == null) return new String(data, 0, max);
-                return new String(data, 0, max) + ellipsis;
-            } else if (max < 0) {  // "tail" mode: keep the last N
-                int len;
-                boolean rolled = false;
-                byte[] last = null;
-                byte[] data = null;
-                do {
-                    if (last != null) rolled = true;
-                    byte[] tmp = last;
-                    last = data;
-                    data = tmp;
-                    if (data == null) data = new byte[-max];
-                    len = bis.read(data);
-                } while (len == data.length);
-
-                if (last == null && len <= 0) return "";
-                if (last == null) return new String(data, 0, len);
-                if (len > 0) {
-                    rolled = true;
-                    System.arraycopy(last, len, last, 0, last.length - len);
-                    System.arraycopy(data, 0, last, last.length - len, len);
-                }
-                if (ellipsis == null || !rolled) return new String(last);
-                return ellipsis + new String(last);
-            } else {  // "cat" mode: size unknown, read it all in streaming fashion
-                ByteArrayOutputStream contents = new ByteArrayOutputStream();
-                int len;
-                byte[] data = new byte[1024];
-                do {
-                    len = bis.read(data);
-                    if (len > 0) contents.write(data, 0, len);
-                } while (len == data.length);
-                return contents.toString();
-            }
-        } finally {
-            bis.close();
-            input.close();
-        }
-    }
-
-    /**
-     * Perform an fsync on the given FileOutputStream. The stream at this
-     * point must be flushed but not yet closed.
-     *
-     * @hide
-     */
-    public static boolean sync(FileOutputStream stream) {
-        try {
-            if (stream != null) {
-                stream.getFD().sync();
-            }
-            return true;
-        } catch (IOException e) {
-        }
-        return false;
-    }
-
-    /**
-     * List the files in the directory or return empty file.
-     *
-     * @hide
-     */
-    public static @NonNull File[] listFilesOrEmpty(@Nullable File dir) {
-        return (dir != null) ? ArrayUtils.defeatNullable(dir.listFiles())
-            : ArrayUtils.EMPTY_FILE;
-    }
-}
diff --git a/packages/CrashRecovery/services/java/com/android/utils/HandlerExecutor.java b/packages/CrashRecovery/services/java/com/android/utils/HandlerExecutor.java
deleted file mode 100644
index fdb15e2..0000000
--- a/packages/CrashRecovery/services/java/com/android/utils/HandlerExecutor.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.utils;
-
-import android.annotation.NonNull;
-import android.os.Handler;
-
-import java.util.Objects;
-import java.util.concurrent.Executor;
-import java.util.concurrent.RejectedExecutionException;
-
-/**
- * An adapter {@link Executor} that posts all executed tasks onto the given
- * {@link Handler}.
- *
- * TODO: b/326916057 depend on modules-utils-backgroundthread instead
- * @hide
- */
-public class HandlerExecutor implements Executor {
-    private final Handler mHandler;
-
-    public HandlerExecutor(@NonNull Handler handler) {
-        mHandler = Objects.requireNonNull(handler);
-    }
-
-    @Override
-    public void execute(Runnable command) {
-        if (!mHandler.post(command)) {
-            throw new RejectedExecutionException(mHandler + " is shutting down");
-        }
-    }
-}
diff --git a/packages/CrashRecovery/services/java/com/android/utils/LongArrayQueue.java b/packages/CrashRecovery/services/java/com/android/utils/LongArrayQueue.java
deleted file mode 100644
index 5cdc253..0000000
--- a/packages/CrashRecovery/services/java/com/android/utils/LongArrayQueue.java
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * 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.utils;
-
-import libcore.util.EmptyArray;
-
-import java.util.NoSuchElementException;
-
-/**
- * Copied from frameworks/base/core/java/android/util/LongArrayQueue.java
- *
- * @hide
- */
-public class LongArrayQueue {
-
-    private long[] mValues;
-    private int mSize;
-    private int mHead;
-    private int mTail;
-
-    private long[] newUnpaddedLongArray(int num) {
-        return new long[num];
-    }
-    /**
-     * Initializes a queue with the given starting capacity.
-     *
-     * @param initialCapacity the capacity.
-     */
-    public LongArrayQueue(int initialCapacity) {
-        if (initialCapacity == 0) {
-            mValues = EmptyArray.LONG;
-        } else {
-            mValues = newUnpaddedLongArray(initialCapacity);
-        }
-        mSize = 0;
-        mHead = mTail = 0;
-    }
-
-    /**
-     * Initializes a queue with default starting capacity.
-     */
-    public LongArrayQueue() {
-        this(16);
-    }
-
-    /** @hide */
-    public static int growSize(int currentSize) {
-        return currentSize <= 4 ? 8 : currentSize * 2;
-    }
-
-    private void grow() {
-        if (mSize < mValues.length) {
-            throw new IllegalStateException("Queue not full yet!");
-        }
-        final int newSize = growSize(mSize);
-        final long[] newArray = newUnpaddedLongArray(newSize);
-        final int r = mValues.length - mHead; // Number of elements on and to the right of head.
-        System.arraycopy(mValues, mHead, newArray, 0, r);
-        System.arraycopy(mValues, 0, newArray, r, mHead);
-        mValues = newArray;
-        mHead = 0;
-        mTail = mSize;
-    }
-
-    /**
-     * Returns the number of elements in the queue.
-     */
-    public int size() {
-        return mSize;
-    }
-
-    /**
-     * Removes all elements from this queue.
-     */
-    public void clear() {
-        mSize = 0;
-        mHead = mTail = 0;
-    }
-
-    /**
-     * Adds a value to the tail of the queue.
-     *
-     * @param value the value to be added.
-     */
-    public void addLast(long value) {
-        if (mSize == mValues.length) {
-            grow();
-        }
-        mValues[mTail] = value;
-        mTail = (mTail + 1) % mValues.length;
-        mSize++;
-    }
-
-    /**
-     * Removes an element from the head of the queue.
-     *
-     * @return the element at the head of the queue.
-     * @throws NoSuchElementException if the queue is empty.
-     */
-    public long removeFirst() {
-        if (mSize == 0) {
-            throw new NoSuchElementException("Queue is empty!");
-        }
-        final long ret = mValues[mHead];
-        mHead = (mHead + 1) % mValues.length;
-        mSize--;
-        return ret;
-    }
-
-    /**
-     * Returns the element at the given position from the head of the queue, where 0 represents the
-     * head of the queue.
-     *
-     * @param position the position from the head of the queue.
-     * @return the element found at the given position.
-     * @throws IndexOutOfBoundsException if {@code position} < {@code 0} or
-     *                                   {@code position} >= {@link #size()}
-     */
-    public long get(int position) {
-        if (position < 0 || position >= mSize) {
-            throw new IndexOutOfBoundsException("Index " + position
-                + " not valid for a queue of size " + mSize);
-        }
-        final int index = (mHead + position) % mValues.length;
-        return mValues[index];
-    }
-
-    /**
-     * Returns the element at the head of the queue, without removing it.
-     *
-     * @return the element at the head of the queue.
-     * @throws NoSuchElementException if the queue is empty
-     */
-    public long peekFirst() {
-        if (mSize == 0) {
-            throw new NoSuchElementException("Queue is empty!");
-        }
-        return mValues[mHead];
-    }
-
-    /**
-     * Returns the element at the tail of the queue.
-     *
-     * @return the element at the tail of the queue.
-     * @throws NoSuchElementException if the queue is empty.
-     */
-    public long peekLast() {
-        if (mSize == 0) {
-            throw new NoSuchElementException("Queue is empty!");
-        }
-        final int index = (mTail == 0) ? mValues.length - 1 : mTail - 1;
-        return mValues[index];
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public String toString() {
-        if (mSize <= 0) {
-            return "{}";
-        }
-
-        final StringBuilder buffer = new StringBuilder(mSize * 64);
-        buffer.append('{');
-        buffer.append(get(0));
-        for (int i = 1; i < mSize; i++) {
-            buffer.append(", ");
-            buffer.append(get(i));
-        }
-        buffer.append('}');
-        return buffer.toString();
-    }
-}
diff --git a/packages/CrashRecovery/services/java/com/android/utils/XmlUtils.java b/packages/CrashRecovery/services/java/com/android/utils/XmlUtils.java
deleted file mode 100644
index dbbef61..0000000
--- a/packages/CrashRecovery/services/java/com/android/utils/XmlUtils.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * 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.utils;
-
-import android.annotation.NonNull;
-import android.system.ErrnoException;
-import android.system.Os;
-
-import com.android.modules.utils.TypedXmlPullParser;
-
-import libcore.util.XmlObjectFactory;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.BufferedInputStream;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * Copied over partly from frameworks/base/core/java/com/android/internal/util/XmlUtils.java
- *
- * @hide
- */
-public class XmlUtils {
-
-    private static final String STRING_ARRAY_SEPARATOR = ":";
-
-    /** @hide */
-    public static final void beginDocument(XmlPullParser parser, String firstElementName)
-            throws XmlPullParserException, IOException {
-        int type;
-        while ((type = parser.next()) != parser.START_TAG
-            && type != parser.END_DOCUMENT) {
-            // Do nothing
-        }
-
-        if (type != parser.START_TAG) {
-            throw new XmlPullParserException("No start tag found");
-        }
-
-        if (!parser.getName().equals(firstElementName)) {
-            throw new XmlPullParserException("Unexpected start tag: found " + parser.getName()
-                + ", expected " + firstElementName);
-        }
-    }
-
-    /** @hide */
-    public static boolean nextElementWithin(XmlPullParser parser, int outerDepth)
-            throws IOException, XmlPullParserException {
-        for (;;) {
-            int type = parser.next();
-            if (type == XmlPullParser.END_DOCUMENT
-                    || (type == XmlPullParser.END_TAG && parser.getDepth() == outerDepth)) {
-                return false;
-            }
-            if (type == XmlPullParser.START_TAG
-                    && parser.getDepth() == outerDepth + 1) {
-                return true;
-            }
-        }
-    }
-
-    private static XmlPullParser newPullParser() {
-        try {
-            XmlPullParser parser = XmlObjectFactory.newXmlPullParser();
-            parser.setFeature(XmlPullParser.FEATURE_PROCESS_DOCDECL, true);
-            parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
-            return parser;
-        } catch (XmlPullParserException e) {
-            throw new AssertionError();
-        }
-    }
-
-    /** @hide */
-    public static @NonNull TypedXmlPullParser resolvePullParser(@NonNull InputStream in)
-            throws IOException {
-        final byte[] magic = new byte[4];
-        if (in instanceof FileInputStream) {
-            try {
-                Os.pread(((FileInputStream) in).getFD(), magic, 0, magic.length, 0);
-            } catch (ErrnoException e) {
-                throw e.rethrowAsIOException();
-            }
-        } else {
-            if (!in.markSupported()) {
-                in = new BufferedInputStream(in);
-            }
-            in.mark(8);
-            in.read(magic);
-            in.reset();
-        }
-
-        final TypedXmlPullParser xml;
-        xml = (TypedXmlPullParser) newPullParser();
-        try {
-            xml.setInput(in, "UTF_8");
-        } catch (XmlPullParserException e) {
-            throw new IOException(e);
-        }
-        return xml;
-    }
-}
diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS
index 78cacec..796e391 100644
--- a/packages/SystemUI/OWNERS
+++ b/packages/SystemUI/OWNERS
@@ -60,7 +60,6 @@
 lynhan@google.com
 madym@google.com
 mankoff@google.com
-mateuszc@google.com
 matiashe@google.com
 mgalhardo@google.com
 michaelmikhil@google.com
diff --git a/packages/CrashRecovery/services/java/com/android/server/ExplicitHealthCheckController.java b/services/core/java/com/android/server/ExplicitHealthCheckController.java
similarity index 100%
rename from packages/CrashRecovery/services/java/com/android/server/ExplicitHealthCheckController.java
rename to services/core/java/com/android/server/ExplicitHealthCheckController.java
diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS
index bdc4a7a..2545620 100644
--- a/services/core/java/com/android/server/OWNERS
+++ b/services/core/java/com/android/server/OWNERS
@@ -22,6 +22,7 @@
 per-file *Battery* = file:/BATTERY_STATS_OWNERS
 per-file *BinaryTransparency* = file:/core/java/android/transparency/OWNERS
 per-file *Binder* = file:/core/java/com/android/internal/os/BINDER_OWNERS
+per-file ExplicitHealthCheckController.java = file:/services/core/java/com/android/server/crashrecovery/OWNERS
 per-file *Gnss* = file:/services/core/java/com/android/server/location/OWNERS
 per-file **IpSec* = file:/services/core/java/com/android/server/net/OWNERS
 per-file **IpSec* = file:/services/core/java/com/android/server/vcn/OWNERS
@@ -35,9 +36,9 @@
 per-file GestureLauncherService.java = file:platform/packages/apps/EmergencyInfo:/OWNERS
 per-file MmsServiceBroker.java = file:/telephony/OWNERS
 per-file NetIdManager.java = file:/services/core/java/com/android/server/net/OWNERS
-per-file PackageWatchdog.java, RescueParty.java = file:/services/core/java/com/android/server/rollback/OWNERS
+per-file PackageWatchdog.java = file:/services/core/java/com/android/server/crashrecovery/OWNERS
 per-file PinnerService.java = file:/core/java/android/app/pinner/OWNERS
-per-file RescueParty.java = shuc@google.com, ancr@google.com, harshitmahajan@google.com
+per-file RescueParty.java = file:/services/core/java/com/android/server/crashrecovery/OWNERS
 per-file SensitiveContentProtectionManagerService.java = file:/core/java/android/permission/OWNERS
 per-file SystemClockTime.java = file:/services/core/java/com/android/server/timedetector/OWNERS
 per-file SystemTimeZone.java = file:/services/core/java/com/android/server/timezonedetector/OWNERS
diff --git a/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
similarity index 99%
rename from packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java
rename to services/core/java/com/android/server/PackageWatchdog.java
index 75a8bdf..6f20adf 100644
--- a/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -39,15 +39,15 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.AtomicFile;
+import android.util.LongArrayQueue;
 import android.util.Slog;
 import android.util.Xml;
-import android.utils.BackgroundThread;
-import android.utils.LongArrayQueue;
-import android.utils.XmlUtils;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.XmlUtils;
 import com.android.modules.utils.TypedXmlPullParser;
 import com.android.modules.utils.TypedXmlSerializer;
 
diff --git a/packages/CrashRecovery/services/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java
similarity index 99%
rename from packages/CrashRecovery/services/java/com/android/server/RescueParty.java
rename to services/core/java/com/android/server/RescueParty.java
index f86eb61..271d552 100644
--- a/packages/CrashRecovery/services/java/com/android/server/RescueParty.java
+++ b/services/core/java/com/android/server/RescueParty.java
@@ -31,6 +31,7 @@
 import android.crashrecovery.flags.Flags;
 import android.os.Build;
 import android.os.Environment;
+import android.os.FileUtils;
 import android.os.PowerManager;
 import android.os.RecoverySystem;
 import android.os.SystemClock;
@@ -43,11 +44,10 @@
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.Slog;
-import android.utils.ArrayUtils;
-import android.utils.FileUtils;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
 import com.android.server.PackageWatchdog.FailureReasons;
 import com.android.server.PackageWatchdog.PackageHealthObserver;
 import com.android.server.PackageWatchdog.PackageHealthObserverImpact;
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 2b35231..0ff0264 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -146,7 +146,6 @@
 import com.android.internal.os.SomeArgs;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.DumpUtils;
-import com.android.internal.util.HexDump;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
 import com.android.modules.utils.TypedXmlPullParser;
@@ -3270,7 +3269,7 @@
             throws RemoteException {
         super.setCeStorageProtection_enforcePermission();
 
-        mVold.setCeStorageProtection(userId, HexDump.toHexString(secret));
+        mVold.setCeStorageProtection(userId, secret);
     }
 
     /* Only for use by LockSettingsService */
@@ -3280,7 +3279,7 @@
         super.unlockCeStorage_enforcePermission();
 
         if (StorageManager.isFileEncrypted()) {
-            mVold.unlockCeStorage(userId, HexDump.toHexString(secret));
+            mVold.unlockCeStorage(userId, secret);
         }
         synchronized (mLock) {
             mCeUnlockedUsers.append(userId);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index d35892e..28d840b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -13496,6 +13496,8 @@
             // Goodbye!
             removePidLocked(pid, app);
             mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
+            mHandler.removeMessages(BIND_APPLICATION_TIMEOUT_SOFT_MSG, app);
+            mHandler.removeMessages(BIND_APPLICATION_TIMEOUT_HARD_MSG, app);
             mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid);
             if (app.isolated) {
                 mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid);
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index de039fb..c13f02e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -173,6 +173,8 @@
     private static final DateTimeFormatter LOG_NAME_TIME_FORMATTER =
             DateTimeFormatter.ofPattern("yyyyMMdd-HHmmss", Locale.ROOT);
 
+    private static final String PROFILER_OUTPUT_VERSION_FLAG = "--profiler-output-version";
+
     // IPC interface to activity manager -- don't need to do additional security checks.
     final IActivityManager mInterface;
     final IActivityTaskManager mTaskInterface;
@@ -198,6 +200,7 @@
     private String mAgent;  // Agent to attach on startup.
     private boolean mAttachAgentDuringBind;  // Whether agent should be attached late.
     private int mClockType; // Whether we need thread cpu / wall clock / both.
+    private int mProfilerOutputVersion; // The version of the profiler output.
     private int mDisplayId;
     private int mTaskDisplayAreaFeatureId;
     private int mWindowingMode;
@@ -526,6 +529,8 @@
                 } else if (opt.equals("--clock-type")) {
                     String clock_type = getNextArgRequired();
                     mClockType = ProfilerInfo.getClockTypeFromString(clock_type);
+                } else if (opt.equals(PROFILER_OUTPUT_VERSION_FLAG)) {
+                    mProfilerOutputVersion = Integer.parseInt(getNextArgRequired());
                 } else if (opt.equals("--streaming")) {
                     mStreaming = true;
                 } else if (opt.equals("--attach-agent")) {
@@ -578,7 +583,7 @@
                 } else if (opt.equals("--splashscreen-show-icon")) {
                     mShowSplashScreen = true;
                 } else if (opt.equals("--dismiss-keyguard-if-insecure")
-                      || opt.equals("--dismiss-keyguard")) {
+                        || opt.equals("--dismiss-keyguard")) {
                     mDismissKeyguardIfInsecure = true;
                 } else {
                     return false;
@@ -684,8 +689,9 @@
                         return 1;
                     }
                 }
-                profilerInfo = new ProfilerInfo(mProfileFile, fd, mSamplingInterval, mAutoStop,
-                        mStreaming, mAgent, mAttachAgentDuringBind, mClockType);
+                profilerInfo =
+                        new ProfilerInfo(mProfileFile, fd, mSamplingInterval, mAutoStop, mStreaming,
+                                mAgent, mAttachAgentDuringBind, mClockType, mProfilerOutputVersion);
             }
 
             pw.println("Starting: " + intent);
@@ -1028,6 +1034,7 @@
         mSamplingInterval = 0;
         mStreaming = false;
         mClockType = ProfilerInfo.CLOCK_TYPE_DEFAULT;
+        mProfilerOutputVersion = ProfilerInfo.OUTPUT_VERSION_DEFAULT;
 
         String process = null;
 
@@ -1042,6 +1049,8 @@
                 } else if (opt.equals("--clock-type")) {
                     String clock_type = getNextArgRequired();
                     mClockType = ProfilerInfo.getClockTypeFromString(clock_type);
+                } else if (opt.equals(PROFILER_OUTPUT_VERSION_FLAG)) {
+                    mProfilerOutputVersion = Integer.parseInt(getNextArgRequired());
                 } else if (opt.equals("--streaming")) {
                     mStreaming = true;
                 } else if (opt.equals("--sampling")) {
@@ -1089,7 +1098,7 @@
                 return -1;
             }
             profilerInfo = new ProfilerInfo(profileFile, fd, mSamplingInterval, false, mStreaming,
-                    null, false, mClockType);
+                    null, false, mClockType, mProfilerOutputVersion);
         }
 
         if (!mInterface.profileControl(process, userId, start, profilerInfo, profileType)) {
@@ -4177,6 +4186,7 @@
             pw.println("      Print this help text.");
             pw.println("  start-activity [-D] [-N] [-W] [-P <FILE>] [--start-profiler <FILE>]");
             pw.println("          [--sampling INTERVAL] [--clock-type <TYPE>] [--streaming]");
+            pw.println("          [" + PROFILER_OUTPUT_VERSION_FLAG + " NUMBER]");
             pw.println("          [-R COUNT] [-S] [--track-allocation]");
             pw.println("          [--user <USER_ID> | current] [--suspend] <INTENT>");
             pw.println("      Start an Activity.  Options are:");
@@ -4192,6 +4202,8 @@
             pw.println("          The default value is dual. (use with --start-profiler)");
             pw.println("      --streaming: stream the profiling output to the specified file");
             pw.println("          (use with --start-profiler)");
+            pw.println("      " + PROFILER_OUTPUT_VERSION_FLAG + " Specify the version of the");
+            pw.println("          profiling output (use with --start-profiler)");
             pw.println("      -P <FILE>: like above, but profiling stops when app goes idle");
             pw.println("      --attach-agent <agent>: attach the given agent before binding");
             pw.println("      --attach-agent-bind <agent>: attach the given agent during binding");
@@ -4283,6 +4295,7 @@
             pw.println("      --dump-file <FILE>: Specify the file the trace should be dumped to.");
             pw.println("  profile start [--user <USER_ID> current]");
             pw.println("          [--clock-type <TYPE>]");
+            pw.println("          [" + PROFILER_OUTPUT_VERSION_FLAG + " VERSION]");
             pw.println("          [--sampling INTERVAL | --streaming] <PROCESS> <FILE>");
             pw.println("      Start profiler on a process.  The given <PROCESS> argument");
             pw.println("        may be either a process name or pid.  Options are:");
@@ -4292,6 +4305,8 @@
             pw.println("      --clock-type <TYPE>: use the specified clock to report timestamps.");
             pw.println("          The type can be one of wall | thread-cpu | dual. The default");
             pw.println("          value is dual.");
+            pw.println("      " + PROFILER_OUTPUT_VERSION_FLAG + "VERSION: specifies the output");
+            pw.println("          format version");
             pw.println("      --sampling INTERVAL: use sample profiling with INTERVAL microseconds");
             pw.println("          between samples.");
             pw.println("      --streaming: stream the profiling output to the specified file.");
diff --git a/services/core/java/com/android/server/am/AppProfiler.java b/services/core/java/com/android/server/am/AppProfiler.java
index 9b091b3..1dab8c7 100644
--- a/services/core/java/com/android/server/am/AppProfiler.java
+++ b/services/core/java/com/android/server/am/AppProfiler.java
@@ -2484,8 +2484,8 @@
                     }
                 }
             } else if (instr != null && instr.mProfileFile != null) {
-                profilerInfo = new ProfilerInfo(instr.mProfileFile, null, 0, false, false,
-                        null, false, 0);
+                profilerInfo = new ProfilerInfo(instr.mProfileFile, null, 0, false, false, null,
+                        false, 0, ProfilerInfo.OUTPUT_VERSION_DEFAULT);
             }
             if (mAppAgentMap != null && mAppAgentMap.containsKey(processName)) {
                 // We need to do a debuggable check here. See setAgentApp for why the check is
@@ -2495,7 +2495,8 @@
                     // Do not overwrite already requested agent.
                     if (profilerInfo == null) {
                         profilerInfo = new ProfilerInfo(null, null, 0, false, false,
-                                mAppAgentMap.get(processName), true, 0);
+                                mAppAgentMap.get(processName), true, 0,
+                                ProfilerInfo.OUTPUT_VERSION_DEFAULT);
                     } else if (profilerInfo.agent == null) {
                         profilerInfo = profilerInfo.setAgent(mAppAgentMap.get(processName), true);
                     }
@@ -2622,14 +2623,16 @@
                 if (mProfileData.getProfilerInfo() != null) {
                     pw.println("  mProfileFile=" + mProfileData.getProfilerInfo().profileFile
                             + " mProfileFd=" + mProfileData.getProfilerInfo().profileFd);
-                    pw.println("  mSamplingInterval="
-                            + mProfileData.getProfilerInfo().samplingInterval
+                    pw.println(
+                            "  mSamplingInterval=" + mProfileData.getProfilerInfo().samplingInterval
                             + " mAutoStopProfiler="
                             + mProfileData.getProfilerInfo().autoStopProfiler
                             + " mStreamingOutput="
                             + mProfileData.getProfilerInfo().streamingOutput
                             + " mClockType="
-                            + mProfileData.getProfilerInfo().clockType);
+                            + mProfileData.getProfilerInfo().clockType
+                            + " mProfilerOutputVersion="
+                            + mProfileData.getProfilerInfo().profilerOutputVersion);
                     pw.println("  mProfileType=" + mProfileType);
                 }
             }
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index bccbee9..d10223f 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -848,8 +848,10 @@
 
             Slog.d(TAG, "resetLockout(userId=" + userId
                     + ", hat=" + (hardwareAuthToken == null ? "null " : "present") + ")");
-            mBiometricContext.getAuthSessionCoordinator()
+            mHandler.post(() -> {
+                mBiometricContext.getAuthSessionCoordinator()
                     .resetLockoutFor(userId, Authenticators.BIOMETRIC_STRONG, -1);
+            });
         }
 
         @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthSessionCoordinator.java b/services/core/java/com/android/server/biometrics/sensors/AuthSessionCoordinator.java
index d9947dd..dc2eff4 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthSessionCoordinator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthSessionCoordinator.java
@@ -235,7 +235,7 @@
             mApiCallNumber = 0;
         }
 
-        void addApiCall(String str) {
+        synchronized void addApiCall(String str) {
             mApiCalls[mCurr] = str;
             mCurr++;
             mCurr %= mSize;
@@ -243,7 +243,7 @@
         }
 
         @Override
-        public String toString() {
+        public synchronized String toString() {
             String buffer = "";
             int apiCall = mApiCallNumber > mSize ? mApiCallNumber - mSize : 0;
             for (int i = 0; i < mSize; i++) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerNative.java b/services/core/java/com/android/server/pm/PackageManagerNative.java
index d035084..66ecd6e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerNative.java
+++ b/services/core/java/com/android/server/pm/PackageManagerNative.java
@@ -68,6 +68,11 @@
         }
     }
 
+    @Override
+    public int getPackageUid(String packageName, long flags, int userId) throws RemoteException {
+        return mPm.snapshotComputer().getPackageUid(packageName, flags, userId);
+    }
+
     // NB: this differentiates between preloads and sideloads
     @Override
     public String getInstallerForPackage(String packageName) throws RemoteException {
diff --git a/services/core/java/com/android/server/power/batterysaver/TEST_MAPPING b/services/core/java/com/android/server/power/batterysaver/TEST_MAPPING
index c091b8e..eb91a72 100644
--- a/services/core/java/com/android/server/power/batterysaver/TEST_MAPPING
+++ b/services/core/java/com/android/server/power/batterysaver/TEST_MAPPING
@@ -5,12 +5,7 @@
     },
     {
       "name": "CtsLocationFineTestCases",
-      "options": [
-          {
-             // TODO: Wait for test to deflake - b/293934372
-             "exclude-filter":"android.location.cts.fine.ScanningSettingsTest"
-          }
-      ]
+      "options": []
     },
     {
       "name": "CtsLocationNoneTestCases"
diff --git a/packages/CrashRecovery/services/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
similarity index 100%
rename from packages/CrashRecovery/services/java/com/android/server/rollback/RollbackPackageHealthObserver.java
rename to services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
diff --git a/packages/CrashRecovery/services/java/com/android/server/rollback/WatchdogRollbackLogger.java b/services/core/java/com/android/server/rollback/WatchdogRollbackLogger.java
similarity index 100%
rename from packages/CrashRecovery/services/java/com/android/server/rollback/WatchdogRollbackLogger.java
rename to services/core/java/com/android/server/rollback/WatchdogRollbackLogger.java
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/CasResource.java b/services/core/java/com/android/server/tv/tunerresourcemanager/CasResource.java
index 4a81c95..440d251 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/CasResource.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/CasResource.java
@@ -89,8 +89,34 @@
      * @param ownerId the removing client id of the owner.
      */
     public void removeOwner(int ownerId) {
-        mAvailableSessionNum += mOwnerClientIdsToSessionNum.get(ownerId);
-        mOwnerClientIdsToSessionNum.remove(ownerId);
+        if (mOwnerClientIdsToSessionNum.containsKey(ownerId)) {
+            mAvailableSessionNum += mOwnerClientIdsToSessionNum.get(ownerId);
+            mOwnerClientIdsToSessionNum.remove(ownerId);
+        }
+    }
+
+    /**
+     * Remove a single session from resource
+     *
+     * @param ownerId the client Id of the owner of the session
+     */
+    public void removeSession(int ownerId) {
+        if (mOwnerClientIdsToSessionNum.containsKey(ownerId)) {
+            int sessionNum = mOwnerClientIdsToSessionNum.get(ownerId);
+            if (sessionNum > 0) {
+                mOwnerClientIdsToSessionNum.put(ownerId, --sessionNum);
+                mAvailableSessionNum++;
+            }
+        }
+    }
+
+    /**
+     * Check if there are any open sessions owned by a client
+     *
+     * @param ownerId the client Id of the owner of the sessions
+     */
+    public boolean hasOpenSessions(int ownerId) {
+        return mOwnerClientIdsToSessionNum.get(ownerId) > 0;
     }
 
     public Set<Integer> getOwnerClientIds() {
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
index cddc79d..0afb049 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
@@ -1924,11 +1924,13 @@
         ownerProfile.useCiCam(grantingId);
     }
 
-    private void updateCasClientMappingOnRelease(
-            @NonNull CasResource releasingCas, int ownerClientId) {
-        ClientProfile ownerProfile = getClientProfile(ownerClientId);
-        releasingCas.removeOwner(ownerClientId);
-        ownerProfile.releaseCas();
+    private void updateCasClientMappingOnRelease(@NonNull CasResource cas, int ownerClientId) {
+        cas.removeSession(ownerClientId);
+        if (!cas.hasOpenSessions(ownerClientId)) {
+            ClientProfile ownerProfile = getClientProfile(ownerClientId);
+            cas.removeOwner(ownerClientId);
+            ownerProfile.releaseCas();
+        }
     }
 
     private void updateCiCamClientMappingOnRelease(
diff --git a/services/core/java/com/android/server/vcn/Vcn.java b/services/core/java/com/android/server/vcn/Vcn.java
index 37f0450..5a5f7ef 100644
--- a/services/core/java/com/android/server/vcn/Vcn.java
+++ b/services/core/java/com/android/server/vcn/Vcn.java
@@ -626,8 +626,12 @@
      * Dumps the state of this Vcn for logging and debugging purposes.
      *
      * <p>PII and credentials MUST NEVER be dumped here.
+     *
+     * <p>This method is not thread safe and MUST run on the VCN thread.
      */
     public void dump(IndentingPrintWriter pw) {
+        mVcnContext.ensureRunningOnLooperThread();
+
         pw.println("Vcn (" + mSubscriptionGroup + "):");
         pw.increaseIndent();
 
diff --git a/services/core/java/com/android/server/vcn/VcnContext.java b/services/core/java/com/android/server/vcn/VcnContext.java
index 1383708..6a4c9c2 100644
--- a/services/core/java/com/android/server/vcn/VcnContext.java
+++ b/services/core/java/com/android/server/vcn/VcnContext.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.content.Context;
+import android.net.IpSecTransformState;
 import android.net.vcn.FeatureFlags;
 import android.net.vcn.FeatureFlagsImpl;
 import android.os.Looper;
@@ -34,7 +35,6 @@
     @NonNull private final Looper mLooper;
     @NonNull private final VcnNetworkProvider mVcnNetworkProvider;
     @NonNull private final FeatureFlags mFeatureFlags;
-    @NonNull private final android.net.platform.flags.FeatureFlags mCoreNetFeatureFlags;
     private final boolean mIsInTestMode;
 
     public VcnContext(
@@ -49,7 +49,6 @@
 
         // Auto-generated class
         mFeatureFlags = new FeatureFlagsImpl();
-        mCoreNetFeatureFlags = new android.net.platform.flags.FeatureFlagsImpl();
     }
 
     @NonNull
@@ -76,7 +75,16 @@
     }
 
     public boolean isFlagIpSecTransformStateEnabled() {
-        return mCoreNetFeatureFlags.ipsecTransformState();
+        // TODO: b/328844044: Ideally this code should gate the behavior by checking the
+        // android.net.platform.flags.ipsec_transform_state flag but that flag is not accessible
+        // right now. We should either update the code when the flag is accessible or remove the
+        // legacy behavior after VIC SDK finalization
+        try {
+            new IpSecTransformState.Builder();
+            return true;
+        } catch (Exception e) {
+            return false;
+        }
     }
 
     @NonNull
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 3094b18..8d378a0 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -2580,8 +2580,12 @@
      * Dumps the state of this VcnGatewayConnection for logging and debugging purposes.
      *
      * <p>PII and credentials MUST NEVER be dumped here.
+     *
+     * <p>This method is not thread safe and MUST run on the VCN thread.
      */
     public void dump(IndentingPrintWriter pw) {
+        mVcnContext.ensureRunningOnLooperThread();
+
         pw.println("VcnGatewayConnection (" + mConnectionConfig.getGatewayConnectionName() + "):");
         pw.increaseIndent();
 
@@ -2602,6 +2606,19 @@
         mUnderlyingNetworkController.dump(pw);
         pw.println();
 
+        if (mIkeSession == null) {
+            pw.println("mIkeSession: null");
+        } else {
+            pw.println("mIkeSession:");
+
+            // Add a try catch block in case IkeSession#dump is not thread-safe
+            try {
+                mIkeSession.dump(pw);
+            } catch (Exception e) {
+                Slog.wtf(TAG, "Failed to dump IkeSession: " + e);
+            }
+        }
+
         pw.decreaseIndent();
     }
 
@@ -2905,6 +2922,11 @@
         public void setNetwork(@NonNull Network network) {
             mImpl.setNetwork(network);
         }
+
+        /** Dumps the state of the IkeSession */
+        public void dump(@NonNull IndentingPrintWriter pw) {
+            mImpl.dump(pw);
+        }
     }
 
     /** Proxy Implementation of WakeLock, used for testing. */
diff --git a/services/core/java/com/android/server/wm/OWNERS b/services/core/java/com/android/server/wm/OWNERS
index 79eb0dc..ce47f5c 100644
--- a/services/core/java/com/android/server/wm/OWNERS
+++ b/services/core/java/com/android/server/wm/OWNERS
@@ -26,3 +26,6 @@
 
 # File related to activity callers
 per-file ActivityCallerState.java = file:/core/java/android/app/COMPONENT_CALLER_OWNERS
+
+# Files related to tracing
+per-file *TransitionTracer.java = file:platform/development:/tools/winscope/OWNERS
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
index 1fdf97a..093923f 100644
--- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -45,13 +45,13 @@
 import android.platform.test.flag.junit.SetFlagsRule;
 import android.provider.DeviceConfig;
 import android.util.AtomicFile;
+import android.util.LongArrayQueue;
 import android.util.Xml;
-import android.utils.LongArrayQueue;
-import android.utils.XmlUtils;
 
 import androidx.test.InstrumentationRegistry;
 
 import com.android.dx.mockito.inline.extended.ExtendedMockito;
+import com.android.internal.util.XmlUtils;
 import com.android.modules.utils.TypedXmlPullParser;
 import com.android.modules.utils.TypedXmlSerializer;
 import com.android.server.PackageWatchdog.HealthCheckState;
diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java
index 6189fb0..edad678 100644
--- a/tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java
+++ b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java
@@ -107,7 +107,6 @@
     @Mock protected Context mContext;
     @Mock protected Network mNetwork;
     @Mock protected FeatureFlags mFeatureFlags;
-    @Mock protected android.net.platform.flags.FeatureFlags mCoreNetFeatureFlags;
     @Mock protected TelephonySubscriptionSnapshot mSubscriptionSnapshot;
     @Mock protected ConnectivityManager mConnectivityManager;
     @Mock protected TelephonyManager mTelephonyManager;
diff --git a/tools/streaming_proto/java/java_proto_stream_code_generator.cpp b/tools/streaming_proto/java/java_proto_stream_code_generator.cpp
index 9d61111..be5c197 100644
--- a/tools/streaming_proto/java/java_proto_stream_code_generator.cpp
+++ b/tools/streaming_proto/java/java_proto_stream_code_generator.cpp
@@ -18,11 +18,13 @@
 
 #include <stdio.h>
 
+#include <algorithm>
 #include <iomanip>
 #include <iostream>
 #include <map>
 #include <sstream>
 #include <string>
+#include <unordered_set>
 
 #include "Errors.h"
 
@@ -30,21 +32,39 @@
 using namespace google::protobuf::io;
 using namespace std;
 
+static bool outer_class_name_clashes_with_any_message(const string& outer_class_name,
+                                                      const vector<DescriptorProto>& messages) {
+    return any_of(messages.cbegin(), messages.cend(), [&](const DescriptorProto& message) {
+        return message.name() == outer_class_name;
+    });
+}
+
 /**
  * If the descriptor gives us a class name, use that. Otherwise make one up from
  * the filename of the .proto file.
  */
-static string make_outer_class_name(const FileDescriptorProto& file_descriptor) {
+static string make_outer_class_name(const FileDescriptorProto& file_descriptor,
+                                    const vector<DescriptorProto>& messages) {
     string name = file_descriptor.options().java_outer_classname();
-    if (name.size() == 0) {
-        name = to_camel_case(file_base_name(file_descriptor.name()));
-        if (name.size() == 0) {
-            ERRORS.Add(UNKNOWN_FILE, UNKNOWN_LINE,
-                       "Unable to make an outer class name for file: %s",
-                       file_descriptor.name().c_str());
-            name = "Unknown";
-        }
+    if (!name.empty()) {
+        return name;
     }
+
+    // Outer class and messages with the same name would result in invalid java (outer class and
+    // inner class cannot have same names).
+    // If the outer class name clashes with any message, let's append an "OuterClass" suffix.
+    // This behavior is consistent with the standard protoc.
+    name = to_camel_case(file_base_name(file_descriptor.name()));
+    while (outer_class_name_clashes_with_any_message(name, messages)) {
+        name += "OuterClass";
+    }
+
+    if (name.empty()) {
+        ERRORS.Add(UNKNOWN_FILE, UNKNOWN_LINE, "Unable to make an outer class name for file: %s",
+                   file_descriptor.name().c_str());
+        name = "Unknown";
+    }
+
     return name;
 }
 
@@ -149,6 +169,12 @@
         write_field(text, message.field(i), indented);
     }
 
+    // Extensions
+    N = message.extension_size();
+    for (int i = 0; i < N; i++) {
+        write_field(text, message.extension(i), indented);
+    }
+
     text << indent << "}" << endl;
     text << endl;
 }
@@ -165,7 +191,7 @@
     stringstream text;
 
     string const package_name = make_java_package(file_descriptor);
-    string const outer_class_name = make_outer_class_name(file_descriptor);
+    string const outer_class_name = make_outer_class_name(file_descriptor, messages);
 
     text << "// Generated by protoc-gen-javastream. DO NOT MODIFY." << endl;
     text << "// source: " << file_descriptor.name() << endl << endl;
@@ -214,7 +240,7 @@
  */
 static void write_multiple_files(CodeGeneratorResponse* response,
                                  const FileDescriptorProto& file_descriptor,
-                                 set<string> messages_to_compile) {
+                                 const unordered_set<string>& messages_allowlist) {
     // If there is anything to put in the outer class file, create one
     if (file_descriptor.enum_type_size() > 0) {
         vector<EnumDescriptorProto> enums;
@@ -222,7 +248,7 @@
         for (int i = 0; i < N; i++) {
             auto enum_full_name =
                     file_descriptor.package() + "." + file_descriptor.enum_type(i).name();
-            if (!messages_to_compile.empty() && !messages_to_compile.count(enum_full_name)) {
+            if (!messages_allowlist.empty() && !messages_allowlist.count(enum_full_name)) {
                 continue;
             }
             enums.push_back(file_descriptor.enum_type(i));
@@ -230,9 +256,10 @@
 
         vector<DescriptorProto> messages;
 
-        if (messages_to_compile.empty() || !enums.empty()) {
+        if (messages_allowlist.empty() || !enums.empty()) {
             write_file(response, file_descriptor,
-                       make_file_name(file_descriptor, make_outer_class_name(file_descriptor)),
+                       make_file_name(file_descriptor,
+                                      make_outer_class_name(file_descriptor, messages)),
                        true, enums, messages);
         }
     }
@@ -246,12 +273,12 @@
 
         auto message_full_name =
                 file_descriptor.package() + "." + file_descriptor.message_type(i).name();
-        if (!messages_to_compile.empty() && !messages_to_compile.count(message_full_name)) {
+        if (!messages_allowlist.empty() && !messages_allowlist.count(message_full_name)) {
             continue;
         }
         messages.push_back(file_descriptor.message_type(i));
 
-        if (messages_to_compile.empty() || !messages.empty()) {
+        if (messages_allowlist.empty() || !messages.empty()) {
             write_file(response, file_descriptor,
                        make_file_name(file_descriptor, file_descriptor.message_type(i).name()),
                        false, enums, messages);
@@ -261,14 +288,14 @@
 
 static void write_single_file(CodeGeneratorResponse* response,
                               const FileDescriptorProto& file_descriptor,
-                              set<string> messages_to_compile) {
+                              const unordered_set<string>& messages_allowlist) {
     int N;
 
     vector<EnumDescriptorProto> enums;
     N = file_descriptor.enum_type_size();
     for (int i = 0; i < N; i++) {
         auto enum_full_name = file_descriptor.package() + "." + file_descriptor.enum_type(i).name();
-        if (!messages_to_compile.empty() && !messages_to_compile.count(enum_full_name)) {
+        if (!messages_allowlist.empty() && !messages_allowlist.count(enum_full_name)) {
             continue;
         }
 
@@ -281,22 +308,23 @@
         auto message_full_name =
                 file_descriptor.package() + "." + file_descriptor.message_type(i).name();
 
-        if (!messages_to_compile.empty() && !messages_to_compile.count(message_full_name)) {
+        if (!messages_allowlist.empty() && !messages_allowlist.count(message_full_name)) {
             continue;
         }
 
         messages.push_back(file_descriptor.message_type(i));
     }
 
-    if (messages_to_compile.empty() || !enums.empty() || !messages.empty()) {
+    if (messages_allowlist.empty() || !enums.empty() || !messages.empty()) {
         write_file(response, file_descriptor,
-                   make_file_name(file_descriptor, make_outer_class_name(file_descriptor)), true,
-                   enums, messages);
+                   make_file_name(file_descriptor,
+                                  make_outer_class_name(file_descriptor, messages)),
+                   true, enums, messages);
     }
 }
 
 static void parse_args_string(stringstream args_string_stream,
-                              set<string>* messages_to_compile_out) {
+                              unordered_set<string>& messages_allowlist_out) {
     string line;
     while (getline(args_string_stream, line, ';')) {
         stringstream line_ss(line);
@@ -305,7 +333,7 @@
         if (arg_name == "include_filter") {
             string full_message_name;
             while (getline(line_ss, full_message_name, ',')) {
-                messages_to_compile_out->insert(full_message_name);
+                messages_allowlist_out.insert(full_message_name);
             }
         } else {
             ERRORS.Add(UNKNOWN_FILE, UNKNOWN_LINE, "Unexpected argument '%s'.", arg_name.c_str());
@@ -316,10 +344,10 @@
 CodeGeneratorResponse generate_java_protostream_code(CodeGeneratorRequest request) {
     CodeGeneratorResponse response;
 
-    set<string> messages_to_compile;
+    unordered_set<string> messages_allowlist;
     auto request_params = request.parameter();
     if (!request_params.empty()) {
-        parse_args_string(stringstream(request_params), &messages_to_compile);
+        parse_args_string(stringstream(request_params), messages_allowlist);
     }
 
     // Build the files we need.
@@ -328,9 +356,9 @@
         const FileDescriptorProto& file_descriptor = request.proto_file(i);
         if (should_generate_for_file(request, file_descriptor.name())) {
             if (file_descriptor.options().java_multiple_files()) {
-                write_multiple_files(&response, file_descriptor, messages_to_compile);
+                write_multiple_files(&response, file_descriptor, messages_allowlist);
             } else {
-                write_single_file(&response, file_descriptor, messages_to_compile);
+                write_single_file(&response, file_descriptor, messages_allowlist);
             }
         }
     }