Merge "Update thermal file owner" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index 45f6570..fdd0505 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -121,6 +121,18 @@
     srcs: ["core/java/android/nfc/*.aconfig"],
 }
 
+cc_aconfig_library {
+    name: "android_nfc_flags_aconfig_c_lib",
+    vendor_available: true,
+    aconfig_declarations: "android.nfc.flags-aconfig",
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.nfcservices",
+        "nfc_nci.st21nfc.default",
+    ],
+    defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
 java_aconfig_library {
     name: "android.nfc.flags-aconfig-java",
     aconfig_declarations: "android.nfc.flags-aconfig",
@@ -149,7 +161,7 @@
     name: "android.security.flags-aconfig-java-host",
     aconfig_declarations: "android.security.flags-aconfig",
     host_supported: true,
-    test: true,
+    mode: "test",
     defaults: ["framework-minus-apex-aconfig-java-defaults"],
 }
 
diff --git a/INPUT_OWNERS b/INPUT_OWNERS
index e02ba77..44b2f38 100644
--- a/INPUT_OWNERS
+++ b/INPUT_OWNERS
@@ -5,3 +5,5 @@
 prabirmsp@google.com
 svv@google.com
 vdevmurari@google.com
+
+per-file Virtual*=file:/services/companion/java/com/android/server/companion/virtual/OWNERS
diff --git a/apct-tests/perftests/OWNERS b/apct-tests/perftests/OWNERS
index 4c57e64..8ff3f9b 100644
--- a/apct-tests/perftests/OWNERS
+++ b/apct-tests/perftests/OWNERS
@@ -1,12 +1,11 @@
-balejs@google.com
 carmenjackson@google.com
-cfijalkovich@google.com
 dualli@google.com
 edgararriaga@google.com
-jpakaravoor@google.com
+jdduke@google.com
 jreck@google.com #{LAST_RESORT_SUGGESTION}
 kevinjeon@google.com
 philipcuadra@google.com
+shayba@google.com
 shombert@google.com
 timmurray@google.com
 wessam@google.com
diff --git a/apct-tests/perftests/core/res/drawable-nodpi/fountain_night.jpg b/apct-tests/perftests/core/res/drawable-nodpi/fountain_night.jpg
new file mode 100644
index 0000000..d8b2d75
--- /dev/null
+++ b/apct-tests/perftests/core/res/drawable-nodpi/fountain_night.jpg
Binary files differ
diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/CanvasPerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/CanvasPerfTest.java
index f84a0d0..e5a06c9 100644
--- a/apct-tests/perftests/core/src/android/graphics/perftests/CanvasPerfTest.java
+++ b/apct-tests/perftests/core/src/android/graphics/perftests/CanvasPerfTest.java
@@ -16,20 +16,29 @@
 
 package android.graphics.perftests;
 
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.Config;
 import android.graphics.Color;
+import android.graphics.ImageDecoder;
 import android.graphics.Paint;
 import android.graphics.RecordingCanvas;
 import android.graphics.RenderNode;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
 
+import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.LargeTest;
 
+import com.android.perftests.core.R;
+
 import org.junit.Rule;
 import org.junit.Test;
 
+import java.io.IOException;
+
 @LargeTest
 public class CanvasPerfTest {
     @Rule
@@ -93,4 +102,38 @@
             node.end(canvas);
         }
     }
+
+    @Test
+    public void testCreateScaledBitmap() throws IOException {
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final Context context = InstrumentationRegistry.getContext();
+        Bitmap source = ImageDecoder.decodeBitmap(
+                ImageDecoder.createSource(context.getResources(), R.drawable.fountain_night),
+                (decoder, info, source1) -> {
+                    decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+                });
+        source.setGainmap(null);
+
+        while (state.keepRunning()) {
+            Bitmap.createScaledBitmap(source, source.getWidth() / 2, source.getHeight() / 2, true)
+                    .recycle();
+        }
+    }
+
+    @Test
+    public void testCreateScaledBitmapWithGainmap() throws IOException {
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final Context context = InstrumentationRegistry.getContext();
+        Bitmap source = ImageDecoder.decodeBitmap(
+                ImageDecoder.createSource(context.getResources(), R.drawable.fountain_night),
+                (decoder, info, source1) -> {
+                    decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+                });
+        assertTrue(source.hasGainmap());
+
+        while (state.keepRunning()) {
+            Bitmap.createScaledBitmap(source, source.getWidth() / 2, source.getHeight() / 2, true)
+                    .recycle();
+        }
+    }
 }
diff --git a/api/Android.bp b/api/Android.bp
index 15b10a6..a89e1f2 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -83,7 +83,6 @@
         "framework-configinfrastructure",
         "framework-connectivity",
         "framework-connectivity-t",
-        "framework-crashrecovery",
         "framework-devicelock",
         "framework-graphics",
         "framework-healthfitness",
@@ -91,6 +90,7 @@
         "framework-media",
         "framework-mediaprovider",
         "framework-ondevicepersonalization",
+        "framework-pdf",
         "framework-permission",
         "framework-permission-s",
         "framework-scheduling",
@@ -106,7 +106,6 @@
     system_server_classpath: [
         "service-art",
         "service-configinfrastructure",
-        "service-crashrecovery",
         "service-healthfitness",
         "service-media-s",
         "service-permission",
diff --git a/api/coverage/tools/Android.bp b/api/coverage/tools/Android.bp
new file mode 100644
index 0000000..3e16912
--- /dev/null
+++ b/api/coverage/tools/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2023 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.
+
+java_binary_host {
+    name: "extract-flagged-apis",
+    srcs: ["ExtractFlaggedApis.kt"],
+    main_class: "android.platform.coverage.ExtractFlaggedApisKt",
+    static_libs: [
+        "metalava-signature-reader",
+        "extract_flagged_apis_proto",
+    ],
+}
+
+java_library_host {
+    name: "extract_flagged_apis_proto",
+    srcs: ["extract_flagged_apis.proto"],
+    static_libs: ["libprotobuf-java-full"],
+    proto: {
+        type: "full",
+    },
+}
diff --git a/api/coverage/tools/ExtractFlaggedApis.kt b/api/coverage/tools/ExtractFlaggedApis.kt
new file mode 100644
index 0000000..948e64f
--- /dev/null
+++ b/api/coverage/tools/ExtractFlaggedApis.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2023 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.platform.coverage
+
+import com.android.tools.metalava.model.text.ApiFile
+import java.io.File
+import java.io.FileWriter
+
+/** Usage: extract-flagged-apis <api text file> <output .pb file> */
+fun main(args: Array<String>) {
+    var cb = ApiFile.parseApi(listOf(File(args[0])))
+    val flagToApi = mutableMapOf<String, MutableList<String>>()
+    cb.getPackages()
+        .allTopLevelClasses()
+        .filter { it.methods().size > 0 }
+        .forEach {
+            for (method in it.methods()) {
+                val flagValue =
+                    method.modifiers
+                        .findAnnotation("android.annotation.FlaggedApi")
+                        ?.findAttribute("value")
+                        ?.value
+                        ?.value()
+                if (flagValue != null && flagValue is String) {
+                    val methodQualifiedName = "${it.qualifiedName()}.${method.name()}"
+                    if (flagToApi.containsKey(flagValue)) {
+                        flagToApi.get(flagValue)?.add(methodQualifiedName)
+                    } else {
+                        flagToApi.put(flagValue, mutableListOf(methodQualifiedName))
+                    }
+                }
+            }
+        }
+    var builder = FlagApiMap.newBuilder()
+    for (flag in flagToApi.keys) {
+        var flaggedApis = FlaggedApis.newBuilder()
+        for (method in flagToApi.get(flag).orEmpty()) {
+            flaggedApis.addFlaggedApi(FlaggedApi.newBuilder().setQualifiedName(method))
+        }
+        builder.putFlagToApi(flag, flaggedApis.build())
+    }
+    val flagApiMap = builder.build()
+    FileWriter(args[1]).use { it.write(flagApiMap.toString()) }
+}
diff --git a/api/coverage/tools/extract_flagged_apis.proto b/api/coverage/tools/extract_flagged_apis.proto
new file mode 100644
index 0000000..a858108
--- /dev/null
+++ b/api/coverage/tools/extract_flagged_apis.proto
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+syntax = "proto3";
+
+package android.platform.coverage;
+
+option java_multiple_files = true;
+
+message FlagApiMap {
+  map<string, FlaggedApis> flag_to_api = 1;
+}
+
+message FlaggedApis {
+  repeated FlaggedApi flagged_api = 1;
+}
+
+message FlaggedApi {
+  string qualified_name = 1;
+}
+
diff --git a/boot/Android.bp b/boot/Android.bp
index b33fab6..8a3d35e 100644
--- a/boot/Android.bp
+++ b/boot/Android.bp
@@ -84,10 +84,6 @@
             module: "com.android.conscrypt-bootclasspath-fragment",
         },
         {
-            apex: "com.android.crashrecovery",
-            module: "com.android.crashrecovery-bootclasspath-fragment",
-        },
-        {
             apex: "com.android.devicelock",
             module: "com.android.devicelock-bootclasspath-fragment",
         },
diff --git a/core/api/current.txt b/core/api/current.txt
index c9cba00..958b2f9 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -29105,14 +29105,17 @@
   }
 
   public final class NfcAdapter {
+    method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean allowTransaction();
     method public void disableForegroundDispatch(android.app.Activity);
     method public void disableReaderMode(android.app.Activity);
+    method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean disallowTransaction();
     method public void enableForegroundDispatch(android.app.Activity, android.app.PendingIntent, android.content.IntentFilter[], String[][]);
     method public void enableReaderMode(android.app.Activity, android.nfc.NfcAdapter.ReaderCallback, int, android.os.Bundle);
     method public static android.nfc.NfcAdapter getDefaultAdapter(android.content.Context);
     method @Nullable public android.nfc.NfcAntennaInfo getNfcAntennaInfo();
     method public boolean ignore(android.nfc.Tag, int, android.nfc.NfcAdapter.OnTagRemovedListener, android.os.Handler);
     method public boolean isEnabled();
+    method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean isObserveModeSupported();
     method @FlaggedApi("android.nfc.enable_nfc_reader_option") public boolean isReaderOptionEnabled();
     method @FlaggedApi("android.nfc.enable_nfc_reader_option") public boolean isReaderOptionSupported();
     method public boolean isSecureNfcEnabled();
@@ -29220,6 +29223,7 @@
     method public boolean removeAidsForService(android.content.ComponentName, String);
     method @NonNull @RequiresPermission(android.Manifest.permission.NFC) public boolean setOffHostForService(@NonNull android.content.ComponentName, @NonNull String);
     method public boolean setPreferredService(android.app.Activity, android.content.ComponentName);
+    method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean setServiceObserveModeDefault(@NonNull android.content.ComponentName, boolean);
     method public boolean supportsAidPrefixRegistration();
     method @NonNull @RequiresPermission(android.Manifest.permission.NFC) public boolean unsetOffHostForService(@NonNull android.content.ComponentName);
     method public boolean unsetPreferredService(android.app.Activity);
@@ -29239,9 +29243,20 @@
     method public final android.os.IBinder onBind(android.content.Intent);
     method public abstract void onDeactivated(int);
     method public abstract byte[] processCommandApdu(byte[], android.os.Bundle);
+    method @FlaggedApi("android.nfc.nfc_read_polling_loop") public void processPollingFrames(@NonNull java.util.List<android.os.Bundle>);
     method public final void sendResponseApdu(byte[]);
     field public static final int DEACTIVATION_DESELECTED = 1; // 0x1
     field public static final int DEACTIVATION_LINK_LOSS = 0; // 0x0
+    field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final String POLLING_LOOP_DATA_KEY = "android.nfc.cardemulation.DATA";
+    field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final String POLLING_LOOP_GAIN_KEY = "android.nfc.cardemulation.GAIN";
+    field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final String POLLING_LOOP_TIMESTAMP_KEY = "android.nfc.cardemulation.TIMESTAMP";
+    field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_A = 65; // 0x0041 'A'
+    field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_B = 66; // 0x0042 'B'
+    field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_F = 70; // 0x0046 'F'
+    field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final String POLLING_LOOP_TYPE_KEY = "android.nfc.cardemulation.TYPE";
+    field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_OFF = 88; // 0x0058 'X'
+    field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_ON = 79; // 0x004f 'O'
+    field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_UNKNOWN = 85; // 0x0055 'U'
     field public static final String SERVICE_INTERFACE = "android.nfc.cardemulation.action.HOST_APDU_SERVICE";
     field public static final String SERVICE_META_DATA = "android.nfc.cardemulation.host_apdu_service";
   }
@@ -39603,7 +39618,7 @@
     method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityForOriginationEnd(java.util.Date);
     method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityStart(java.util.Date);
     method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setMaxUsageCount(int);
-    method @FlaggedApi("MGF1_DIGEST_SETTER") @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setMgf1Digests(@Nullable java.lang.String...);
+    method @FlaggedApi("MGF1_DIGEST_SETTER") @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setMgf1Digests(@NonNull java.lang.String...);
     method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setRandomizedEncryptionRequired(boolean);
     method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setSignaturePaddings(java.lang.String...);
     method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUnlockedDeviceRequired(boolean);
diff --git a/core/java/Android.bp b/core/java/Android.bp
index b6789aa..d5acf42 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -413,6 +413,10 @@
     backend: {
         rust: {
             enabled: true,
+            apex_available: [
+                "//apex_available:platform",
+                "com.android.virt",
+            ],
         },
     },
 }
diff --git a/core/java/android/net/INetworkManagementEventObserver.aidl b/core/java/android/net/INetworkManagementEventObserver.aidl
index 0a6be20..eda80c8 100644
--- a/core/java/android/net/INetworkManagementEventObserver.aidl
+++ b/core/java/android/net/INetworkManagementEventObserver.aidl
@@ -85,14 +85,14 @@
     /**
      * Interface data activity status is changed.
      *
-     * @param transportType The transport type of the data activity change.
+     * @param label label of the data activity change.
      * @param active  True if the interface is actively transmitting data, false if it is idle.
      * @param tsNanos Elapsed realtime in nanos when the state of the network interface changed.
      * @param uid Uid of this event. It represents the uid that was responsible for waking the
      *            radio. For those events that are reported by system itself, not from specific uid,
      *            use -1 for the events which means no uid.
      */
-    void interfaceClassDataActivityChanged(int transportType, boolean active, long tsNanos, int uid);
+    void interfaceClassDataActivityChanged(int label, boolean active, long tsNanos, int uid);
 
     /**
      * Information about available DNS servers has been received.
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index 0c95c2e..f6beec1 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -84,4 +84,6 @@
     boolean isReaderOptionSupported();
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)")
     boolean enableReaderOption(boolean enable);
+    boolean isObserveModeSupported();
+    boolean setObserveMode(boolean enabled);
 }
diff --git a/core/java/android/nfc/INfcCardEmulation.aidl b/core/java/android/nfc/INfcCardEmulation.aidl
index c7b3b2c..191385a 100644
--- a/core/java/android/nfc/INfcCardEmulation.aidl
+++ b/core/java/android/nfc/INfcCardEmulation.aidl
@@ -30,6 +30,7 @@
     boolean isDefaultServiceForAid(int userHandle, in ComponentName service, String aid);
     boolean setDefaultServiceForCategory(int userHandle, in ComponentName service, String category);
     boolean setDefaultForNextTap(int userHandle, in ComponentName service);
+    boolean setServiceObserveModeDefault(int userId, in android.content.ComponentName service, boolean enable);
     boolean registerAidGroupForService(int userHandle, in ComponentName service, in AidGroup aidGroup);
     boolean setOffHostForService(int userHandle, in ComponentName service, in String offHostSecureElement);
     boolean unsetOffHostForService(int userHandle, in ComponentName service);
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index c897595..98a980f 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -1081,6 +1081,61 @@
         }
     }
 
+
+    /**
+     * Returns whether the device supports observer mode or not. When observe
+     * mode is enabled, the NFC hardware will listen for NFC readers, but not
+     * respond to them. When observe mode is disabled, the NFC hardware will
+     * resoond to the reader and proceed with the transaction.
+     * @return true if the mode is supported, false otherwise.
+     */
+    @FlaggedApi(Flags.FLAG_NFC_OBSERVE_MODE)
+    public boolean isObserveModeSupported() {
+        try {
+            return sService.isObserveModeSupported();
+        } catch (RemoteException e) {
+            attemptDeadServiceRecovery(e);
+            return false;
+        }
+    }
+
+   /**
+    * Disables observe mode to allow the transaction to proceed. See
+    * {@link #isObserveModeSupported()} for a description of observe mode and
+    * use {@link #disallowTransaction()} to enable observe mode and block
+    * transactions again.
+    *
+    * @return boolean indicating success or failure.
+    */
+    @FlaggedApi(Flags.FLAG_NFC_OBSERVE_MODE)
+    public boolean allowTransaction() {
+        try {
+            return sService.setObserveMode(false);
+        } catch (RemoteException e) {
+            attemptDeadServiceRecovery(e);
+            return false;
+        }
+    }
+
+    /**
+    * Signals that the transaction has completed and observe mode may be
+    * reenabled. See {@link #isObserveModeSupported()} for a description of
+    * observe mode and use {@link #allowTransaction()} to disable observe
+    * mode and allow transactions to proceed.
+    *
+    * @return boolean indicating success or failure.
+    */
+
+    @FlaggedApi(Flags.FLAG_NFC_OBSERVE_MODE)
+    public boolean disallowTransaction() {
+        try {
+            return sService.setObserveMode(true);
+        } catch (RemoteException e) {
+            attemptDeadServiceRecovery(e);
+            return false;
+        }
+    }
+
     /**
      * Resumes default polling for the current device state if polling is paused. Calling
      * this while polling is not paused is a no-op.
diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
index 597c948..e331c95 100644
--- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -21,6 +21,7 @@
 package android.nfc.cardemulation;
 
 import android.annotation.FlaggedApi;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
@@ -134,8 +135,9 @@
     /**
      * @hide
      */
+    @UnsupportedAppUsage
     public ApduServiceInfo(ResolveInfo info, boolean onHost, String description,
-            List<AidGroup> staticAidGroups, List<AidGroup> dynamicAidGroups,
+            ArrayList<AidGroup> staticAidGroups, ArrayList<AidGroup> dynamicAidGroups,
             boolean requiresUnlock, int bannerResource, int uid,
             String settingsActivityName, String offHost, String staticOffHost) {
         this(info, onHost, description, staticAidGroups, dynamicAidGroups,
@@ -147,7 +149,7 @@
      * @hide
      */
     public ApduServiceInfo(ResolveInfo info, boolean onHost, String description,
-            List<AidGroup> staticAidGroups, List<AidGroup> dynamicAidGroups,
+            ArrayList<AidGroup> staticAidGroups, ArrayList<AidGroup> dynamicAidGroups,
             boolean requiresUnlock, int bannerResource, int uid,
             String settingsActivityName, String offHost, String staticOffHost,
             boolean isEnabled) {
diff --git a/core/java/android/nfc/cardemulation/CardEmulation.java b/core/java/android/nfc/cardemulation/CardEmulation.java
index d048b59..58b6179 100644
--- a/core/java/android/nfc/cardemulation/CardEmulation.java
+++ b/core/java/android/nfc/cardemulation/CardEmulation.java
@@ -328,6 +328,24 @@
             return SELECTION_MODE_ASK_IF_CONFLICT;
         }
     }
+    /**
+     * Sets whether the system should default to observe mode or not when
+     * the service is in the foreground or the default payment service.
+     *
+     * @param service The component name of the service
+     * @param enable Whether the servic should default to observe mode or not
+     * @return whether the change was successful.
+     */
+    @FlaggedApi(Flags.FLAG_NFC_OBSERVE_MODE)
+    public boolean setServiceObserveModeDefault(@NonNull ComponentName service, boolean enable) {
+        try {
+            return sService.setServiceObserveModeDefault(mContext.getUser().getIdentifier(),
+                    service, enable);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to reach CardEmulationService.");
+        }
+        return  false;
+    }
 
     /**
      * Registers a list of AIDs for a specific category for the
diff --git a/core/java/android/nfc/cardemulation/HostApduService.java b/core/java/android/nfc/cardemulation/HostApduService.java
index 55d0e73..7cd2533 100644
--- a/core/java/android/nfc/cardemulation/HostApduService.java
+++ b/core/java/android/nfc/cardemulation/HostApduService.java
@@ -16,11 +16,14 @@
 
 package android.nfc.cardemulation;
 
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.app.Service;
 import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.nfc.NfcAdapter;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -29,6 +32,9 @@
 import android.os.RemoteException;
 import android.util.Log;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * <p>HostApduService is a convenience {@link Service} class that can be
  * extended to emulate an NFC card inside an Android
@@ -230,9 +236,99 @@
     /**
      * @hide
      */
+    public static final int MSG_POLLING_LOOP = 4;
+
+    /**
+     * @hide
+     */
     public static final String KEY_DATA = "data";
 
     /**
+     * POLLING_LOOP_TYPE_KEY is the Bundle key for the type of
+     * polling loop frame in the Bundle passed to {@link #processPollingFrames(List)}
+     */
+    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
+    public static final String POLLING_LOOP_TYPE_KEY = "android.nfc.cardemulation.TYPE";
+
+    /**
+     * POLLING_LOOP_TYPE_A is the value associated with the key
+     * POLLING_LOOP_TYPE  in the Bundle passed to {@link #processPollingFrames(List)}
+     * when the polling loop is for NFC-A.
+     */
+    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
+    public static final char POLLING_LOOP_TYPE_A = 'A';
+
+    /**
+     * POLLING_LOOP_TYPE_B is the value associated with the key
+     * POLLING_LOOP_TYPE  in the Bundle passed to {@link #processPollingFrames(List)}
+     * when the polling loop is for NFC-B.
+     */
+    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
+    public static final char POLLING_LOOP_TYPE_B = 'B';
+
+    /**
+     * POLLING_LOOP_TYPE_F is the value associated with the key
+     * POLLING_LOOP_TYPE  in the Bundle passed to {@link #processPollingFrames(List)}
+     * when the polling loop is for NFC-F.
+     */
+    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
+    public static final char POLLING_LOOP_TYPE_F = 'F';
+
+    /**
+     * POLLING_LOOP_TYPE_ON is the value associated with the key
+     * POLLING_LOOP_TYPE  in the Bundle passed to {@link #processPollingFrames(List)}
+     * when the polling loop turns on.
+     */
+    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
+    public static final char POLLING_LOOP_TYPE_ON = 'O';
+
+    /**
+     * POLLING_LOOP_TYPE_OFF is the value associated with the key
+     * POLLING_LOOP_TYPE  in the Bundle passed to {@link #processPollingFrames(List)}
+     * when the polling loop turns off.
+     */
+    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
+    public static final char POLLING_LOOP_TYPE_OFF = 'X';
+
+    /**
+     * POLLING_LOOP_TYPE_UNKNOWN is the value associated with the key
+     * POLLING_LOOP_TYPE  in the Bundle passed to {@link #processPollingFrames(List)}
+     * when the polling loop frame isn't recognized.
+     */
+    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
+    public static final char POLLING_LOOP_TYPE_UNKNOWN = 'U';
+
+    /**
+     * POLLING_LOOP_DATA is the Bundle key for the raw data of captured from
+     * the polling loop frame in the Bundle passed to {@link #processPollingFrames(List)}
+     * when the frame type isn't recognized.
+     */
+    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
+    public static final String POLLING_LOOP_DATA_KEY = "android.nfc.cardemulation.DATA";
+
+    /**
+     * POLLING_LOOP_GAIN_KEY is the Bundle key for the field strength of
+     * the polling loop frame in the Bundle passed to {@link #processPollingFrames(List)}
+     * when the frame type isn't recognized.
+     */
+    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
+    public static final String POLLING_LOOP_GAIN_KEY = "android.nfc.cardemulation.GAIN";
+
+    /**
+     * POLLING_LOOP_TIMESTAMP_KEY is the Bundle key for the timestamp of
+     * the polling loop frame in the Bundle passed to {@link #processPollingFrames(List)}
+     * when the frame type isn't recognized.
+     */
+    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
+    public static final String POLLING_LOOP_TIMESTAMP_KEY = "android.nfc.cardemulation.TIMESTAMP";
+
+    /**
+     * @hide
+     */
+    public static final String POLLING_LOOP_FRAMES_BUNDLE_KEY =
+            "android.nfc.cardemulation.POLLING_FRAMES";
+
+    /**
      * Messenger interface to NfcService for sending responses.
      * Only accessed on main thread by the message handler.
      *
@@ -255,6 +351,7 @@
 
                 byte[] apdu = dataBundle.getByteArray(KEY_DATA);
                 if (apdu != null) {
+                        HostApduService has = HostApduService.this;
                     byte[] responseApdu = processCommandApdu(apdu, null);
                     if (responseApdu != null) {
                         if (mNfcService == null) {
@@ -306,6 +403,12 @@
                     Log.e(TAG, "RemoteException calling into NfcService.");
                 }
                 break;
+                case MSG_POLLING_LOOP:
+                    ArrayList<Bundle> frames =
+                            msg.getData().getParcelableArrayList(POLLING_LOOP_FRAMES_BUNDLE_KEY,
+                            Bundle.class);
+                    processPollingFrames(frames);
+                    break;
             default:
                 super.handleMessage(msg);
             }
@@ -366,6 +469,21 @@
         }
     }
 
+    /**
+     * This method is called when a polling frame has been received from a
+     * remote device. If the device is in observe mode, the service should
+     * call {@link NfcAdapter#allowTransaction()} once it is ready to proceed
+     * with the transaction. If the device is not in observe mode, the service
+     * can use this polling frame information to determine how to proceed if it
+     * subsequently has {@link #processCommandApdu(byte[], Bundle)} called. The
+     * service must override this method inorder to receive polling frames,
+     * otherwise the base implementation drops the frame.
+     *
+     * @param frame A description of the polling frame.
+     */
+    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
+    public void processPollingFrames(@NonNull List<Bundle> frame) {
+    }
 
     /**
      * <p>This method will be called when a command APDU has been received
diff --git a/core/java/android/nfc/flags.aconfig b/core/java/android/nfc/flags.aconfig
index cd50ace..17e0427 100644
--- a/core/java/android/nfc/flags.aconfig
+++ b/core/java/android/nfc/flags.aconfig
@@ -20,3 +20,31 @@
     description: "Flag for NFC user restriction"
     bug: "291187960"
 }
+
+flag {
+    name: "nfc_observe_mode"
+    namespace: "nfc"
+    description: "Enable NFC Observe Mode"
+    bug: "294217286"
+}
+
+flag {
+    name: "nfc_read_polling_loop"
+    namespace: "nfc"
+    description: "Enable NFC Polling Loop Notifications"
+    bug: "294217286"
+}
+
+flag {
+    name: "nfc_observe_mode_st_shim"
+    namespace: "nfc"
+    description: "Enable NFC Observe Mode ST shim"
+    bug: "294217286"
+}
+
+flag {
+    name: "nfc_read_polling_loop_st_shim"
+    namespace: "nfc"
+    description: "Enable NFC Polling Loop Notifications ST shim"
+    bug: "294217286"
+}
diff --git a/core/java/android/os/DeadObjectException.java b/core/java/android/os/DeadObjectException.java
index e06b0f9..61aa222 100644
--- a/core/java/android/os/DeadObjectException.java
+++ b/core/java/android/os/DeadObjectException.java
@@ -19,7 +19,29 @@
 
 /**
  * The object you are calling has died, because its hosting process
- * no longer exists.
+ * no longer exists, or there has been a low-level binder error.
+ *
+ * If you get this exception from a system service, the error is
+ * usually nonrecoverable as the framework will restart. If you
+ * receive this error from an app, at a minimum, you should
+ * recover by resetting the connection. For instance, you should
+ * drop the binder, clean up associated state, and reset your
+ * connection to the service which through this error. In order
+ * to simplify your error recovery paths, you may also want to
+ * "simply" restart your process. However, this may not be an
+ * option if the service you are talking to is unreliable or
+ * crashes frequently.
+ *
+ * If this isn't from a service death and is instead from a
+ * low-level binder error, it will be from:
+ * - a oneway call queue filling up (too many oneway calls)
+ * - from the binder buffer being filled up, so that the transaction
+ *   is rejected.
+ *
+ * In these cases, more information about the error will be
+ * logged. However, there isn't a good way to differentiate
+ * this information at runtime. So, you should handle the
+ * error, as if the service died.
  */
 public class DeadObjectException extends RemoteException {
     public DeadObjectException() {
diff --git a/core/java/android/os/DeadSystemRuntimeException.java b/core/java/android/os/DeadSystemRuntimeException.java
index 1e86924..3b10798 100644
--- a/core/java/android/os/DeadSystemRuntimeException.java
+++ b/core/java/android/os/DeadSystemRuntimeException.java
@@ -18,9 +18,12 @@
 
 /**
  * Exception thrown when a call into system_server resulted in a
- * DeadObjectException, meaning that the system_server has died.  There's
- * nothing apps can do at this point - the system will automatically restart -
- * so there's no point in catching this.
+ * DeadObjectException, meaning that the system_server has died or
+ * experienced a low-level binder error.  There's nothing apps can
+ * do at this point - the system will automatically restart - so
+ * there's no point in catching this.
+ *
+ * See {@link android.os.DeadObjectException}.
  *
  * @hide
  */
diff --git a/core/java/com/android/internal/net/VpnProfile.java b/core/java/com/android/internal/net/VpnProfile.java
index 0947ec1..f62094d 100644
--- a/core/java/com/android/internal/net/VpnProfile.java
+++ b/core/java/com/android/internal/net/VpnProfile.java
@@ -618,4 +618,14 @@
     public int describeContents() {
         return 0;
     }
+
+    @Override
+    public VpnProfile clone() {
+        try {
+            return (VpnProfile) super.clone();
+        } catch (CloneNotSupportedException e) {
+            Log.wtf(TAG, e);
+            return null;
+        }
+    }
 }
diff --git a/core/java/com/android/internal/os/ProcessCpuTracker.java b/core/java/com/android/internal/os/ProcessCpuTracker.java
index 70514c3..01c91ba 100644
--- a/core/java/com/android/internal/os/ProcessCpuTracker.java
+++ b/core/java/com/android/internal/os/ProcessCpuTracker.java
@@ -337,6 +337,12 @@
 
     @UnsupportedAppUsage
     public void update() {
+        synchronized (this) {
+            updateLocked();
+        }
+    }
+
+    private void updateLocked() {
         if (DEBUG) Slog.v(TAG, "Update: " + this);
 
         final long nowUptime = SystemClock.uptimeMillis();
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index a3e0016..28fd2b4 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -1936,7 +1936,8 @@
      * If the user is not secured, ie doesn't have an LSKF, then decrypt the user's synthetic
      * password and use it to unlock various cryptographic keys associated with the user.  This
      * primarily includes unlocking the user's credential-encrypted (CE) storage.  It also includes
-     * deriving or decrypting the vendor auth secret and sending it to the AuthSecret HAL.
+     * unlocking the user's Keystore super keys, and deriving or decrypting the vendor auth secret
+     * and sending it to the AuthSecret HAL in order to unlock Secure Element firmware updates.
      * <p>
      * These tasks would normally be done when the LSKF is verified.  This method is where these
      * tasks are done when the user doesn't have an LSKF.  It's called when the user is started.
diff --git a/core/java/com/android/server/net/BaseNetworkObserver.java b/core/java/com/android/server/net/BaseNetworkObserver.java
index 139b88b..61e017d 100644
--- a/core/java/com/android/server/net/BaseNetworkObserver.java
+++ b/core/java/com/android/server/net/BaseNetworkObserver.java
@@ -64,7 +64,7 @@
     }
 
     @Override
-    public void interfaceClassDataActivityChanged(int transportType, boolean active, long tsNanos,
+    public void interfaceClassDataActivityChanged(int label, boolean active, long tsNanos,
             int uid) {
         // default no-op
     }
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index b1dab85..f9d00ed 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -212,14 +212,11 @@
             return (jint) AUDIORECORD_ERROR_SETUP_INVALIDFORMAT;
         }
 
-        size_t bytesPerSample = audio_bytes_per_sample(format);
-
         if (buffSizeInBytes == 0) {
             ALOGE("Error creating AudioRecord: frameCount is 0.");
             return (jint) AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT;
         }
-        size_t frameSize = channelCount * bytesPerSample;
-        size_t frameCount = buffSizeInBytes / frameSize;
+        size_t frameCount = buffSizeInBytes / audio_bytes_per_frame(channelCount, format);
 
         // create an uninitialized AudioRecord object
         Parcel* parcel = parcelForJavaObject(env, jAttributionSource);
@@ -574,7 +571,7 @@
     if (result != NO_ERROR) {
         return -1;
     }
-    return frameCount * channelCount * audio_bytes_per_sample(format);
+    return frameCount * audio_bytes_per_frame(channelCount, format);
 }
 
 static jboolean android_media_AudioRecord_setInputDevice(
diff --git a/core/res/Android.bp b/core/res/Android.bp
index b71995f..6fa70d8 100644
--- a/core/res/Android.bp
+++ b/core/res/Android.bp
@@ -151,6 +151,8 @@
             "simulated_device_launcher",
         ],
     },
+
+    generate_product_characteristics_rro: true,
 }
 
 java_genrule {
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 6f7bc53..3413282 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -4303,6 +4303,9 @@
         <!-- Whether the device must be screen on before routing data to this service.
              The default is true.-->
         <attr name="requireDeviceScreenOn" format="boolean"/>
+        <!-- Whether the device should default to observe mode when this service is
+             default or in the foreground. -->
+        <attr name="defaultToObserveMode" format="boolean"/>
     </declare-styleable>
 
     <!-- Use <code>offhost-apdu-service</code> as the root tag of the XML resource that
@@ -4327,6 +4330,9 @@
         <!-- Whether the device must be screen on before routing data to this service.
              The default is false.-->
         <attr name="requireDeviceScreenOn"/>
+        <!-- Whether the device should default to observe mode when this service is
+             default or in the foreground. -->
+        <attr name="defaultToObserveMode"/>
     </declare-styleable>
 
     <!-- Specify one or more <code>aid-group</code> elements inside a
diff --git a/keystore/java/android/security/AndroidKeyStoreMaintenance.java b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
index b7ea04f..2beb434 100644
--- a/keystore/java/android/security/AndroidKeyStoreMaintenance.java
+++ b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
@@ -51,7 +51,7 @@
      * @return 0 if successful or a {@code ResponseCode}
      * @hide
      */
-    public static int onUserAdded(@NonNull int userId) {
+    public static int onUserAdded(int userId) {
         StrictMode.noteDiskWrite();
         try {
             getService().onUserAdded(userId);
@@ -66,6 +66,30 @@
     }
 
     /**
+     * Tells Keystore to create a user's super keys and store them encrypted by the given secret.
+     *
+     * @param userId - Android user id of the user
+     * @param password - a secret derived from the user's synthetic password
+     * @param allowExisting - true if the keys already existing should not be considered an error
+     * @return 0 if successful or a {@code ResponseCode}
+     * @hide
+     */
+    public static int initUserSuperKeys(int userId, @NonNull byte[] password,
+            boolean allowExisting) {
+        StrictMode.noteDiskWrite();
+        try {
+            getService().initUserSuperKeys(userId, password, allowExisting);
+            return 0;
+        } catch (ServiceSpecificException e) {
+            Log.e(TAG, "initUserSuperKeys failed", e);
+            return e.errorCode;
+        } catch (Exception e) {
+            Log.e(TAG, "Can not connect to keystore", e);
+            return SYSTEM_ERROR;
+        }
+    }
+
+    /**
      * Informs Keystore 2.0 about removing a user
      *
      * @param userId - Android user id of the user being removed
@@ -110,6 +134,28 @@
     }
 
     /**
+     * Tells Keystore that a user's LSKF is being removed, ie the user's lock screen is changing to
+     * Swipe or None.  Keystore uses this notification to delete the user's auth-bound keys.
+     *
+     * @param userId - Android user id of the user
+     * @return 0 if successful or a {@code ResponseCode}
+     * @hide
+     */
+    public static int onUserLskfRemoved(int userId) {
+        StrictMode.noteDiskWrite();
+        try {
+            getService().onUserLskfRemoved(userId);
+            return 0;
+        } catch (ServiceSpecificException e) {
+            Log.e(TAG, "onUserLskfRemoved failed", e);
+            return e.errorCode;
+        } catch (Exception e) {
+            Log.e(TAG, "Can not connect to keystore", e);
+            return SYSTEM_ERROR;
+        }
+    }
+
+    /**
      * Informs Keystore 2.0 that an app was uninstalled and the corresponding namespace is to
      * be cleared.
      */
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index b714035..231fa48 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -1282,15 +1282,18 @@
          * function (MGF1) with a digest.
          * The default digest for MGF1 is {@code SHA-1}, which will be specified during key creation
          * time if no digests have been explicitly provided.
-         * When using the key, the caller may not specify any digests that were not provided during
-         * key creation time. The caller may specify the default digest, {@code SHA-1}, if no
+         * {@code null} may not be specified as a parameter to this method: It is not possible to
+         * disable MGF1 digest, a default must be present for when the caller tries to use it.
+         *
+         * <p>When using the key, the caller may not specify any digests that were not provided
+         * during key creation time. The caller may specify the default digest, {@code SHA-1}, if no
          * digests were explicitly provided during key creation (but it is not necessary to do so).
          *
          * <p>See {@link KeyProperties}.{@code DIGEST} constants.
          */
         @NonNull
         @FlaggedApi("MGF1_DIGEST_SETTER")
-        public Builder setMgf1Digests(@Nullable @KeyProperties.DigestEnum String... mgf1Digests) {
+        public Builder setMgf1Digests(@NonNull @KeyProperties.DigestEnum String... mgf1Digests) {
             mMgf1Digests = Set.of(mgf1Digests);
             return this;
         }
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 8394c3c..ea9b6c9 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -588,10 +588,40 @@
 // Canvas draw operations: Bitmaps
 // ----------------------------------------------------------------------------
 
+bool SkiaCanvas::useGainmapShader(Bitmap& bitmap) {
+    // If the bitmap doesn't have a gainmap, don't use the gainmap shader
+    if (!bitmap.hasGainmap()) return false;
+
+    // If we don't have an owned canvas, then we're either hardware accelerated or drawing
+    // to a picture - use the gainmap shader out of caution. Ideally a picture canvas would
+    // use a drawable here instead to defer making that decision until the last possible
+    // moment
+    if (!mCanvasOwned) return true;
+
+    auto info = mCanvasOwned->imageInfo();
+
+    // If it's an unknown colortype then it's not a bitmap-backed canvas
+    if (info.colorType() == SkColorType::kUnknown_SkColorType) return true;
+
+    skcms_TransferFunction tfn;
+    info.colorSpace()->transferFn(&tfn);
+
+    auto transferType = skcms_TransferFunction_getType(&tfn);
+    switch (transferType) {
+        case skcms_TFType_HLGish:
+        case skcms_TFType_HLGinvish:
+        case skcms_TFType_PQish:
+            return true;
+        case skcms_TFType_Invalid:
+        case skcms_TFType_sRGBish:
+            return false;
+    }
+}
+
 void SkiaCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const Paint* paint) {
     auto image = bitmap.makeImage();
 
-    if (bitmap.hasGainmap()) {
+    if (useGainmapShader(bitmap)) {
         Paint gainmapPaint = paint ? *paint : Paint();
         sk_sp<SkShader> gainmapShader = uirenderer::MakeGainmapShader(
                 image, bitmap.gainmap()->bitmap->makeImage(), bitmap.gainmap()->info,
@@ -618,7 +648,7 @@
     SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
     SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
 
-    if (bitmap.hasGainmap()) {
+    if (useGainmapShader(bitmap)) {
         Paint gainmapPaint = paint ? *paint : Paint();
         sk_sp<SkShader> gainmapShader = uirenderer::MakeGainmapShader(
                 image, bitmap.gainmap()->bitmap->makeImage(), bitmap.gainmap()->info,
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index b785989..9cb50ed 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -223,6 +223,8 @@
 
     void drawPoints(const float* points, int count, const Paint& paint, SkCanvas::PointMode mode);
 
+    bool useGainmapShader(Bitmap& bitmap);
+
     class Clip;
 
     std::unique_ptr<SkCanvas> mCanvasOwned;  // Might own a canvas we allocated.
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 7faa13c..447d3bb 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -1176,6 +1176,7 @@
             case AudioFormat.ENCODING_PCM_FLOAT:
             case AudioFormat.ENCODING_PCM_16BIT:
             case AudioFormat.ENCODING_PCM_8BIT:
+            case AudioFormat.ENCODING_E_AC3_JOC:
                 mAudioFormat = audioFormat;
                 break;
             default:
@@ -1188,20 +1189,12 @@
 
 
     // Convenience method for the contructor's audio buffer size check.
-    // preconditions:
-    //    mChannelCount is valid
-    //    mAudioFormat is AudioFormat.ENCODING_PCM_8BIT, AudioFormat.ENCODING_PCM_16BIT,
-    //                 or AudioFormat.ENCODING_PCM_FLOAT
     // postcondition:
     //    mNativeBufferSizeInBytes is valid (multiple of frame size, positive)
     private void audioBuffSizeCheck(int audioBufferSize) throws IllegalArgumentException {
-        // NB: this section is only valid with PCM data.
-        // To update when supporting compressed formats
-        int frameSizeInBytes = mChannelCount
-            * (AudioFormat.getBytesPerSample(mAudioFormat));
-        if ((audioBufferSize % frameSizeInBytes != 0) || (audioBufferSize < 1)) {
+        if ((audioBufferSize % getFormat().getFrameSizeInBytes() != 0) || (audioBufferSize < 1)) {
             throw new IllegalArgumentException("Invalid audio buffer size " + audioBufferSize
-                    + " (frame size " + frameSizeInBytes + ")");
+                    + " (frame size " + getFormat().getFrameSizeInBytes() + ")");
         }
 
         mNativeBufferSizeInBytes = audioBufferSize;
diff --git a/services/core/java/com/android/server/VpnManagerService.java b/services/core/java/com/android/server/VpnManagerService.java
index 0d423d8..2ba3a1d 100644
--- a/services/core/java/com/android/server/VpnManagerService.java
+++ b/services/core/java/com/android/server/VpnManagerService.java
@@ -33,7 +33,6 @@
 import android.net.ConnectivityManager;
 import android.net.INetd;
 import android.net.IVpnManager;
-import android.net.LinkProperties;
 import android.net.Network;
 import android.net.NetworkStack;
 import android.net.UnderlyingNetworkInfo;
@@ -437,16 +436,9 @@
             throw new UnsupportedOperationException("Legacy VPN is deprecated");
         }
         int user = UserHandle.getUserId(mDeps.getCallingUid());
-        // Note that if the caller is not system (uid >= Process.FIRST_APPLICATION_UID),
-        // the code might not work well since getActiveNetwork might return null if the uid is
-        // blocked by NetworkPolicyManagerService.
-        final LinkProperties egress = mCm.getLinkProperties(mCm.getActiveNetwork());
-        if (egress == null) {
-            throw new IllegalStateException("Missing active network connection");
-        }
         synchronized (mVpns) {
             throwIfLockdownEnabled();
-            mVpns.get(user).startLegacyVpn(profile, null /* underlying */, egress);
+            mVpns.get(user).startLegacyVpn(profile);
         }
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index d56448d..469582d 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -4122,7 +4122,7 @@
             pw.println("      -D: enable debugging");
             pw.println("      --suspend: debugged app suspend threads at startup (only with -D)");
             pw.println("      -N: enable native debugging");
-            pw.println("      -W: wait for launch to complete");
+            pw.println("      -W: wait for launch to complete (initial display)");
             pw.println("      --start-profiler <FILE>: start profiler and send results to <FILE>");
             pw.println("      --sampling INTERVAL: use sample profiling with INTERVAL microseconds");
             pw.println("          between samples (use with --start-profiler)");
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index dc6f858..7dac241 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -17,7 +17,6 @@
 package com.android.server.am;
 
 import static android.Manifest.permission.BATTERY_STATS;
-import static android.Manifest.permission.BLUETOOTH_CONNECT;
 import static android.Manifest.permission.DEVICE_POWER;
 import static android.Manifest.permission.NETWORK_STACK;
 import static android.Manifest.permission.POWER_SAVER;
@@ -103,6 +102,7 @@
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.util.ParseUtils;
 import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.modules.utils.build.SdkLevel;
 import com.android.net.module.util.NetworkCapabilitiesUtils;
 import com.android.server.LocalServices;
 import com.android.server.Watchdog;
@@ -426,7 +426,12 @@
                 ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
         final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
         try {
-            nms.registerObserver(mActivityChangeObserver);
+            if (!SdkLevel.isAtLeastV()) {
+                // On V+ devices, ConnectivityService calls BatteryStats API to update
+                // RadioPowerState change. So BatteryStatsService registers the callback only on
+                // pre V devices.
+                nms.registerObserver(mActivityChangeObserver);
+            }
             cm.registerDefaultNetworkCallback(mNetworkCallback);
         } catch (RemoteException e) {
             Slog.e(TAG, "Could not register INetworkManagement event observer " + e);
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index a12243b..aef2248 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -2549,15 +2549,14 @@
      * secondary thread to perform connection work, returning quickly.
      *
      * Should only be called to respond to Binder requests as this enforces caller permission. Use
-     * {@link #startLegacyVpnPrivileged(VpnProfile, Network, LinkProperties)} to skip the
+     * {@link #startLegacyVpnPrivileged(VpnProfile)} to skip the
      * permission check only when the caller is trusted (or the call is initiated by the system).
      */
-    public void startLegacyVpn(VpnProfile profile, @Nullable Network underlying,
-            LinkProperties egress) {
+    public void startLegacyVpn(VpnProfile profile) {
         enforceControlPermission();
         final long token = Binder.clearCallingIdentity();
         try {
-            startLegacyVpnPrivileged(profile, underlying, egress);
+            startLegacyVpnPrivileged(profile);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -2616,13 +2615,13 @@
     }
 
     /**
-     * Like {@link #startLegacyVpn(VpnProfile, Network, LinkProperties)}, but does not
-     * check permissions under the assumption that the caller is the system.
+     * Like {@link #startLegacyVpn(VpnProfile)}, but does not check permissions under
+     * the assumption that the caller is the system.
      *
      * Callers are responsible for checking permissions if needed.
      */
-    public void startLegacyVpnPrivileged(VpnProfile profile,
-            @Nullable Network underlying, @NonNull LinkProperties egress) {
+    public void startLegacyVpnPrivileged(VpnProfile profileToStart) {
+        final VpnProfile profile = profileToStart.clone();
         UserInfo user = mUserManager.getUserInfo(mUserId);
         if (user.isRestricted() || mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_VPN,
                     new UserHandle(mUserId))) {
@@ -3385,6 +3384,13 @@
          *              given network to start a new IKE session.
          */
         private void startOrMigrateIkeSession(@Nullable Network underlyingNetwork) {
+            synchronized (Vpn.this) {
+                // Ignore stale runner.
+                if (mVpnRunner != this) return;
+                setVpnNetworkPreference(mSessionKey,
+                        createUserAndRestrictedProfilesRanges(mUserId,
+                                mConfig.allowedApplications, mConfig.disallowedApplications));
+            }
             if (underlyingNetwork == null) {
                 // For null underlyingNetwork case, there will not be a NetworkAgent available so
                 // no underlying network update is necessary here. Note that updating
@@ -3905,6 +3911,7 @@
                 updateState(DetailedState.FAILED, exception.getMessage());
             }
 
+            clearVpnNetworkPreference(mSessionKey);
             disconnectVpnRunner();
         }
 
@@ -4039,6 +4046,13 @@
             }
 
             resetIkeState();
+            if (errorCode != VpnManager.ERROR_CODE_NETWORK_LOST
+                    // Clear the VPN network preference when the retry delay is higher than 5s.
+                    // mRetryCount was increased when scheduleRetryNewIkeSession() is called,
+                    // therefore use mRetryCount - 1 here.
+                    && mDeps.getNextRetryDelayMs(mRetryCount - 1) > 5_000L) {
+                clearVpnNetworkPreference(mSessionKey);
+            }
         }
 
         /**
@@ -4085,13 +4099,17 @@
             mCarrierConfigManager.unregisterCarrierConfigChangeListener(
                     mCarrierConfigChangeListener);
             mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
-            clearVpnNetworkPreference(mSessionKey);
 
             mExecutor.shutdown();
         }
 
         @Override
         public void exitVpnRunner() {
+            // mSessionKey won't be changed since the Ikev2VpnRunner is created, so it's ok to use
+            // it outside the mExecutor. And clearing the VPN network preference here can prevent
+            // the case that the VPN network preference isn't cleared when Ikev2VpnRunner became
+            // stale.
+            clearVpnNetworkPreference(mSessionKey);
             try {
                 mExecutor.execute(() -> {
                     disconnectVpnRunner();
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java b/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java
index 7045e65..d994849 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java
@@ -899,6 +899,9 @@
      * port id.
      */
     int portIdToPath(int portId) {
+        if (portId == Constants.CEC_SWITCH_HOME) {
+            return getPhysicalAddress();
+        }
         HdmiPortInfo portInfo = getPortInfo(portId);
         if (portInfo == null) {
             Slog.e(TAG, "Cannot find the port info: " + portId);
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index fa95a34..ec7f561 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -243,6 +243,10 @@
     private static final String MIGRATED_FRP2 = "migrated_frp2";
     private static final String MIGRATED_KEYSTORE_NS = "migrated_keystore_namespace";
     private static final String MIGRATED_SP_CE_ONLY = "migrated_all_users_to_sp_and_bound_ce";
+    private static final String MIGRATED_SP_FULL = "migrated_all_users_to_sp_and_bound_keys";
+
+    private static final boolean FIX_UNLOCKED_DEVICE_REQUIRED_KEYS =
+            android.security.Flags.fixUnlockedDeviceRequiredKeys();
 
     // Duration that LockSettingsService will store the gatekeeper password for. This allows
     // multiple biometric enrollments without prompting the user to enter their password via
@@ -853,9 +857,11 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) {
-                // Notify keystore that a new user was added.
-                final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
-                AndroidKeyStoreMaintenance.onUserAdded(userHandle);
+                if (!FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) {
+                    // Notify keystore that a new user was added.
+                    final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
+                    AndroidKeyStoreMaintenance.onUserAdded(userHandle);
+                }
             } else if (Intent.ACTION_USER_STARTING.equals(intent.getAction())) {
                 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
                 mStorage.prefetchUser(userHandle);
@@ -1019,24 +1025,53 @@
             }
             mEarlyCreatedUsers = null; // no longer needed
 
-            // Also do a one-time migration of all users to SP-based credentials with the CE key
-            // encrypted by the SP.  This is needed for the system user on the first boot of a
-            // device, as the system user is special and never goes through the user creation flow
-            // that other users do.  It is also needed for existing users on a device upgraded from
-            // Android 13 or earlier, where users with no LSKF didn't necessarily have an SP, and if
-            // they did have an SP then their CE key wasn't encrypted by it.
+            // Do a one-time migration for any unsecured users: create the user's synthetic password
+            // if not already done, encrypt the user's CE key with the synthetic password if not
+            // already done, and create the user's Keystore super keys if not already done.
             //
-            // If this gets interrupted (e.g. by the device powering off), there shouldn't be a
-            // problem since this will run again on the next boot, and setCeStorageProtection() is
-            // okay with the CE key being already protected by the given secret.
-            if (getString(MIGRATED_SP_CE_ONLY, null, 0) == null) {
-                for (UserInfo user : mUserManager.getAliveUsers()) {
-                    removeStateForReusedUserIdIfNecessary(user.id, user.serialNumber);
-                    synchronized (mSpManager) {
-                        migrateUserToSpWithBoundCeKeyLocked(user.id);
+            // This is needed for the following cases:
+            //
+            // - Finalizing the creation of the system user on the first boot of a device, as the
+            //   system user is special and doesn't go through the normal user creation flow.
+            //
+            // - Upgrading from Android 13 or earlier, where unsecured users didn't necessarily have
+            //   a synthetic password, and if they did have a synthetic password their CE key wasn't
+            //   encrypted by it.  Also, unsecured users didn't have Keystore super keys.
+            //
+            // - Upgrading from Android 14, where unsecured users didn't have Keystore super keys.
+            //
+            // The end result is that all users, regardless of whether they are secured or not, have
+            // a synthetic password with all keys initialized and protected by it.
+            //
+            // Note: if this migration gets interrupted (e.g. by the device powering off), there
+            // shouldn't be a problem since this will run again on the next boot, and
+            // setCeStorageProtection() and initKeystoreSuperKeys(..., true) are idempotent.
+            if (FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) {
+                if (!getBoolean(MIGRATED_SP_FULL, false, 0)) {
+                    for (UserInfo user : mUserManager.getAliveUsers()) {
+                        removeStateForReusedUserIdIfNecessary(user.id, user.serialNumber);
+                        synchronized (mSpManager) {
+                            migrateUserToSpWithBoundKeysLocked(user.id);
+                        }
                     }
+                    setBoolean(MIGRATED_SP_FULL, true, 0);
                 }
-                setString(MIGRATED_SP_CE_ONLY, "true", 0);
+            } else {
+                if (getString(MIGRATED_SP_CE_ONLY, null, 0) == null) {
+                    for (UserInfo user : mUserManager.getAliveUsers()) {
+                        removeStateForReusedUserIdIfNecessary(user.id, user.serialNumber);
+                        synchronized (mSpManager) {
+                            migrateUserToSpWithBoundCeKeyLocked(user.id);
+                        }
+                    }
+                    setString(MIGRATED_SP_CE_ONLY, "true", 0);
+                }
+
+                if (getBoolean(MIGRATED_SP_FULL, false, 0)) {
+                    // The FIX_UNLOCKED_DEVICE_REQUIRED_KEYS flag was enabled but then got disabled.
+                    // Ensure the full migration runs again the next time the flag is enabled...
+                    setBoolean(MIGRATED_SP_FULL, false, 0);
+                }
             }
 
             mThirdPartyAppsStarted = true;
@@ -1067,6 +1102,37 @@
         }
     }
 
+    @GuardedBy("mSpManager")
+    private void migrateUserToSpWithBoundKeysLocked(@UserIdInt int userId) {
+        if (isUserSecure(userId)) {
+            Slogf.d(TAG, "User %d is secured; no migration needed", userId);
+            return;
+        }
+        long protectorId = getCurrentLskfBasedProtectorId(userId);
+        if (protectorId == SyntheticPasswordManager.NULL_PROTECTOR_ID) {
+            Slogf.i(TAG, "Migrating unsecured user %d to SP-based credential", userId);
+            initializeSyntheticPassword(userId);
+            return;
+        }
+        Slogf.i(TAG, "Existing unsecured user %d has a synthetic password", userId);
+        AuthenticationResult result = mSpManager.unlockLskfBasedProtector(
+                getGateKeeperService(), protectorId, LockscreenCredential.createNone(), userId,
+                null);
+        SyntheticPassword sp = result.syntheticPassword;
+        if (sp == null) {
+            Slogf.wtf(TAG, "Failed to unwrap synthetic password for unsecured user %d", userId);
+            return;
+        }
+        // While setCeStorageProtection() is idempotent, it does log some error messages when called
+        // again.  Skip it if we know it was already handled by an earlier upgrade to Android 14.
+        if (getString(MIGRATED_SP_CE_ONLY, null, 0) == null) {
+            Slogf.i(TAG, "Encrypting CE key of user %d with synthetic password", userId);
+            setCeStorageProtection(userId, sp);
+        }
+        Slogf.i(TAG, "Initializing Keystore super keys for user %d", userId);
+        initKeystoreSuperKeys(userId, sp, /* allowExisting= */ true);
+    }
+
     /**
      * Returns the lowest password quality that still presents the same UI for entering it.
      *
@@ -1348,6 +1414,20 @@
         AndroidKeyStoreMaintenance.onUserPasswordChanged(userHandle, password);
     }
 
+    @VisibleForTesting /** Note: this method is overridden in unit tests */
+    void initKeystoreSuperKeys(@UserIdInt int userId, SyntheticPassword sp, boolean allowExisting) {
+        final byte[] password = sp.deriveKeyStorePassword();
+        try {
+            int res = AndroidKeyStoreMaintenance.initUserSuperKeys(userId, password, allowExisting);
+            if (res != 0) {
+                throw new IllegalStateException("Failed to initialize Keystore super keys for user "
+                        + userId);
+            }
+        } finally {
+            Arrays.fill(password, (byte) 0);
+        }
+    }
+
     private void unlockKeystore(int userId, SyntheticPassword sp) {
         Authorization.onLockScreenEvent(false, userId, sp.deriveKeyStorePassword(), null);
     }
@@ -2071,6 +2151,9 @@
                 return;
             }
             onSyntheticPasswordUnlocked(userId, result.syntheticPassword);
+            if (FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) {
+                unlockKeystore(userId, result.syntheticPassword);
+            }
             unlockCeStorage(userId, result.syntheticPassword);
         }
     }
@@ -2350,6 +2433,16 @@
     }
 
     private void createNewUser(@UserIdInt int userId, int userSerialNumber) {
+
+        // Delete all Keystore keys for userId, just in case any were left around from a removed
+        // user with the same userId.  This should be unnecessary, but we've been doing this for a
+        // long time, so for now we keep doing it just in case it's ever important.  Don't wait
+        // until initKeystoreSuperKeys() to do this; that can be delayed if the user is being
+        // created during early boot, and maybe something will use Keystore before then.
+        if (FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) {
+            AndroidKeyStoreMaintenance.onUserAdded(userId);
+        }
+
         synchronized (mUserCreationAndRemovalLock) {
             // During early boot, don't actually create the synthetic password yet, but rather
             // automatically delay it to later.  We do this because protecting the synthetic
@@ -2756,7 +2849,7 @@
 
     /**
      * Creates the synthetic password (SP) for the given user, protects it with an empty LSKF, and
-     * protects the user's CE key with a key derived from the SP.
+     * protects the user's CE storage key and Keystore super keys with keys derived from the SP.
      *
      * <p>This is called just once in the lifetime of the user: at user creation time (possibly
      * delayed until the time when Weaver is guaranteed to be available), or when upgrading from
@@ -2775,6 +2868,9 @@
                     LockscreenCredential.createNone(), sp, userId);
             setCurrentLskfBasedProtectorId(protectorId, userId);
             setCeStorageProtection(userId, sp);
+            if (FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) {
+                initKeystoreSuperKeys(userId, sp, /* allowExisting= */ false);
+            }
             onSyntheticPasswordCreated(userId, sp);
             Slogf.i(TAG, "Successfully initialized synthetic password for user %d", userId);
             return sp;
@@ -2867,11 +2963,10 @@
     /**
      * Changes the user's LSKF by creating an LSKF-based protector that uses the new LSKF (which may
      * be empty) and replacing the old LSKF-based protector with it.  The SP itself is not changed.
-     *
-     * Also maintains the invariants described in {@link SyntheticPasswordManager} by
-     * setting/clearing the protection (by the SP) on the user's auth-bound Keystore keys when the
-     * LSKF is added/removed, respectively.  If an LSKF is being added, then the Gatekeeper auth
-     * token is also refreshed.
+     * <p>
+     * Also maintains the invariants described in {@link SyntheticPasswordManager} by enrolling /
+     * deleting the synthetic password into Gatekeeper as the LSKF is set / cleared, and asking
+     * Keystore to delete the user's auth-bound keys when the LSKF is cleared.
      */
     @GuardedBy("mSpManager")
     private long setLockCredentialWithSpLocked(LockscreenCredential credential,
@@ -2890,7 +2985,9 @@
             if (!mSpManager.hasSidForUser(userId)) {
                 mSpManager.newSidForUser(getGateKeeperService(), sp, userId);
                 mSpManager.verifyChallenge(getGateKeeperService(), sp, 0L, userId);
-                setKeystorePassword(sp.deriveKeyStorePassword(), userId);
+                if (!FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) {
+                    setKeystorePassword(sp.deriveKeyStorePassword(), userId);
+                }
             }
         } else {
             // Cache all profile password if they use unified work challenge. This will later be
@@ -2901,7 +2998,11 @@
             gateKeeperClearSecureUserId(userId);
             unlockCeStorage(userId, sp);
             unlockKeystore(userId, sp);
-            setKeystorePassword(null, userId);
+            if (FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) {
+                AndroidKeyStoreMaintenance.onUserLskfRemoved(userId);
+            } else {
+                setKeystorePassword(null, userId);
+            }
             removeBiometricsForUser(userId);
         }
         setCurrentLskfBasedProtectorId(newProtectorId, userId);
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
index 8e9c21f..cc205d4 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
@@ -90,10 +90,15 @@
  *
  *  - The user's credential-encrypted storage is always protected by the SP.
  *
- *  - The user's auth-bound Keystore keys are protected by the SP, but only while an LSKF is set.
- *    This works by setting the user's Keystore and Gatekeeper passwords to SP-derived secrets, but
- *    only while an LSKF is set.  When the LSKF is removed, these passwords are cleared,
- *    invalidating the user's auth-bound keys.
+ *  - The user's Keystore superencryption keys are always protected by the SP.  These in turn
+ *    protect the Keystore keys that require user authentication, an unlocked device, or both.
+ *
+ *  - A secret derived from the synthetic password is enrolled in Gatekeeper for the user, but only
+ *    while the user has a (nonempty) LSKF.  This enrollment has an associated ID called the Secure
+ *    user ID or SID.  This use of Gatekeeper, which is separate from the use of GateKeeper that may
+ *    be used in the LSKF-based protector, makes it so that unlocking the synthetic password
+ *    generates a HardwareAuthToken (but only when the user has LSKF).  That HardwareAuthToken can
+ *    be provided to KeyMint to authorize the use of the user's authentication-bound Keystore keys.
  *
  * Files stored on disk for each user:
  *   For the SP itself, stored under NULL_PROTECTOR_ID:
diff --git a/services/core/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java
index 1b7d1ba..9a0b391 100644
--- a/services/core/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java
@@ -208,7 +208,7 @@
                 //    network is the system default. So, if the VPN  is up and underlying network
                 //    (e.g., wifi) disconnects, CS will inform apps that the VPN's capabilities have
                 //    changed to match the new default network (e.g., cell).
-                mVpn.startLegacyVpnPrivileged(mProfile, network, egressProp);
+                mVpn.startLegacyVpnPrivileged(mProfile);
             } catch (IllegalStateException e) {
                 mAcceptedEgressIface = null;
                 Log.e(TAG, "Failed to start VPN", e);
diff --git a/services/core/java/com/android/server/net/NetworkManagementService.java b/services/core/java/com/android/server/net/NetworkManagementService.java
index 550ad5d..681d1a0 100644
--- a/services/core/java/com/android/server/net/NetworkManagementService.java
+++ b/services/core/java/com/android/server/net/NetworkManagementService.java
@@ -74,7 +74,6 @@
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.HexDump;
 import com.android.modules.utils.build.SdkLevel;
-import com.android.net.flags.Flags;
 import com.android.net.module.util.NetdUtils;
 import com.android.net.module.util.PermissionUtils;
 import com.android.server.FgThread;
@@ -328,10 +327,10 @@
     /**
      * Notify our observers of a change in the data activity state of the interface
      */
-    private void notifyInterfaceClassActivity(int type, boolean isActive, long tsNanos,
+    private void notifyInterfaceClassActivity(int label, boolean isActive, long tsNanos,
             int uid) {
         invokeForAllObservers(o -> o.interfaceClassDataActivityChanged(
-                type, isActive, tsNanos, uid));
+                label, isActive, tsNanos, uid));
     }
 
     // Sync the state of the given chain with the native daemon.
@@ -1062,7 +1061,7 @@
             }
             Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "setDataSaverModeEnabled");
             try {
-                if (Flags.setDataSaverViaCm()) {
+                if (SdkLevel.isAtLeastV()) {
                     // setDataSaverEnabled throws if it fails to set data saver.
                     mContext.getSystemService(ConnectivityManager.class)
                             .setDataSaverEnabled(enable);
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 76ee845..cc892a0 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -1421,6 +1421,7 @@
 
         final NetworkStats nonTaggedStats =
                 NetworkStatsUtils.fromPublicNetworkStats(queryNonTaggedStats);
+        queryNonTaggedStats.close();
         if (!includeTags) return nonTaggedStats;
 
         final android.app.usage.NetworkStats queryTaggedStats =
@@ -1429,6 +1430,7 @@
                         currentTimeInMillis);
         final NetworkStats taggedStats =
                 NetworkStatsUtils.fromPublicNetworkStats(queryTaggedStats);
+        queryTaggedStats.close();
         return nonTaggedStats.add(taggedStats);
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
index 1c33d0d..18961c0 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
@@ -34,6 +34,7 @@
 
 import com.android.internal.widget.LockscreenCredential;
 import com.android.server.ServiceThread;
+import com.android.server.locksettings.SyntheticPasswordManager.SyntheticPassword;
 import com.android.server.locksettings.recoverablekeystore.RecoverableKeyStoreManager;
 import com.android.server.pm.UserManagerInternal;
 
@@ -203,6 +204,10 @@
     }
 
     @Override
+    void initKeystoreSuperKeys(int userId, SyntheticPassword sp, boolean allowExisting) {
+    }
+
+    @Override
     protected boolean isCredentialSharableWithParent(int userId) {
         UserInfo userInfo = mUserManager.getUserInfo(userId);
         return userInfo.isCloneProfile() || userInfo.isManagedProfile();
diff --git a/services/tests/servicestests/src/com/android/server/net/LockdownVpnTrackerTest.java b/services/tests/servicestests/src/com/android/server/net/LockdownVpnTrackerTest.java
index 949f8e7..0e881ef 100644
--- a/services/tests/servicestests/src/com/android/server/net/LockdownVpnTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/LockdownVpnTrackerTest.java
@@ -221,7 +221,7 @@
         callCallbacksForNetworkConnect(defaultCallback, mNetwork);
 
         // Vpn is starting
-        verify(mVpn).startLegacyVpnPrivileged(mProfile, mNetwork, TEST_CELL_LP);
+        verify(mVpn).startLegacyVpnPrivileged(mProfile);
         verify(mNotificationManager).notify(any(), eq(SystemMessage.NOTE_VPN_STATUS),
                 argThat(notification -> isExpectedNotification(notification,
                         R.string.vpn_lockdown_connecting, R.drawable.vpn_disconnected)));
@@ -242,7 +242,7 @@
         // LockdownVpnTracker#handleStateChangedLocked. This is a bug.
         // TODO: consider fixing this.
         verify(mVpn, never()).stopVpnRunnerPrivileged();
-        verify(mVpn, never()).startLegacyVpnPrivileged(any(), any(), any());
+        verify(mVpn, never()).startLegacyVpnPrivileged(any());
         verify(mNotificationManager, never()).cancel(any(), eq(SystemMessage.NOTE_VPN_STATUS));
     }
 
@@ -302,7 +302,7 @@
 
         // Vpn is restarted.
         verify(mVpn).stopVpnRunnerPrivileged();
-        verify(mVpn).startLegacyVpnPrivileged(mProfile, mNetwork2, wifiLp);
+        verify(mVpn).startLegacyVpnPrivileged(mProfile);
         verify(mNotificationManager, never()).cancel(any(), eq(SystemMessage.NOTE_VPN_STATUS));
         verify(mNotificationManager).notify(any(), eq(SystemMessage.NOTE_VPN_STATUS),
                 argThat(notification -> isExpectedNotification(notification,
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkManagementServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkManagementServiceTest.java
index 2cdfbff..13dc120 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkManagementServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkManagementServiceTest.java
@@ -57,7 +57,7 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.app.IBatteryStats;
-import com.android.net.flags.Flags;
+import com.android.modules.utils.build.SdkLevel;
 
 import org.junit.After;
 import org.junit.Before;
@@ -264,7 +264,7 @@
         verify(mCm).addUidToMeteredNetworkDenyList(TEST_UID);
 
         mNMService.setDataSaverModeEnabled(true);
-        if (Flags.setDataSaverViaCm()) {
+        if (SdkLevel.isAtLeastV()) {
             verify(mCm).setDataSaverEnabled(true);
         } else {
             verify(mNetdService).bandwidthEnableDataSaver(true);
@@ -284,7 +284,7 @@
         mNMService.setUidOnMeteredNetworkAllowlist(TEST_UID, false);
         verify(mCm).removeUidFromMeteredNetworkAllowList(TEST_UID);
         mNMService.setDataSaverModeEnabled(false);
-        if (Flags.setDataSaverViaCm()) {
+        if (SdkLevel.isAtLeastV()) {
             verify(mCm).setDataSaverEnabled(false);
         } else {
             verify(mNetdService).bandwidthEnableDataSaver(false);