Merge "NetdEventListenerService extends BaseNetdEventListener"
diff --git a/ProtoLibraries.bp b/ProtoLibraries.bp
index c12f5b4..a0944d4 100644
--- a/ProtoLibraries.bp
+++ b/ProtoLibraries.bp
@@ -100,6 +100,8 @@
         ],
         type: "full",
     },
+    // b/267831518: Pin tradefed and dependencies to Java 11.
+    java_version: "11",
     // Protos have lots of MissingOverride and similar.
     errorprone: {
         enabled: false,
diff --git a/StubLibraries.bp b/StubLibraries.bp
index fc046fb..d043464 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -530,11 +530,17 @@
     extensions_info_file: ":sdk-extensions-info",
 }
 
+// This module can be built with:
+// m out/soong/.intermediates/frameworks/base/api_versions_module_lib/android_common/metalava/api-versions.xml
 droidstubs {
     name: "api_versions_module_lib",
     srcs: [":android_module_stubs_current_with_test_libs{.jar}"],
     generate_stubs: false,
     api_levels_annotations_enabled: true,
+    // this only has the non-updatable portions of the module lib sdk,
+    // which can reference classes from updatable apexes, so remove references to them
+    // from this api_versions file.
+    flags: ["--remove-missing-class-references-in-api-levels"],
     api_levels_annotations_dirs: [
         "sdk-dir",
         "api-versions-jars-dir",
@@ -548,6 +554,10 @@
     srcs: [":android_system_server_stubs_current_with_test_libs{.jar}"],
     generate_stubs: false,
     api_levels_annotations_enabled: true,
+    // this only has the non-updatable portions of the system server sdk,
+    // which can reference classes from updatable apexes, so remove references to them
+    // from this api_versions file.
+    flags: ["--remove-missing-class-references-in-api-levels"],
     api_levels_annotations_dirs: [
         "sdk-dir",
         "api-versions-jars-dir",
diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS
index 20869e0..eea607b 100644
--- a/core/java/android/app/OWNERS
+++ b/core/java/android/app/OWNERS
@@ -4,12 +4,12 @@
 
 # ActivityManager
 per-file ActivityManager* = file:/services/core/java/com/android/server/am/OWNERS
+per-file *ApplicationStartInfo* = file:/services/core/java/com/android/server/am/OWNERS
 per-file ApplicationErrorReport* = file:/services/core/java/com/android/server/am/OWNERS
 per-file ApplicationExitInfo* = file:/services/core/java/com/android/server/am/OWNERS
 per-file Application.java = file:/services/core/java/com/android/server/am/OWNERS
 per-file ApplicationLoaders.java = file:/services/core/java/com/android/server/am/OWNERS
 per-file ApplicationThreadConstants.java = file:/services/core/java/com/android/server/am/OWNERS
-per-file BroadcastOptions.java = file:/services/core/java/com/android/server/am/OWNERS
 per-file ContentProviderHolder* = file:/services/core/java/com/android/server/am/OWNERS
 per-file *ForegroundService* = file:/services/core/java/com/android/server/am/OWNERS
 per-file IActivityController.aidl = file:/services/core/java/com/android/server/am/OWNERS
@@ -50,6 +50,10 @@
 # Backup and Restore
 per-file IBackupAgent.aidl = file:/services/backup/OWNERS
 
+# Broadcasts
+per-file Broadcast* = file:/BROADCASTS_OWNERS
+per-file ReceiverInfo* = file:/BROADCASTS_OWNERS
+
 # LocaleManager
 per-file *Locale* = file:/services/core/java/com/android/server/locales/OWNERS
 
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 861a850..331a5ab 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -3467,7 +3467,7 @@
      * <p>An array of mandatory stream combinations which are applicable when device support the
      * 10-bit output capability
      * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT }
-     * This is an app-readable conversion of the maximum resolution mandatory stream combination
+     * This is an app-readable conversion of the 10 bit output mandatory stream combination
      * {@link android.hardware.camera2.CameraDevice#createCaptureSession tables}.</p>
      * <p>The array of
      * {@link android.hardware.camera2.params.MandatoryStreamCombination combinations} is
@@ -3492,7 +3492,7 @@
     /**
      * <p>An array of mandatory stream combinations which are applicable when device lists
      * {@code PREVIEW_STABILIZATION} in {@link CameraCharacteristics#CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES android.control.availableVideoStabilizationModes}.
-     * This is an app-readable conversion of the maximum resolution mandatory stream combination
+     * This is an app-readable conversion of the preview stabilization mandatory stream combination
      * {@link android.hardware.camera2.CameraDevice#createCaptureSession tables}.</p>
      * <p>The array of
      * {@link android.hardware.camera2.params.MandatoryStreamCombination combinations} is
diff --git a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
index c8dc2d0..b52daab 100644
--- a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
@@ -528,8 +528,15 @@
             boolean status = true;
             synchronized (mInterfaceLock) {
                 try {
-                    mSessionProcessor.onCaptureSessionStart(mRequestProcessor);
-                    mInitialized = true;
+                    if (mSessionProcessor != null) {
+                        mSessionProcessor.onCaptureSessionStart(mRequestProcessor);
+                        mInitialized = true;
+                    } else {
+                        Log.v(TAG, "Failed to start capture session, session released before " +
+                                "extension start!");
+                        status = false;
+                        mCaptureSession.close();
+                    }
                 } catch (RemoteException e) {
                     Log.e(TAG, "Failed to start capture session,"
                             + " extension service does not respond!");
diff --git a/core/java/android/nfc/cardemulation/CardEmulation.java b/core/java/android/nfc/cardemulation/CardEmulation.java
index 6a42091..ac3344e 100644
--- a/core/java/android/nfc/cardemulation/CardEmulation.java
+++ b/core/java/android/nfc/cardemulation/CardEmulation.java
@@ -265,12 +265,16 @@
      * @return whether AIDs in the category can be handled by a service
      *         specified by the foreground app.
      */
+    @SuppressWarnings("NonUserGetterCalled")
     public boolean categoryAllowsForegroundPreference(String category) {
         if (CATEGORY_PAYMENT.equals(category)) {
             boolean preferForeground = false;
+            Context contextAsUser = mContext.createContextAsUser(
+                    UserHandle.of(UserHandle.myUserId()), 0);
             try {
-                preferForeground = Settings.Secure.getIntForUser(mContext.getContentResolver(),
-                        Settings.Secure.NFC_PAYMENT_FOREGROUND, UserHandle.myUserId()) != 0;
+                preferForeground = Settings.Secure.getInt(
+                        contextAsUser.getContentResolver(),
+                        Settings.Secure.NFC_PAYMENT_FOREGROUND) != 0;
             } catch (SettingNotFoundException e) {
             }
             return preferForeground;
diff --git a/core/java/android/service/notification/OWNERS b/core/java/android/service/notification/OWNERS
index debb493..bb0e6ab 100644
--- a/core/java/android/service/notification/OWNERS
+++ b/core/java/android/service/notification/OWNERS
@@ -1,6 +1,7 @@
 # Bug component: 34005
 
 juliacr@google.com
-pixel@google.com
+yurilin@google.com
+jeffdq@google.com
 dsandler@android.com
 dsandler@google.com
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index c218a0b..754178ab 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -77,6 +77,16 @@
             "settings_app_allow_dark_theme_activation_at_bedtime";
 
     /**
+     * Flag to decouple bluetooth LE Audio Broadcast from Unicast
+     * If the flag is true, the broadcast feature will be enabled when the phone
+     * is connected to the BLE device.
+     * If the flag is false, it is not necessary to connect the BLE device.
+     * @hide
+     */
+    public static final String SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST =
+            "settings_need_connected_ble_device_for_broadcast";
+
+    /**
      * Hide back key in the Settings two pane design.
      * @hide
      */
@@ -110,6 +120,7 @@
         DEFAULT_FLAGS.put(SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS, "true");
         DEFAULT_FLAGS.put(SETTINGS_APP_ALLOW_DARK_THEME_ACTIVATION_AT_BEDTIME, "true");
         DEFAULT_FLAGS.put(SETTINGS_HIDE_SECOND_LAYER_PAGE_NAVIGATE_UP_BUTTON_IN_TWO_PANE, "true");
+        DEFAULT_FLAGS.put(SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST, "true");
     }
 
     private static final Set<String> PERSISTENT_FLAGS;
diff --git a/core/java/com/android/internal/app/OWNERS b/core/java/com/android/internal/app/OWNERS
index 69660ae..0d02683 100644
--- a/core/java/com/android/internal/app/OWNERS
+++ b/core/java/com/android/internal/app/OWNERS
@@ -6,6 +6,8 @@
 per-file *EmptyStateProvider.java = file:/packages/SystemUI/OWNERS
 per-file NetInitiatedActivity.java = file:/location/java/android/location/OWNERS
 per-file *BatteryStats* = file:/BATTERY_STATS_OWNERS
+per-file *SoundTrigger* = file:/media/java/android/media/soundtrigger/OWNERS
+
 
 # Voice Interaction
 per-file *Assist* = file:/core/java/android/service/voice/OWNERS
diff --git a/core/java/com/android/internal/expresslog/Histogram.java b/core/java/com/android/internal/expresslog/Histogram.java
index fe950c4..db70cac 100644
--- a/core/java/com/android/internal/expresslog/Histogram.java
+++ b/core/java/com/android/internal/expresslog/Histogram.java
@@ -20,7 +20,7 @@
 
 import com.android.internal.util.FrameworkStatsLog;
 
-/** CounterHistogram encapsulates StatsD write API calls */
+/** Histogram encapsulates StatsD write API calls */
 public final class Histogram {
 
     private final long mMetricIdHash;
@@ -42,10 +42,10 @@
                 /*count*/ 1, binIndex);
     }
 
-    /** Used by CounterHistogram to map data sample to corresponding bin */
+    /** Used by Histogram to map data sample to corresponding bin */
     public interface BinOptions {
         /**
-         * Returns bins count to be used by counter histogram
+         * Returns bins count to be used by a histogram
          *
          * @return bins count used to initialize Options, including overflow & underflow bins
          * @hide
@@ -62,7 +62,7 @@
         int getBinForSample(float sample);
     }
 
-    /** Used by CounterHistogram to map data sample to corresponding bin for on uniform bins */
+    /** Used by Histogram to map data sample to corresponding bin for uniform bins */
     public static final class UniformOptions implements BinOptions {
 
         private final int mBinCount;
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index 1fd0410..d192ad9 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -39,8 +39,7 @@
 import java.util.function.IntFunction;
 
 /**
- * ArrayUtils contains some methods that you can call to find out
- * the most efficient increments by which to grow arrays.
+ * Static utility methods for arrays that aren't already included in {@link java.util.Arrays}.
  */
 public class ArrayUtils {
     private static final int CACHE_SIZE = 73;
@@ -341,15 +340,16 @@
     }
 
     /**
-     * Combine multiple arrays into a single array.
+     * Returns the concatenation of the given arrays.  Only works for object arrays, not for
+     * primitive arrays.  See {@link #concat(byte[]...)} for a variant that works on byte arrays.
      *
      * @param kind The class of the array elements
-     * @param arrays The arrays to combine
+     * @param arrays The arrays to concatenate.  Null arrays are treated as empty.
      * @param <T> The class of the array elements (inferred from kind).
      * @return A single array containing all the elements of the parameter arrays.
      */
     @SuppressWarnings("unchecked")
-    public static @NonNull <T> T[] concatElements(Class<T> kind, @Nullable T[]... arrays) {
+    public static @NonNull <T> T[] concat(Class<T> kind, @Nullable T[]... arrays) {
         if (arrays == null || arrays.length == 0) {
             return createEmptyArray(kind);
         }
@@ -390,6 +390,29 @@
         return (T[]) Array.newInstance(kind, 0);
     }
 
+    /**
+     * Returns the concatenation of the given byte arrays.  Null arrays are treated as empty.
+     */
+    public static @NonNull byte[] concat(@Nullable byte[]... arrays) {
+        if (arrays == null) {
+            return new byte[0];
+        }
+        int totalLength = 0;
+        for (byte[] a : arrays) {
+            if (a != null) {
+                totalLength += a.length;
+            }
+        }
+        final byte[] result = new byte[totalLength];
+        int pos = 0;
+        for (byte[] a : arrays) {
+            if (a != null) {
+                System.arraycopy(a, 0, result, pos, a.length);
+                pos += a.length;
+            }
+        }
+        return result;
+    }
 
     /**
      * Adds value to given array if not already present, providing set-like
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 963a83e..fad9e0e 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -1923,15 +1923,16 @@
 
     const char* nice_name_ptr = nice_name.has_value() ? nice_name.value().c_str() : nullptr;
     android_mallopt_gwp_asan_options_t gwp_asan_options;
+    const char* kGwpAsanAppRecoverableSysprop =
+            "persist.device_config.memory_safety_native.gwp_asan_recoverable_apps";
     // The system server doesn't have its nice name set by the time SpecializeCommon is called.
     gwp_asan_options.program_name = nice_name_ptr ?: process_name;
     switch (runtime_flags & RuntimeFlags::GWP_ASAN_LEVEL_MASK) {
         default:
         case RuntimeFlags::GWP_ASAN_LEVEL_DEFAULT:
-            // TODO(b/247012630): Switch this to Action::TURN_ON_FOR_APP_SAMPLED_NON_CRASHING once
-            // performance and syshealth testing is completed, making the default for non-system
-            // apps that don't specify a `gwpAsanMode` in their manifest to be sampled-recoverable.
-            gwp_asan_options.desire = Action::DONT_TURN_ON_UNLESS_OVERRIDDEN;
+            gwp_asan_options.desire = GetBoolProperty(kGwpAsanAppRecoverableSysprop, true)
+                    ? Action::TURN_ON_FOR_APP_SAMPLED_NON_CRASHING
+                    : Action::DONT_TURN_ON_UNLESS_OVERRIDDEN;
             android_mallopt(M_INITIALIZE_GWP_ASAN, &gwp_asan_options, sizeof(gwp_asan_options));
             break;
         case RuntimeFlags::GWP_ASAN_LEVEL_NEVER:
diff --git a/core/proto/android/app/OWNERS b/core/proto/android/app/OWNERS
index 4d76aee..a137ea9 100644
--- a/core/proto/android/app/OWNERS
+++ b/core/proto/android/app/OWNERS
@@ -1,2 +1,3 @@
+per-file appstartinfo.proto = file:/services/core/java/com/android/server/am/OWNERS
 per-file location_time_zone_manager.proto = file:platform/frameworks/base:/services/core/java/com/android/server/timezonedetector/OWNERS
 per-file time_zone_detector.proto = file:platform/frameworks/base:/services/core/java/com/android/server/timezonedetector/OWNERS
diff --git a/core/proto/android/server/OWNERS b/core/proto/android/server/OWNERS
index 72d39bf..c6d3cda 100644
--- a/core/proto/android/server/OWNERS
+++ b/core/proto/android/server/OWNERS
@@ -1 +1,2 @@
+per-file activitymanagerservice.proto = file:/services/core/java/com/android/server/am/OWNERS
 per-file window*.proto = file:/services/core/java/com/android/server/wm/OWNERS
diff --git a/core/tests/coretests/src/android/credentials/OWNERS b/core/tests/coretests/src/android/credentials/OWNERS
new file mode 100644
index 0000000..00b5e06
--- /dev/null
+++ b/core/tests/coretests/src/android/credentials/OWNERS
@@ -0,0 +1,2 @@
+include /core/java/android/credentials/OWNERS
+
diff --git a/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java b/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java
index cb30b3f..c66a743 100644
--- a/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java
@@ -16,8 +16,6 @@
 
 package com.android.internal.util;
 
-import static com.android.internal.util.ArrayUtils.concatElements;
-
 import static org.junit.Assert.assertArrayEquals;
 
 import junit.framework.TestCase;
@@ -156,61 +154,107 @@
                 ArrayUtils.removeLong(new long[] { 1, 2, 3, 1 }, 1));
     }
 
-    public void testConcatEmpty() throws Exception {
-        assertArrayEquals(new Long[] {},
-                concatElements(Long.class, null, null));
-        assertArrayEquals(new Long[] {},
-                concatElements(Long.class, new Long[] {}, null));
-        assertArrayEquals(new Long[] {},
-                concatElements(Long.class, null, new Long[] {}));
-        assertArrayEquals(new Long[] {},
-                concatElements(Long.class, new Long[] {}, new Long[] {}));
+    public void testConcat_zeroObjectArrays() {
+        // empty varargs array
+        assertArrayEquals(new String[] {}, ArrayUtils.concat(String.class));
+        // null varargs array
+        assertArrayEquals(new String[] {}, ArrayUtils.concat(String.class, (String[][]) null));
     }
 
-    public void testconcatElements() throws Exception {
+    public void testConcat_oneObjectArray() {
+        assertArrayEquals(new String[] { "1", "2" },
+                ArrayUtils.concat(String.class, new String[] { "1", "2" }));
+    }
+
+    public void testConcat_oneEmptyObjectArray() {
+        assertArrayEquals(new String[] {}, ArrayUtils.concat(String.class, (String[]) null));
+        assertArrayEquals(new String[] {}, ArrayUtils.concat(String.class, new String[] {}));
+    }
+
+    public void testConcat_twoObjectArrays() {
         assertArrayEquals(new Long[] { 1L },
-                concatElements(Long.class, new Long[] { 1L }, new Long[] {}));
+                ArrayUtils.concat(Long.class, new Long[] { 1L }, new Long[] {}));
         assertArrayEquals(new Long[] { 1L },
-                concatElements(Long.class, new Long[] {}, new Long[] { 1L }));
+                ArrayUtils.concat(Long.class, new Long[] {}, new Long[] { 1L }));
         assertArrayEquals(new Long[] { 1L, 2L },
-                concatElements(Long.class, new Long[] { 1L }, new Long[] { 2L }));
+                ArrayUtils.concat(Long.class, new Long[] { 1L }, new Long[] { 2L }));
         assertArrayEquals(new Long[] { 1L, 2L, 3L, 4L },
-                concatElements(Long.class, new Long[] { 1L, 2L }, new Long[] { 3L, 4L }));
+                ArrayUtils.concat(Long.class, new Long[] { 1L, 2L }, new Long[] { 3L, 4L }));
     }
 
-    public void testConcatElements_threeWay() {
+    public void testConcat_twoEmptyObjectArrays() {
+        assertArrayEquals(new Long[] {}, ArrayUtils.concat(Long.class, null, null));
+        assertArrayEquals(new Long[] {}, ArrayUtils.concat(Long.class, new Long[] {}, null));
+        assertArrayEquals(new Long[] {}, ArrayUtils.concat(Long.class, null, new Long[] {}));
+        assertArrayEquals(new Long[] {},
+                ArrayUtils.concat(Long.class, new Long[] {}, new Long[] {}));
+    }
+
+    public void testConcat_threeObjectArrays() {
         String[] array1 = { "1", "2" };
         String[] array2 = { "3", "4" };
         String[] array3 = { "5", "6" };
-        String[] expectation = {"1", "2", "3", "4", "5", "6"};
+        String[] expectation = { "1", "2", "3", "4", "5", "6" };
 
-        String[] concatResult = ArrayUtils.concatElements(String.class, array1, array2, array3);
-        assertArrayEquals(expectation, concatResult);
+        assertArrayEquals(expectation, ArrayUtils.concat(String.class, array1, array2, array3));
     }
 
-
-    public void testConcatElements_threeWayWithNull() {
+    public void testConcat_threeObjectArraysWithNull() {
         String[] array1 = { "1", "2" };
         String[] array2 = null;
         String[] array3 = { "5", "6" };
-        String[] expectation = {"1", "2", "5", "6"};
+        String[] expectation = { "1", "2", "5", "6" };
 
-        String[] concatResult = ArrayUtils.concatElements(String.class, array1, array2, array3);
-        assertArrayEquals(expectation, concatResult);
+        assertArrayEquals(expectation, ArrayUtils.concat(String.class, array1, array2, array3));
     }
 
-    public void testConcatElements_zeroElements() {
-        String[] expectation = new String[0];
-
-        String[] concatResult = ArrayUtils.concatElements(String.class);
-        assertArrayEquals(expectation, concatResult);
+    public void testConcat_zeroByteArrays() {
+        // empty varargs array
+        assertArrayEquals(new byte[] {}, ArrayUtils.concat());
+        // null varargs array
+        assertArrayEquals(new byte[] {}, ArrayUtils.concat((byte[][]) null));
     }
 
-    public void testConcatElements_oneNullElement() {
-        String[] expectation = new String[0];
-
-        String[] concatResult = ArrayUtils.concatElements(String.class, null);
-        assertArrayEquals(expectation, concatResult);
+    public void testConcat_oneByteArray() {
+        assertArrayEquals(new byte[] { 1, 2 }, ArrayUtils.concat(new byte[] { 1, 2 }));
     }
 
+    public void testConcat_oneEmptyByteArray() {
+        assertArrayEquals(new byte[] {}, ArrayUtils.concat((byte[]) null));
+        assertArrayEquals(new byte[] {}, ArrayUtils.concat(new byte[] {}));
+    }
+
+    public void testConcat_twoByteArrays() {
+        assertArrayEquals(new byte[] { 1 }, ArrayUtils.concat(new byte[] { 1 }, new byte[] {}));
+        assertArrayEquals(new byte[] { 1 }, ArrayUtils.concat(new byte[] {}, new byte[] { 1 }));
+        assertArrayEquals(new byte[] { 1, 2 },
+                ArrayUtils.concat(new byte[] { 1 }, new byte[] { 2 }));
+        assertArrayEquals(new byte[] { 1, 2, 3, 4 },
+                ArrayUtils.concat(new byte[] { 1, 2 }, new byte[] { 3, 4 }));
+    }
+
+    public void testConcat_twoEmptyByteArrays() {
+        assertArrayEquals(new byte[] {}, ArrayUtils.concat((byte[]) null, null));
+        assertArrayEquals(new byte[] {}, ArrayUtils.concat(new byte[] {}, null));
+        assertArrayEquals(new byte[] {}, ArrayUtils.concat((byte[]) null, new byte[] {}));
+        assertArrayEquals(new byte[] {}, ArrayUtils.concat(new byte[] {}, new byte[] {}));
+    }
+
+    public void testConcat_threeByteArrays() {
+        byte[] array1 = { 1, 2 };
+        byte[] array2 = { 3, 4 };
+        byte[] array3 = { 5, 6 };
+        byte[] expectation = { 1, 2, 3, 4, 5, 6 };
+
+        assertArrayEquals(expectation, ArrayUtils.concat(array1, array2, array3));
+    }
+
+    public void testConcat_threeByteArraysWithNull() {
+        byte[] array1 = { 1, 2 };
+        byte[] array2 = null;
+        byte[] array3 = { 5, 6 };
+        byte[] expectation = { 1, 2, 5, 6 };
+
+        assertArrayEquals(expectation, ArrayUtils.concat(array1, array2, array3));
+    }
 }
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index 663e8e4..9108449 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -116,6 +116,36 @@
         <item>full</item>
     </string-array>
 
+    <!-- Titles for Bluetooth HCI Snoop Filtered Logging -->
+    <string-array name="bt_hci_snoop_log_filters_entries">
+        <item>Headers Filtered</item>
+        <item>A2DP Media Packets Filtered</item>
+        <item>RFCOMM Channel Filtered</item>
+    </string-array>
+
+        <!-- Values for Bluetooth HCI Snoop Filtered Logging -->
+    <string-array name="bt_hci_snoop_log_filters_values" translatable="false">
+        <item>headers</item>
+        <item>profiles.a2dp</item>
+        <item>profiles.rfcomm</item>
+    </string-array>
+
+        <!-- Titles for Bluetooth HCI Snoop Filtered Logging -->
+    <string-array name="bt_hci_snoop_log_profile_filter_entries">
+        <item>Disabled</item>
+        <item>Magic</item>
+        <item>Header</item>
+        <item>Full Filter</item>
+    </string-array>
+
+        <!-- Values for Bluetooth HCI Snoop Filtered Logging -->
+    <string-array name="bt_hci_snoop_log_profile_filter_values" translatable="false">
+        <item>disabled</item>
+        <item>magic</item>
+        <item>header</item>
+        <item>fullfilter</item>
+    </string-array>
+
     <!-- Titles for Bluetooth AVRCP Versions -->
     <string-array name="bluetooth_avrcp_versions">
         <item>AVRCP 1.5 (Default)</item>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
index 1a65717..1940986 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
@@ -236,7 +236,7 @@
     /**
      * @return whether high quality audio is enabled or not
      */
-    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+    @RequiresApi(Build.VERSION_CODES.TIRAMISU)
     public boolean isHighQualityAudioEnabled(BluetoothDevice device) {
         BluetoothDevice bluetoothDevice = (device != null) ? device : getActiveDevice();
         if (bluetoothDevice == null) {
@@ -288,7 +288,7 @@
      * @param device to get codec label from
      * @return the label associated with the device codec
      */
-    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+    @RequiresApi(Build.VERSION_CODES.TIRAMISU)
     public String getHighQualityAudioOptionLabel(BluetoothDevice device) {
         BluetoothDevice bluetoothDevice = (device != null) ? device : getActiveDevice();
         int unknownCodecId = R.string.bluetooth_profile_a2dp_high_quality_unknown_codec;
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index d3afccc..6aa08f2 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -875,16 +875,16 @@
         String[] whitelist;
         Map<String, Validator> validators = null;
         if (contentUri.equals(Settings.Secure.CONTENT_URI)) {
-            whitelist = ArrayUtils.concatElements(String.class, SecureSettings.SETTINGS_TO_BACKUP,
+            whitelist = ArrayUtils.concat(String.class, SecureSettings.SETTINGS_TO_BACKUP,
                     Settings.Secure.LEGACY_RESTORE_SETTINGS,
                     DeviceSpecificSettings.DEVICE_SPECIFIC_SETTINGS_TO_BACKUP);
             validators = SecureSettingsValidators.VALIDATORS;
         } else if (contentUri.equals(Settings.System.CONTENT_URI)) {
-            whitelist = ArrayUtils.concatElements(String.class, SystemSettings.SETTINGS_TO_BACKUP,
+            whitelist = ArrayUtils.concat(String.class, SystemSettings.SETTINGS_TO_BACKUP,
                     Settings.System.LEGACY_RESTORE_SETTINGS);
             validators = SystemSettingsValidators.VALIDATORS;
         } else if (contentUri.equals(Settings.Global.CONTENT_URI)) {
-            whitelist = ArrayUtils.concatElements(String.class, GlobalSettings.SETTINGS_TO_BACKUP,
+            whitelist = ArrayUtils.concat(String.class, GlobalSettings.SETTINGS_TO_BACKUP,
                     Settings.Global.LEGACY_RESTORE_SETTINGS);
             validators = GlobalSettingsValidators.VALIDATORS;
         } else {
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 53f1227..422b049 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2348,7 +2348,10 @@
     <string name="media_output_broadcast_update_error">Can\u2019t save. Try again.</string>
     <!-- The error message when Broadcast name/code update failed and can't change again[CHAR LIMIT=60] -->
     <string name="media_output_broadcast_last_update_error">Can\u2019t save.</string>
-
+    <!-- The hint message when Broadcast code is less than 4 characters [CHAR LIMIT=60] -->
+    <string name="media_output_broadcast_code_hint_no_less_than_min">Use at least 4 characters</string>
+    <!-- The hint message when Broadcast code is more than 16 characters [CHAR LIMIT=60] -->
+    <string name="media_output_broadcast_code_hint_no_more_than_max">Use fewer than 16 characters</string>
 
     <!-- Label for clip data when copying the build number off QS [CHAR LIMIT=NONE]-->
     <string name="build_number_clip_data_label">Build number</string>
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java
index 35baf013..12d6b7c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java
@@ -20,6 +20,8 @@
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.os.Bundle;
+import android.text.Editable;
+import android.text.TextWatcher;
 import android.text.method.HideReturnsTransformationMethod;
 import android.text.method.PasswordTransformationMethod;
 import android.util.Log;
@@ -64,11 +66,51 @@
     private String mCurrentBroadcastName;
     private String mCurrentBroadcastCode;
     private boolean mIsStopbyUpdateBroadcastCode = false;
+    private TextWatcher mTextWatcher = new TextWatcher() {
+        @Override
+        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+            // Do nothing
+        }
+
+        @Override
+        public void onTextChanged(CharSequence s, int start, int before, int count) {
+            // Do nothing
+        }
+
+        @Override
+        public void afterTextChanged(Editable s) {
+            if (mAlertDialog == null || mBroadcastErrorMessage == null) {
+                return;
+            }
+            boolean breakBroadcastCodeRuleTextLengthLessThanMin =
+                    s.length() > 0 && s.length() < BROADCAST_CODE_MIN_LENGTH;
+            boolean breakBroadcastCodeRuleTextLengthMoreThanMax =
+                    s.length() > BROADCAST_CODE_MAX_LENGTH;
+            boolean breakRule = breakBroadcastCodeRuleTextLengthLessThanMin
+                    || breakBroadcastCodeRuleTextLengthMoreThanMax;
+
+            if (breakBroadcastCodeRuleTextLengthLessThanMin) {
+                mBroadcastErrorMessage.setText(
+                        R.string.media_output_broadcast_code_hint_no_less_than_min);
+            } else if (breakBroadcastCodeRuleTextLengthMoreThanMax) {
+                mBroadcastErrorMessage.setText(
+                        R.string.media_output_broadcast_code_hint_no_more_than_max);
+            }
+
+            mBroadcastErrorMessage.setVisibility(breakRule ? View.VISIBLE : View.INVISIBLE);
+            Button positiveBtn = mAlertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
+            if (positiveBtn != null) {
+                positiveBtn.setEnabled(breakRule ? false : true);
+            }
+        }
+    };
 
     static final int METADATA_BROADCAST_NAME = 0;
     static final int METADATA_BROADCAST_CODE = 1;
 
     private static final int MAX_BROADCAST_INFO_UPDATE = 3;
+    private static final int BROADCAST_CODE_MAX_LENGTH = 16;
+    private static final int BROADCAST_CODE_MIN_LENGTH = 4;
 
     MediaOutputBroadcastDialog(Context context, boolean aboveStatusbar,
             BroadcastSender broadcastSender, MediaOutputController mediaOutputController) {
@@ -219,6 +261,9 @@
                 R.layout.media_output_broadcast_update_dialog, null);
         final EditText editText = layout.requireViewById(R.id.broadcast_edit_text);
         editText.setText(editString);
+        if (isBroadcastCode) {
+            editText.addTextChangedListener(mTextWatcher);
+        }
         mBroadcastErrorMessage = layout.requireViewById(R.id.broadcast_error_message);
         mAlertDialog = new Builder(mContext)
                 .setTitle(isBroadcastCode ? R.string.media_output_broadcast_code
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
index fbd0079..a174b45 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.os.Bundle;
+import android.util.FeatureFlagUtils;
 import android.view.View;
 import android.view.WindowManager;
 
@@ -99,10 +100,18 @@
     @Override
     public boolean isBroadcastSupported() {
         boolean isBluetoothLeDevice = false;
-        if (mMediaOutputController.getCurrentConnectedMediaDevice() != null) {
-            isBluetoothLeDevice = mMediaOutputController.isBluetoothLeDevice(
+        if (FeatureFlagUtils.isEnabled(mContext,
+                FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST)) {
+            if (mMediaOutputController.getCurrentConnectedMediaDevice() != null) {
+                isBluetoothLeDevice = mMediaOutputController.isBluetoothLeDevice(
                     mMediaOutputController.getCurrentConnectedMediaDevice());
+            }
+        } else {
+            // To decouple LE Audio Broadcast and Unicast, it always displays the button when there
+            // is no LE Audio device connected to the phone
+            isBluetoothLeDevice = true;
         }
+
         return mMediaOutputController.isBroadcastSupported() && isBluetoothLeDevice;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 198d022..c63b3b3 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -1128,13 +1128,13 @@
             rescheduleTimeoutH();
         }
 
-        if (mODICaptionsTooltipView != null) {
-            mODICaptionsTooltipView.setAlpha(0.0f);
+        // We need to wait for layout and then center the caption view. Since the height of the
+        // dialog is now dynamic (with the variable ringer drawer height changing the height of
+        // the dialog), we need to do this here in code vs. in XML.
+        mHandler.post(() -> {
+            if (mODICaptionsTooltipView != null) {
+                mODICaptionsTooltipView.setAlpha(0.0f);
 
-            // We need to wait for layout and then center the caption view. Since the height of the
-            // dialog is now dynamic (with the variable ringer drawer height changing the height of
-            // the dialog), we need to do this here in code vs. in XML.
-            mHandler.post(() -> {
                 final int[] odiTooltipLocation = mODICaptionsTooltipView.getLocationOnScreen();
                 final int[] odiButtonLocation = mODICaptionsIcon.getLocationOnScreen();
 
@@ -1160,8 +1160,8 @@
                             }
                         })
                         .start();
-            });
-        }
+            }
+        });
     }
 
     private void hideCaptionsTooltip() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
index bae3569..a9246f7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
@@ -36,6 +36,7 @@
 import android.os.PowerExemptionManager;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
+import android.util.FeatureFlagUtils;
 import android.view.View;
 
 import androidx.test.filters.SmallTest;
@@ -169,6 +170,8 @@
                 mLocalBluetoothLeBroadcast);
         when(mLocalBluetoothLeBroadcast.isEnabled(any())).thenReturn(false);
         when(mPlaybackState.getState()).thenReturn(PlaybackState.STATE_PLAYING);
+        FeatureFlagUtils.setEnabled(mContext,
+                FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST, true);
         when(mMediaDevice.isBLEDevice()).thenReturn(false);
 
         assertThat(mMediaOutputDialog.getStopButtonVisibility()).isEqualTo(View.GONE);
@@ -182,6 +185,62 @@
     }
 
     @Test
+    public void isBroadcastSupported_flagOnAndConnectBleDevice_returnsTrue() {
+        when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
+                mLocalBluetoothLeBroadcast);
+        when(mLocalBluetoothLeBroadcast.isEnabled(any())).thenReturn(false);
+        FeatureFlagUtils.setEnabled(mContext,
+                FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST, true);
+        when(mMediaDevice.isBLEDevice()).thenReturn(true);
+
+        assertThat(mMediaOutputDialog.isBroadcastSupported()).isTrue();
+    }
+
+    @Test
+    public void isBroadcastSupported_flagOnAndNoBleDevice_returnsFalse() {
+        when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
+                mLocalBluetoothLeBroadcast);
+        when(mLocalBluetoothLeBroadcast.isEnabled(any())).thenReturn(false);
+        FeatureFlagUtils.setEnabled(mContext,
+                FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST, true);
+        when(mMediaDevice.isBLEDevice()).thenReturn(false);
+
+        assertThat(mMediaOutputDialog.isBroadcastSupported()).isFalse();
+    }
+
+    @Test
+    public void isBroadcastSupported_notSupportBroadcastAndflagOn_returnsFalse() {
+        FeatureFlagUtils.setEnabled(mContext,
+                FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST, true);
+
+        assertThat(mMediaOutputDialog.isBroadcastSupported()).isFalse();
+    }
+
+    @Test
+    public void isBroadcastSupported_flagOffAndConnectToBleDevice_returnsTrue() {
+        when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
+                mLocalBluetoothLeBroadcast);
+        when(mLocalBluetoothLeBroadcast.isEnabled(any())).thenReturn(false);
+        FeatureFlagUtils.setEnabled(mContext,
+                FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST, false);
+        when(mMediaDevice.isBLEDevice()).thenReturn(true);
+
+        assertThat(mMediaOutputDialog.isBroadcastSupported()).isTrue();
+    }
+
+    @Test
+    public void isBroadcastSupported_flagOffAndNoBleDevice_returnsTrue() {
+        when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
+                mLocalBluetoothLeBroadcast);
+        when(mLocalBluetoothLeBroadcast.isEnabled(any())).thenReturn(false);
+        FeatureFlagUtils.setEnabled(mContext,
+                FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST, false);
+        when(mMediaDevice.isBLEDevice()).thenReturn(false);
+
+        assertThat(mMediaOutputDialog.isBroadcastSupported()).isTrue();
+    }
+
+    @Test
     public void getBroadcastIconVisibility_isBroadcasting_returnVisible() {
         when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
                 mLocalBluetoothLeBroadcast);
diff --git a/rs/java/android/renderscript/package.html b/rs/java/android/renderscript/package.html
index eb178c1..8179928 100644
--- a/rs/java/android/renderscript/package.html
+++ b/rs/java/android/renderscript/package.html
@@ -1,9 +1,9 @@
 <HTML>
 <BODY>
-<p>RenderScript provides support for high-performance computation across heterogeneous processors.</p>
+<p>Renderscript is deprecated since API level 31. Please refer to the
+<a href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration guide</a>
+for alternatives.
 
-<p>For more information, see the
-<a href="{@docRoot}guide/topics/renderscript/index.html">RenderScript</a> developer guide.</p>
 {@more}
 
 </BODY>
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 5c11e2c..9c1933d 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -3840,8 +3840,7 @@
                 && (mSessionFlags.mAugmentedAutofillOnly
                         || !mSessionFlags.mInlineSupportedByService
                         || mSessionFlags.mExpiredResponse)
-                && isViewFocusedLocked(flags)
-                || isFillDialogUiEnabled()) {
+                && (isViewFocusedLocked(flags) || isRequestSupportFillDialog(flags))) {
             if (sDebug) Slog.d(TAG, "Create inline request for augmented autofill");
             remoteRenderService.getInlineSuggestionsRendererInfo(new RemoteCallback(
                     (extras) -> {
diff --git a/services/core/java/com/android/server/DropBoxManagerService.java b/services/core/java/com/android/server/DropBoxManagerService.java
index 1d457aa..2fa18af 100644
--- a/services/core/java/com/android/server/DropBoxManagerService.java
+++ b/services/core/java/com/android/server/DropBoxManagerService.java
@@ -693,7 +693,7 @@
                 out.append(file.getPath()).append("\n");
             }
 
-            if ((entry.flags & DropBoxManager.IS_TEXT) != 0 && (doPrint || !doFile)) {
+            if ((entry.flags & DropBoxManager.IS_TEXT) != 0 && doPrint) {
                 DropBoxManager.Entry dbe = null;
                 InputStreamReader isr = null;
                 try {
@@ -717,17 +717,6 @@
                             }
                         }
                         if (!newline) out.append("\n");
-                    } else {
-                        String text = dbe.getText(70);
-                        out.append("    ");
-                        if (text == null) {
-                            out.append("[null]");
-                        } else {
-                            boolean truncated = (text.length() == 70);
-                            out.append(text.trim().replace('\n', '/'));
-                            if (truncated) out.append(" ...");
-                        }
-                        out.append("\n");
                     }
                 } catch (IOException e) {
                     out.append("*** ").append(e.toString()).append("\n");
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 1fab28e..c7d8ab2 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -160,13 +160,21 @@
     public static final String[] AIDL_INTERFACE_PREFIXES_OF_INTEREST = new String[] {
             "android.hardware.biometrics.face.IFace/",
             "android.hardware.biometrics.fingerprint.IFingerprint/",
+            "android.hardware.bluetooth.IBluetoothHci/",
+            "android.hardware.camera.provider.ICameraProvider/",
+            "android.hardware.gnss.IGnss/",
+            "android.hardware.graphics.allocator.IAllocator/",
             "android.hardware.graphics.composer3.IComposer/",
+            "android.hardware.health.IHealth/",
             "android.hardware.input.processor.IInputProcessor/",
             "android.hardware.light.ILights/",
+            "android.hardware.neuralnetworks.IDevice/",
             "android.hardware.power.IPower/",
             "android.hardware.power.stats.IPowerStats/",
+            "android.hardware.sensors.ISensors/",
             "android.hardware.vibrator.IVibrator/",
-            "android.hardware.vibrator.IVibratorManager/"
+            "android.hardware.vibrator.IVibratorManager/",
+            "android.system.suspend.ISystemSuspend/",
     };
 
     private static Watchdog sWatchdog;
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index e0d324a..05915d9 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -2329,10 +2329,6 @@
             Log.w(TAG, "audioFormat to enable is not a surround format.");
             return false;
         }
-        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.WRITE_SETTINGS)
-                != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Missing WRITE_SETTINGS permission");
-        }
 
         final long token = Binder.clearCallingIdentity();
         try {
@@ -2400,11 +2396,6 @@
     /** @see AudioManager#getEncodedSurroundMode() */
     @Override
     public int getEncodedSurroundMode(int targetSdkVersion) {
-        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.WRITE_SETTINGS)
-                != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Missing WRITE_SETTINGS permission");
-        }
-
         final long token = Binder.clearCallingIdentity();
         try {
             synchronized (mSettingsLock) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index c22091b..2c0e909 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -34,6 +34,7 @@
 import android.graphics.Color;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.ShellCommand;
 import android.os.UserHandle;
@@ -46,6 +47,7 @@
 
 import com.android.internal.os.ByteTransferPipe;
 import com.android.internal.protolog.ProtoLogImpl;
+import com.android.server.IoThread;
 import com.android.server.wm.LetterboxConfiguration.LetterboxBackgroundType;
 import com.android.server.wm.LetterboxConfiguration.LetterboxHorizontalReachabilityPosition;
 import com.android.server.wm.LetterboxConfiguration.LetterboxVerticalReachabilityPosition;
@@ -571,8 +573,22 @@
                         ByteTransferPipe pipe = null;
                         try {
                             pipe = new ByteTransferPipe();
-                            w.mClient.executeCommand(ViewDebug.REMOTE_COMMAND_DUMP_ENCODED, null,
-                                    pipe.getWriteFd());
+                            final ParcelFileDescriptor pfd = pipe.getWriteFd();
+                            if (w.isClientLocal()) {
+                                // Make it asynchronous to avoid writer from being blocked
+                                // by waiting for the buffer to be consumed in the same process.
+                                IoThread.getExecutor().execute(() -> {
+                                    try {
+                                        w.mClient.executeCommand(
+                                                ViewDebug.REMOTE_COMMAND_DUMP_ENCODED, null, pfd);
+                                    } catch (RemoteException e) {
+                                        // Ignore for local call.
+                                    }
+                                });
+                            } else {
+                                w.mClient.executeCommand(
+                                        ViewDebug.REMOTE_COMMAND_DUMP_ENCODED, null, pfd);
+                            }
                             requestList.add(Pair.create(w.getName(), pipe));
                         } catch (IOException | RemoteException e) {
                             // Skip this window
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 432af3a..9c1e8dd 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -1839,8 +1839,15 @@
 
     /**
      * Instructs this {@code Call} to play a dual-tone multi-frequency signaling (DTMF) tone.
-     *
-     * Any other currently playing DTMF tone in the specified call is immediately stopped.
+     * <p>
+     * Tones are both played locally for the user to hear and sent to the network to be relayed
+     * to the remote device.
+     * <p>
+     * You must ensure that any call to {@link #playDtmfTone(char}) is followed by a matching
+     * call to {@link #stopDtmfTone()} and that each tone is stopped before a new one is started.
+     * The play and stop commands are relayed to the underlying
+     * {@link android.telecom.ConnectionService} as executed; implementations may not correctly
+     * handle out of order commands.
      *
      * @param digit A character representing the DTMF digit for which to play the tone. This
      *         value must be one of {@code '0'} through {@code '9'}, {@code '*'} or {@code '#'}.
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index bce6809..6afc400 100755
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -2330,7 +2330,7 @@
     }
 
     private void playDtmfTone(String callId, char digit) {
-        Log.i(this, "playDtmfTone %s %c", callId, digit);
+        Log.i(this, "playDtmfTone %s %s", callId, Log.pii(digit));
         if (mConnectionById.containsKey(callId)) {
             findConnectionForAction(callId, "playDtmfTone").onPlayDtmfTone(digit);
         } else {