Merge cherrypicks of [18563202, 19970324, 15982545, 20120242, 20208339, 20211078, 20291140, 20251345, 20223219, 20122955, 20234866, 20219552, 20426455] into security-aosp-qt-release.

Change-Id: Ifcd157219e4cecce5376bae406c5d57ffd96716e
diff --git a/core/java/android/app/AutomaticZenRule.java b/core/java/android/app/AutomaticZenRule.java
index 37b3363..9a92515 100644
--- a/core/java/android/app/AutomaticZenRule.java
+++ b/core/java/android/app/AutomaticZenRule.java
@@ -125,7 +125,7 @@
             name = getTrimmedString(source.readString());
         }
         interruptionFilter = source.readInt();
-        conditionId = source.readParcelable(null);
+        conditionId = getTrimmedUri(source.readParcelable(null));
         owner = getTrimmedComponentName(source.readParcelable(null));
         configurationActivity = getTrimmedComponentName(source.readParcelable(null));
         creationTime = source.readLong();
diff --git a/core/java/android/hardware/usb/UsbDeviceConnection.java b/core/java/android/hardware/usb/UsbDeviceConnection.java
index 71297c1..5c7a1b0 100644
--- a/core/java/android/hardware/usb/UsbDeviceConnection.java
+++ b/core/java/android/hardware/usb/UsbDeviceConnection.java
@@ -52,6 +52,8 @@
 
     private final CloseGuard mCloseGuard = CloseGuard.get();
 
+    private final Object mLock = new Object();
+
     /**
      * UsbDevice should only be instantiated by UsbService implementation
      * @hide
@@ -62,13 +64,23 @@
 
     /* package */ boolean open(String name, ParcelFileDescriptor pfd, @NonNull Context context) {
         mContext = context.getApplicationContext();
-        boolean wasOpened = native_open(name, pfd.getFileDescriptor());
 
-        if (wasOpened) {
-            mCloseGuard.open("close");
+        synchronized (mLock) {
+            boolean wasOpened = native_open(name, pfd.getFileDescriptor());
+
+            if (wasOpened) {
+                mCloseGuard.open("close");
+            }
+
+            return wasOpened;
         }
+    }
 
-        return wasOpened;
+    /***
+     * @return If this connection is currently open and usable.
+     */
+    boolean isOpen() {
+        return mNativeContext != 0;
     }
 
     /**
@@ -81,15 +93,60 @@
     }
 
     /**
+     * Cancel a request which relates to this connection.
+     *
+     * @return true if the request was successfully cancelled.
+     */
+    /* package */ boolean cancelRequest(UsbRequest request) {
+        synchronized (mLock) {
+            if (!isOpen()) {
+                return false;
+            }
+
+            return request.cancelIfOpen();
+        }
+    }
+
+    /**
+     * This is meant to be called by UsbRequest's queue() in order to synchronize on
+     * UsbDeviceConnection's mLock to prevent the connection being closed while queueing.
+     */
+    /* package */ boolean queueRequest(UsbRequest request, ByteBuffer buffer, int length) {
+        synchronized (mLock) {
+            if (!isOpen()) {
+                return false;
+            }
+
+            return request.queueIfConnectionOpen(buffer, length);
+        }
+    }
+
+    /**
+     * This is meant to be called by UsbRequest's queue() in order to synchronize on
+     * UsbDeviceConnection's mLock to prevent the connection being closed while queueing.
+     */
+    /* package */ boolean queueRequest(UsbRequest request, @Nullable ByteBuffer buffer) {
+        synchronized (mLock) {
+            if (!isOpen()) {
+                return false;
+            }
+
+            return request.queueIfConnectionOpen(buffer);
+        }
+    }
+
+    /**
      * Releases all system resources related to the device.
      * Once the object is closed it cannot be used again.
      * The client must call {@link UsbManager#openDevice} again
      * to retrieve a new instance to reestablish communication with the device.
      */
     public void close() {
-        if (mNativeContext != 0) {
-            native_close();
-            mCloseGuard.close();
+        synchronized (mLock) {
+            if (isOpen()) {
+                native_close();
+                mCloseGuard.close();
+            }
         }
     }
 
diff --git a/core/java/android/hardware/usb/UsbRequest.java b/core/java/android/hardware/usb/UsbRequest.java
index 7abf3e9..11c9d06 100644
--- a/core/java/android/hardware/usb/UsbRequest.java
+++ b/core/java/android/hardware/usb/UsbRequest.java
@@ -112,11 +112,13 @@
      * Releases all resources related to this request.
      */
     public void close() {
-        if (mNativeContext != 0) {
-            mEndpoint = null;
-            mConnection = null;
-            native_close();
-            mCloseGuard.close();
+        synchronized (mLock) {
+            if (mNativeContext != 0) {
+                mEndpoint = null;
+                mConnection = null;
+                native_close();
+                mCloseGuard.close();
+            }
         }
     }
 
@@ -190,10 +192,32 @@
      */
     @Deprecated
     public boolean queue(ByteBuffer buffer, int length) {
+        UsbDeviceConnection connection = mConnection;
+        if (connection == null) {
+            // The expected exception by CTS Verifier - USB Device test
+            throw new NullPointerException("invalid connection");
+        }
+
+        // Calling into the underlying UsbDeviceConnection to synchronize on its lock, to prevent
+        // the connection being closed while queueing.
+        return connection.queueRequest(this, buffer, length);
+    }
+
+    /**
+     * This is meant to be called from UsbDeviceConnection after synchronizing using the lock over
+     * there, to prevent the connection being closed while queueing.
+     */
+    /* package */ boolean queueIfConnectionOpen(ByteBuffer buffer, int length) {
+        UsbDeviceConnection connection = mConnection;
+        if (connection == null || !connection.isOpen()) {
+            // The expected exception by CTS Verifier - USB Device test
+            throw new NullPointerException("invalid connection");
+        }
+
         boolean out = (mEndpoint.getDirection() == UsbConstants.USB_DIR_OUT);
         boolean result;
 
-        if (mConnection.getContext().getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.P
+        if (connection.getContext().getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.P
                 && length > MAX_USBFS_BUFFER_SIZE) {
             length = MAX_USBFS_BUFFER_SIZE;
         }
@@ -242,6 +266,28 @@
      * @return true if the queueing operation succeeded
      */
     public boolean queue(@Nullable ByteBuffer buffer) {
+        UsbDeviceConnection connection = mConnection;
+        if (connection == null) {
+            // The expected exception by CTS Verifier - USB Device test
+            throw new IllegalStateException("invalid connection");
+        }
+
+        // Calling into the underlying UsbDeviceConnection to synchronize on its lock, to prevent
+        // the connection being closed while queueing.
+        return connection.queueRequest(this, buffer);
+    }
+
+    /**
+     * This is meant to be called from UsbDeviceConnection after synchronizing using the lock over
+     * there, to prevent the connection being closed while queueing.
+     */
+    /* package */ boolean queueIfConnectionOpen(@Nullable ByteBuffer buffer) {
+        UsbDeviceConnection connection = mConnection;
+        if (connection == null || !connection.isOpen()) {
+            // The expected exception by CTS Verifier - USB Device test
+            throw new IllegalStateException("invalid connection");
+        }
+
         // Request need to be initialized
         Preconditions.checkState(mNativeContext != 0, "request is not initialized");
 
@@ -259,7 +305,7 @@
                 mIsUsingNewQueue = true;
                 wasQueued = native_queue(null, 0, 0);
             } else {
-                if (mConnection.getContext().getApplicationInfo().targetSdkVersion
+                if (connection.getContext().getApplicationInfo().targetSdkVersion
                         < Build.VERSION_CODES.P) {
                     // Can only send/receive MAX_USBFS_BUFFER_SIZE bytes at once
                     Preconditions.checkArgumentInRange(buffer.remaining(), 0, MAX_USBFS_BUFFER_SIZE,
@@ -362,6 +408,32 @@
      * @return true if cancelling succeeded
      */
     public boolean cancel() {
+        UsbDeviceConnection connection = mConnection;
+        if (connection == null) {
+            return false;
+        }
+
+        return connection.cancelRequest(this);
+    }
+
+    /**
+     * Cancels a pending queue operation (for use when the UsbDeviceConnection associated
+     * with this request is synchronized). This ensures we don't have a race where the
+     * device is closed and then the request is canceled which would lead to a
+     * use-after-free because the cancel operation uses the device connection
+     * information freed in the when UsbDeviceConnection is closed.<br/>
+     *
+     * This method assumes the connected is not closed while this method is executed.
+     *
+     * @return true if cancelling succeeded.
+     */
+    /* package */ boolean cancelIfOpen() {
+        UsbDeviceConnection connection = mConnection;
+        if (mNativeContext == 0 || (connection != null && !connection.isOpen())) {
+            Log.w(TAG,
+                    "Detected attempt to cancel a request on a connection which isn't open");
+            return false;
+        }
         return native_cancel();
     }
 
diff --git a/core/java/android/service/notification/Condition.java b/core/java/android/service/notification/Condition.java
index e506509..50597ec 100644
--- a/core/java/android/service/notification/Condition.java
+++ b/core/java/android/service/notification/Condition.java
@@ -90,6 +90,12 @@
     public final int icon;
 
     /**
+     * The maximum string length for any string contained in this condition.
+     * @hide
+     */
+    public static final int MAX_STRING_LENGTH = 1000;
+
+    /**
      * An object representing the current state of a {@link android.app.AutomaticZenRule}.
      * @param id the {@link android.app.AutomaticZenRule#getConditionId()} of the zen rule
      * @param summary a user visible description of the rule state.
@@ -103,16 +109,19 @@
         if (id == null) throw new IllegalArgumentException("id is required");
         if (summary == null) throw new IllegalArgumentException("summary is required");
         if (!isValidState(state)) throw new IllegalArgumentException("state is invalid: " + state);
-        this.id = id;
-        this.summary = summary;
-        this.line1 = line1;
-        this.line2 = line2;
+        this.id = getTrimmedUri(id);
+        this.summary = getTrimmedString(summary);
+        this.line1 = getTrimmedString(line1);
+        this.line2 = getTrimmedString(line2);
         this.icon = icon;
         this.state = state;
         this.flags = flags;
     }
 
     public Condition(Parcel source) {
+        // This constructor passes all fields directly into the constructor that takes all the
+        // fields as arguments; that constructor will trim each of the input strings to
+        // max length if necessary.
         this((Uri)source.readParcelable(Condition.class.getClassLoader()),
                 source.readString(),
                 source.readString(),
@@ -239,4 +248,25 @@
             return new Condition[size];
         }
     };
+
+    /**
+     * Returns a truncated copy of the string if the string is longer than MAX_STRING_LENGTH.
+     */
+    private static String getTrimmedString(String input) {
+        if (input != null && input.length() > MAX_STRING_LENGTH) {
+            return input.substring(0, MAX_STRING_LENGTH);
+        }
+        return input;
+    }
+
+    /**
+     * Returns a truncated copy of the Uri by trimming the string representation to the maximum
+     * string length.
+     */
+    private static Uri getTrimmedUri(Uri input) {
+        if (input != null && input.toString().length() > MAX_STRING_LENGTH) {
+            return Uri.parse(getTrimmedString(input.toString()));
+        }
+        return input;
+    }
 }
diff --git a/core/tests/coretests/src/android/service/notification/ConditionTest.java b/core/tests/coretests/src/android/service/notification/ConditionTest.java
new file mode 100644
index 0000000..42629ba
--- /dev/null
+++ b/core/tests/coretests/src/android/service/notification/ConditionTest.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2022 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.service.notification;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.fail;
+
+import android.net.Uri;
+import android.os.Parcel;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.google.common.base.Strings;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Field;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ConditionTest {
+    private static final String CLASS = "android.service.notification.Condition";
+
+    @Test
+    public void testLongFields_inConstructors() {
+        String longString = Strings.repeat("A", 65536);
+        Uri longUri = Uri.parse("uri://" + Strings.repeat("A", 65530));
+
+        // Confirm strings are truncated via short constructor
+        Condition cond1 = new Condition(longUri, longString, Condition.STATE_TRUE);
+
+        assertEquals(Condition.MAX_STRING_LENGTH, cond1.id.toString().length());
+        assertEquals(Condition.MAX_STRING_LENGTH, cond1.summary.length());
+
+        // Confirm strings are truncated via long constructor
+        Condition cond2 = new Condition(longUri, longString, longString, longString,
+                -1, Condition.STATE_TRUE, Condition.FLAG_RELEVANT_ALWAYS);
+
+        assertEquals(Condition.MAX_STRING_LENGTH, cond2.id.toString().length());
+        assertEquals(Condition.MAX_STRING_LENGTH, cond2.summary.length());
+        assertEquals(Condition.MAX_STRING_LENGTH, cond2.line1.length());
+        assertEquals(Condition.MAX_STRING_LENGTH, cond2.line2.length());
+    }
+
+    @Test
+    public void testLongFields_viaParcel() {
+        // Set fields via reflection to force them to be long, then parcel and unparcel to make sure
+        // it gets truncated upon unparcelling.
+        Condition cond = new Condition(Uri.parse("uri://placeholder"), "placeholder",
+                Condition.STATE_TRUE);
+
+        try {
+            String longString = Strings.repeat("A", 65536);
+            Uri longUri = Uri.parse("uri://" + Strings.repeat("A", 65530));
+            Field id = Class.forName(CLASS).getDeclaredField("id");
+            id.setAccessible(true);
+            id.set(cond, longUri);
+            Field summary = Class.forName(CLASS).getDeclaredField("summary");
+            summary.setAccessible(true);
+            summary.set(cond, longString);
+            Field line1 = Class.forName(CLASS).getDeclaredField("line1");
+            line1.setAccessible(true);
+            line1.set(cond, longString);
+            Field line2 = Class.forName(CLASS).getDeclaredField("line2");
+            line2.setAccessible(true);
+            line2.set(cond, longString);
+        } catch (NoSuchFieldException e) {
+            fail(e.toString());
+        } catch (ClassNotFoundException e) {
+            fail(e.toString());
+        } catch (IllegalAccessException e) {
+            fail(e.toString());
+        }
+
+        Parcel parcel = Parcel.obtain();
+        cond.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+
+        Condition fromParcel = new Condition(parcel);
+        assertEquals(Condition.MAX_STRING_LENGTH, fromParcel.id.toString().length());
+        assertEquals(Condition.MAX_STRING_LENGTH, fromParcel.summary.length());
+        assertEquals(Condition.MAX_STRING_LENGTH, fromParcel.line1.length());
+        assertEquals(Condition.MAX_STRING_LENGTH, fromParcel.line2.length());
+    }
+}
diff --git a/packages/SettingsProvider/Android.bp b/packages/SettingsProvider/Android.bp
index 1c97fc3..825a0bd 100644
--- a/packages/SettingsProvider/Android.bp
+++ b/packages/SettingsProvider/Android.bp
@@ -24,7 +24,10 @@
         "src/com/android/providers/settings/SettingsState.java",
         "src/com/android/providers/settings/SettingsHelper.java",
     ],
-    static_libs: ["androidx.test.rules"],
+    static_libs: [
+        "androidx.test.rules",
+        "truth-prebuilt",
+    ],
     libs: ["android.test.base"],
     resource_dirs: ["res"],
     aaptflags: [
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index c05c4cdf..451b373 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -48,6 +48,7 @@
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 import com.android.server.LocalServices;
 
@@ -367,9 +368,11 @@
             Setting newSetting = new Setting(name, oldSetting.getValue(), null,
                     oldSetting.getPackageName(), oldSetting.getTag(), false,
                     oldSetting.getId());
+            int newSize = getNewMemoryUsagePerPackageLocked(newSetting.getPackageName(), 0,
+                    oldValue, newSetting.getValue(), oldDefaultValue, newSetting.getDefaultValue());
+            checkNewMemoryUsagePerPackageLocked(newSetting.getPackageName(), newSize);
             mSettings.put(name, newSetting);
-            updateMemoryUsagePerPackageLocked(newSetting.getPackageName(), oldValue,
-                    newSetting.getValue(), oldDefaultValue, newSetting.getDefaultValue());
+            updateMemoryUsagePerPackageLocked(newSetting.getPackageName(), newSize);
             scheduleWriteIfNeededLocked();
         }
     }
@@ -392,6 +395,13 @@
         Setting oldState = mSettings.get(name);
         String oldValue = (oldState != null) ? oldState.value : null;
         String oldDefaultValue = (oldState != null) ? oldState.defaultValue : null;
+        String newDefaultValue = makeDefault ? value : oldDefaultValue;
+
+        int newSize = getNewMemoryUsagePerPackageLocked(packageName,
+                oldValue == null ? name.length() : 0 /* deltaKeySize */,
+                oldValue, value, oldDefaultValue, newDefaultValue);
+        checkNewMemoryUsagePerPackageLocked(packageName, newSize);
+
         Setting newState;
 
         if (oldState != null) {
@@ -409,8 +419,7 @@
 
         addHistoricalOperationLocked(HISTORICAL_OPERATION_UPDATE, newState);
 
-        updateMemoryUsagePerPackageLocked(packageName, oldValue, value,
-                oldDefaultValue, newState.getDefaultValue());
+        updateMemoryUsagePerPackageLocked(packageName, newSize);
 
         scheduleWriteIfNeededLocked();
 
@@ -431,13 +440,18 @@
         }
 
         Setting oldState = mSettings.remove(name);
+        if (oldState == null) {
+            return false;
+        }
+        int newSize = getNewMemoryUsagePerPackageLocked(oldState.packageName,
+                -name.length() /* deltaKeySize */,
+                oldState.value, null, oldState.defaultValue, null);
 
         StatsLog.write(StatsLog.SETTING_CHANGED, name, /* value= */ "", /* newValue= */ "",
             oldState.value, /* tag */ "", false, getUserIdFromKey(mKey),
             StatsLog.SETTING_CHANGED__REASON__DELETED);
 
-        updateMemoryUsagePerPackageLocked(oldState.packageName, oldState.value,
-                null, oldState.defaultValue, null);
+        updateMemoryUsagePerPackageLocked(oldState.packageName, newSize);
 
         addHistoricalOperationLocked(HISTORICAL_OPERATION_DELETE, oldState);
 
@@ -454,20 +468,23 @@
         }
 
         Setting setting = mSettings.get(name);
+        if (setting == null) {
+            return false;
+        }
 
         Setting oldSetting = new Setting(setting);
         String oldValue = setting.getValue();
         String oldDefaultValue = setting.getDefaultValue();
 
+        int newSize = getNewMemoryUsagePerPackageLocked(setting.packageName, 0, oldValue,
+                oldDefaultValue, oldDefaultValue, oldDefaultValue);
+        checkNewMemoryUsagePerPackageLocked(setting.packageName, newSize);
+
         if (!setting.reset()) {
             return false;
         }
 
-        String newValue = setting.getValue();
-        String newDefaultValue = setting.getDefaultValue();
-
-        updateMemoryUsagePerPackageLocked(setting.packageName, oldValue,
-                newValue, oldDefaultValue, newDefaultValue);
+        updateMemoryUsagePerPackageLocked(setting.packageName, newSize);
 
         addHistoricalOperationLocked(HISTORICAL_OPERATION_RESET, oldSetting);
 
@@ -575,38 +592,49 @@
     }
 
     @GuardedBy("mLock")
-    private void updateMemoryUsagePerPackageLocked(String packageName, String oldValue,
-            String newValue, String oldDefaultValue, String newDefaultValue) {
-        if (mMaxBytesPerAppPackage == MAX_BYTES_PER_APP_PACKAGE_UNLIMITED) {
+    private boolean isExemptFromMemoryUsageCap(String packageName) {
+        return mMaxBytesPerAppPackage == MAX_BYTES_PER_APP_PACKAGE_UNLIMITED
+                || SYSTEM_PACKAGE_NAME.equals(packageName);
+    }
+
+    @GuardedBy("mLock")
+    private void checkNewMemoryUsagePerPackageLocked(String packageName, int newSize)
+            throws IllegalStateException {
+        if (isExemptFromMemoryUsageCap(packageName)) {
             return;
         }
-
-        if (SYSTEM_PACKAGE_NAME.equals(packageName)) {
-            return;
-        }
-
-        final int oldValueSize = (oldValue != null) ? oldValue.length() : 0;
-        final int newValueSize = (newValue != null) ? newValue.length() : 0;
-        final int oldDefaultValueSize = (oldDefaultValue != null) ? oldDefaultValue.length() : 0;
-        final int newDefaultValueSize = (newDefaultValue != null) ? newDefaultValue.length() : 0;
-        final int deltaSize = newValueSize + newDefaultValueSize
-                - oldValueSize - oldDefaultValueSize;
-
-        Integer currentSize = mPackageToMemoryUsage.get(packageName);
-        final int newSize = Math.max((currentSize != null)
-                ? currentSize + deltaSize : deltaSize, 0);
-
         if (newSize > mMaxBytesPerAppPackage) {
             throw new IllegalStateException("You are adding too many system settings. "
                     + "You should stop using system settings for app specific data"
                     + " package: " + packageName);
         }
+    }
 
+    @GuardedBy("mLock")
+    private int getNewMemoryUsagePerPackageLocked(String packageName, int deltaKeySize,
+            String oldValue, String newValue, String oldDefaultValue, String newDefaultValue) {
+        if (isExemptFromMemoryUsageCap(packageName)) {
+            return 0;
+        }
+        final Integer currentSize = mPackageToMemoryUsage.get(packageName);
+        final int oldValueSize = (oldValue != null) ? oldValue.length() : 0;
+        final int newValueSize = (newValue != null) ? newValue.length() : 0;
+        final int oldDefaultValueSize = (oldDefaultValue != null) ? oldDefaultValue.length() : 0;
+        final int newDefaultValueSize = (newDefaultValue != null) ? newDefaultValue.length() : 0;
+        final int deltaSize = deltaKeySize + newValueSize + newDefaultValueSize
+                - oldValueSize - oldDefaultValueSize;
+        return Math.max((currentSize != null) ? currentSize + deltaSize : deltaSize, 0);
+    }
+
+    @GuardedBy("mLock")
+    private void updateMemoryUsagePerPackageLocked(String packageName, int newSize) {
+        if (isExemptFromMemoryUsageCap(packageName)) {
+            return;
+        }
         if (DEBUG) {
             Slog.i(LOG_TAG, "Settings for package: " + packageName
                     + " size: " + newSize + " bytes.");
         }
-
         mPackageToMemoryUsage.put(packageName, newSize);
     }
 
@@ -1220,4 +1248,11 @@
             return false;
         }
     }
+
+    @VisibleForTesting
+    public int getMemoryUsage(String packageName) {
+        synchronized (mLock) {
+            return mPackageToMemoryUsage.getOrDefault(packageName, 0);
+        }
+    }
 }
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
index 3f68554..adb3567 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
@@ -21,6 +21,8 @@
 
 import org.xmlpull.v1.XmlSerializer;
 
+import com.google.common.base.Strings;
+
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileOutputStream;
@@ -46,7 +48,6 @@
             "\uD800ab\uDC00 " + // broken surrogate pairs
             "日本語";
 
-
     public void testIsBinary() {
         assertFalse(SettingsState.isBinary(" abc 日本語"));
 
@@ -182,4 +183,140 @@
             assertEquals("p2", s.getPackageName());
         }
     }
+
+    public void testInsertSetting_memoryUsage() {
+        final Object lock = new Object();
+        final File file = new File(getContext().getCacheDir(), "setting.xml");
+        final String settingName = "test_setting";
+
+        SettingsState settingsState = new SettingsState(getContext(), lock, file, 1,
+                SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper());
+        // No exception should be thrown when there is no cap
+        settingsState.insertSettingLocked(settingName, Strings.repeat("A", 20001),
+                null, false, "p1");
+        settingsState.deleteSettingLocked(settingName);
+
+        settingsState = new SettingsState(getContext(), lock, file, 1,
+                SettingsState.MAX_BYTES_PER_APP_PACKAGE_LIMITED, Looper.getMainLooper());
+        // System package doesn't have memory usage limit
+        settingsState.insertSettingLocked(settingName, Strings.repeat("A", 20001),
+                null, false, "android");
+        settingsState.deleteSettingLocked(settingName);
+
+        // Should not throw if usage is under the cap
+        settingsState.insertSettingLocked(settingName, Strings.repeat("A", 19975),
+                null, false, "p1");
+        settingsState.deleteSettingLocked(settingName);
+        try {
+            settingsState.insertSettingLocked(settingName, Strings.repeat("A", 20001),
+                    null, false, "p1");
+            fail("Should throw because it exceeded per package memory usage");
+        } catch (IllegalStateException ex) {
+            assertTrue(ex.getMessage().contains("p1"));
+        }
+        try {
+            settingsState.insertSettingLocked(settingName, Strings.repeat("A", 20001),
+                    null, false, "p1");
+            fail("Should throw because it exceeded per package memory usage");
+        } catch (IllegalStateException ex) {
+            assertTrue(ex.getMessage().contains("p1"));
+        }
+        assertTrue(settingsState.getSettingLocked(settingName).isNull());
+        try {
+            settingsState.insertSettingLocked(Strings.repeat("A", 20001), "",
+                    null, false, "p1");
+            fail("Should throw because it exceeded per package memory usage");
+        } catch (IllegalStateException ex) {
+            assertTrue(ex.getMessage().contains("You are adding too many system settings"));
+        }
+    }
+
+    public void testMemoryUsagePerPackage() {
+        final Object lock = new Object();
+        final File file = new File(getContext().getCacheDir(), "setting.xml");
+        final String testPackage = "package";
+        SettingsState settingsState = new SettingsState(getContext(), lock, file, 1,
+                SettingsState.MAX_BYTES_PER_APP_PACKAGE_LIMITED, Looper.getMainLooper());
+
+        // Test inserting one key with default
+        final String settingName = "test_setting";
+        final String testKey1 = settingName;
+        final String testValue1 = Strings.repeat("A", 100);
+        settingsState.insertSettingLocked(testKey1, testValue1, null, true, testPackage);
+        int expectedMemUsage = testKey1.length() + testValue1.length()
+                + testValue1.length() /* size for default */;
+        assertEquals(expectedMemUsage, settingsState.getMemoryUsage(testPackage));
+
+        // Test inserting another key
+        final String testKey2 = settingName + "2";
+        settingsState.insertSettingLocked(testKey2, testValue1, null, false, testPackage);
+        expectedMemUsage += testKey2.length() + testValue1.length();
+        assertEquals(expectedMemUsage, settingsState.getMemoryUsage(testPackage));
+
+        // Test updating first key with new default
+        final String testValue2 = Strings.repeat("A", 300);
+        settingsState.insertSettingLocked(testKey1, testValue2, null, true, testPackage);
+        expectedMemUsage += (testValue2.length() - testValue1.length()) * 2;
+        assertEquals(expectedMemUsage, settingsState.getMemoryUsage(testPackage));
+
+        // Test updating first key without new default
+        final String testValue3 = Strings.repeat("A", 50);
+        settingsState.insertSettingLocked(testKey1, testValue3, null, false, testPackage);
+        expectedMemUsage -= testValue2.length() - testValue3.length();
+        assertEquals(expectedMemUsage, settingsState.getMemoryUsage(testPackage));
+
+        // Test updating second key
+        settingsState.insertSettingLocked(testKey2, testValue2, null, false, testPackage);
+        expectedMemUsage -= testValue1.length() - testValue2.length();
+        assertEquals(expectedMemUsage, settingsState.getMemoryUsage(testPackage));
+
+        // Test resetting key
+        settingsState.resetSettingLocked(testKey1);
+        expectedMemUsage += testValue2.length() - testValue3.length();
+        assertEquals(expectedMemUsage, settingsState.getMemoryUsage(testPackage));
+
+        // Test resetting default value
+        settingsState.resetSettingDefaultValueLocked(testKey1);
+        expectedMemUsage -= testValue2.length();
+        assertEquals(expectedMemUsage, settingsState.getMemoryUsage(testPackage));
+
+        // Test deletion
+        settingsState.deleteSettingLocked(testKey2);
+        expectedMemUsage -= testValue2.length() + testKey2.length() /* key is deleted too */;
+        assertEquals(expectedMemUsage, settingsState.getMemoryUsage(testPackage));
+
+        // Test another package with a different key
+        final String testPackage2 = testPackage + "2";
+        final String testKey3 = settingName + "3";
+        settingsState.insertSettingLocked(testKey3, testValue1, null, true, testPackage2);
+        assertEquals(expectedMemUsage, settingsState.getMemoryUsage(testPackage));
+        final int expectedMemUsage2 = testKey3.length() + testValue1.length() * 2;
+        assertEquals(expectedMemUsage2, settingsState.getMemoryUsage(testPackage2));
+
+        // Test system package
+        settingsState.insertSettingLocked(testKey1, testValue1, null, true, "android");
+        assertEquals(expectedMemUsage, settingsState.getMemoryUsage(testPackage));
+        assertEquals(expectedMemUsage2, settingsState.getMemoryUsage(testPackage2));
+        assertEquals(0, settingsState.getMemoryUsage("android"));
+
+        // Test invalid value
+        try {
+            settingsState.insertSettingLocked(testKey1, Strings.repeat("A", 20001), null, false,
+                    testPackage);
+            fail("Should throw because it exceeded per package memory usage");
+        } catch (IllegalStateException ex) {
+            assertTrue(ex.getMessage().contains("You are adding too many system settings"));
+        }
+        assertEquals(expectedMemUsage, settingsState.getMemoryUsage(testPackage));
+
+        // Test invalid key
+        try {
+            settingsState.insertSettingLocked(Strings.repeat("A", 20001), "", null, false,
+                    testPackage);
+            fail("Should throw because it exceeded per package memory usage");
+        } catch (IllegalStateException ex) {
+            assertTrue(ex.getMessage().contains("You are adding too many system settings"));
+        }
+        assertEquals(expectedMemUsage, settingsState.getMemoryUsage(testPackage));
+    }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 3ca6bf4..92c06d4 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -427,26 +427,28 @@
                     }
                     UserState userState = getUserStateLocked(userId);
                     Iterator<ComponentName> it = userState.mEnabledServices.iterator();
+                    boolean anyServiceRemoved = false;
                     while (it.hasNext()) {
                         ComponentName comp = it.next();
                         String compPkg = comp.getPackageName();
                         if (compPkg.equals(packageName)) {
                             it.remove();
                             userState.mBindingServices.remove(comp);
-                            // Update the enabled services setting.
-                            persistComponentNamesToSettingLocked(
-                                    Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
-                                    userState.mEnabledServices, userId);
-                            // Update the touch exploration granted services setting.
                             userState.mTouchExplorationGrantedServices.remove(comp);
-                            persistComponentNamesToSettingLocked(
-                                    Settings.Secure.
-                                    TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
-                                    userState.mTouchExplorationGrantedServices, userId);
-                            onUserStateChangedLocked(userState);
-                            return;
+                            anyServiceRemoved = true;
                         }
                     }
+                    if (anyServiceRemoved) {
+                        // Update the enabled services setting.
+                        persistComponentNamesToSettingLocked(
+                                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+                                userState.mEnabledServices, userId);
+                        // Update the touch exploration granted services setting.
+                        persistComponentNamesToSettingLocked(
+                                Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
+                                userState.mTouchExplorationGrantedServices, userId);
+                        onUserStateChangedLocked(userState);
+                    }
                 }
             }
 
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 54504c3..44d67ed 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -317,11 +317,16 @@
                 resolvedType = key.requestResolvedType;
             }
 
-            // Apply any launch flags from the ActivityOptions. This is to ensure that the caller
-            // can specify a consistent launch mode even if the PendingIntent is immutable
+            // Apply any launch flags from the ActivityOptions. This is used only by SystemUI
+            // to ensure that we can launch the pending intent with a consistent launch mode even
+            // if the provided PendingIntent is immutable (ie. to force an activity to launch into
+            // a new task, or to launch multiple instances if supported by the app)
             final ActivityOptions opts = ActivityOptions.fromBundle(options);
             if (opts != null) {
-                finalIntent.addFlags(opts.getPendingIntentLaunchFlags());
+                // TODO(b/254490217): Move this check into SafeActivityOptions
+                if (controller.mAtmInternal.isCallerRecents(Binder.getCallingUid())) {
+                    finalIntent.addFlags(opts.getPendingIntentLaunchFlags());
+                }
             }
 
             // Extract options before clearing calling identity
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 20021db..3fb7500 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -12320,9 +12320,7 @@
 
                 AsyncTask.execute(() -> {
                     if (hasOldPkg) {
-                        mPermissionManager.revokeRuntimePermissionsIfGroupChanged(pkg, oldPkg,
-                                allPackageNames, mPermissionCallback);
-                        mPermissionManager.revokeStoragePermissionsIfScopeExpanded(pkg, oldPkg,
+                        mPermissionManager.onPackageUpdated(pkg, oldPkg, allPackageNames,
                                 mPermissionCallback);
                     }
                     if (hasPermissionDefinitionChanges) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index c7fca39..3acf359 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -647,6 +647,45 @@
     }
 
     /**
+     * If the package was below api 23, got the SYSTEM_ALERT_WINDOW permission automatically, and
+     * then updated past api 23, and the app does not satisfy any of the other SAW permission flags,
+     * the permission should be revoked.
+     *
+     * @param newPackage The new package that was installed
+     * @param oldPackage The old package that was updated
+     */
+    private void revokeSystemAlertWindowIfUpgradedPast23(
+            @NonNull PackageParser.Package newPackage,
+            @NonNull PackageParser.Package oldPackage,
+            @NonNull PermissionCallback permissionCallback) {
+        if (oldPackage.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.M
+                || newPackage.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M
+                || !newPackage.requestedPermissions
+                .contains(Manifest.permission.SYSTEM_ALERT_WINDOW)) {
+            return;
+        }
+
+        BasePermission saw;
+        synchronized (mLock) {
+            saw = mSettings.getPermissionLocked(Manifest.permission.SYSTEM_ALERT_WINDOW);
+        }
+        final PackageSetting ps = (PackageSetting) newPackage.mExtras;
+        if (grantSignaturePermission(Manifest.permission.SYSTEM_ALERT_WINDOW, newPackage, saw,
+                ps.getPermissionsState())) {
+            return;
+        }
+        for (int userId: mUserManagerInt.getUserIds()) {
+            try {
+                revokeRuntimePermission(Manifest.permission.SYSTEM_ALERT_WINDOW,
+                        newPackage.packageName, false, userId, permissionCallback);
+            } catch (IllegalStateException | SecurityException e) {
+                Log.e(TAG, "unable to revoke SYSTEM_ALERT_WINDOW for "
+                        + newPackage.packageName + " user " + userId, e);
+            }
+        }
+    }
+
+    /**
      * We might auto-grant permissions if any permission of the group is already granted. Hence if
      * the group of a granted permission changes we need to revoke it to avoid having permissions of
      * the new group auto-granted.
@@ -942,8 +981,8 @@
             BasePermission bp = mSettings.getPermissionLocked(info.name);
             added = bp == null;
             int fixedLevel = PermissionInfo.fixProtectionLevel(info.protectionLevel);
+            enforcePermissionCapLocked(info, tree);
             if (added) {
-                enforcePermissionCapLocked(info, tree);
                 bp = new BasePermission(info.name, tree.getSourcePackageName(),
                         BasePermission.TYPE_DYNAMIC);
             } else if (!bp.isDynamic()) {
@@ -3170,25 +3209,22 @@
         }
 
         /**
-         * If the app is updated, and has scoped storage permissions, then it is possible that the
-         * app updated in an attempt to get unscoped storage. If so, revoke all storage permissions.
+         * If the app is updated, then some checks need to be performed to ensure the
+         * package is not attempting to expoit permission changes across API boundaries.
          * @param newPackage The new package that was installed
          * @param oldPackage The old package that was updated
+         * @param allPackageNames The current packages in the system
+         * @param permissionCallback Callback for permission changed
          */
-        public void revokeStoragePermissionsIfScopeExpanded(
-                @NonNull PackageParser.Package newPackage,
-                @NonNull PackageParser.Package oldPackage,
-                @NonNull PermissionCallback permissionCallback) {
-            PermissionManagerService.this.revokeStoragePermissionsIfScopeExpanded(newPackage,
-                    oldPackage, permissionCallback);
-        }
-
-        @Override
-        public void revokeRuntimePermissionsIfGroupChanged(
+        public void onPackageUpdated(
                 @NonNull PackageParser.Package newPackage,
                 @NonNull PackageParser.Package oldPackage,
                 @NonNull ArrayList<String> allPackageNames,
                 @NonNull PermissionCallback permissionCallback) {
+            PermissionManagerService.this.revokeStoragePermissionsIfScopeExpanded(newPackage,
+                    oldPackage, permissionCallback);
+            PermissionManagerService.this.revokeSystemAlertWindowIfUpgradedPast23(newPackage,
+                    oldPackage, permissionCallback);
             PermissionManagerService.this.revokeRuntimePermissionsIfGroupChanged(newPackage,
                     oldPackage, allPackageNames, permissionCallback);
         }
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index 46fa4ff..a2f64ea 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -97,17 +97,15 @@
     public abstract void updateAllPermissions(@Nullable String volumeUuid, boolean sdkUpdate,
             @NonNull Collection<PackageParser.Package> allPacakges, PermissionCallback callback);
 
-    /**
-     * We might auto-grant permissions if any permission of the group is already granted. Hence if
-     * the group of a granted permission changes we need to revoke it to avoid having permissions of
-     * the new group auto-granted.
-     *
-     * @param newPackage The new package that was installed
-     * @param oldPackage The old package that was updated
-     * @param allPackageNames All packages
-     * @param permissionCallback Callback for permission changed
-     */
-    public abstract void revokeRuntimePermissionsIfGroupChanged(
+     /**
+      * If the app is updated, then some checks need to be performed to ensure the package is not 
+      * attempting to expoit permission changes across API boundaries.
+      * @param newPackage The new package that was installed
+      * @param oldPackage The old package that was updated
+      * @param allPackageNames The current packages in the system
+      * @param permissionCallback Callback for permission changed
+      */
+    public abstract void onPackageUpdated(
             @NonNull PackageParser.Package newPackage,
             @NonNull PackageParser.Package oldPackage,
             @NonNull ArrayList<String> allPackageNames,
@@ -127,17 +125,6 @@
             @NonNull PermissionCallback permissionCallback);
 
     /**
-     * If the app is updated, and has scoped storage permissions, then it is possible that the
-     * app updated in an attempt to get unscoped storage. If so, revoke all storage permissions.
-     * @param newPackage The new package that was installed
-     * @param oldPackage The old package that was updated
-     */
-    public abstract void revokeStoragePermissionsIfScopeExpanded(
-            @NonNull PackageParser.Package newPackage,
-            @NonNull PackageParser.Package oldPackage,
-            @NonNull PermissionCallback permissionCallback);
-
-    /**
      * Add all permissions in the given package.
      * <p>
      * NOTE: argument {@code groupTEMP} is temporary until mPermissionGroups is moved to
diff --git a/services/core/java/com/android/server/wm/AppTaskImpl.java b/services/core/java/com/android/server/wm/AppTaskImpl.java
index 1eb7455..900b59e 100644
--- a/services/core/java/com/android/server/wm/AppTaskImpl.java
+++ b/services/core/java/com/android/server/wm/AppTaskImpl.java
@@ -84,7 +84,8 @@
                 if (tr == null) {
                     throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
                 }
-                return mService.getRecentTasks().createRecentTaskInfo(tr);
+                return mService.getRecentTasks().createRecentTaskInfo(tr,
+                        true /* getTasksAllowed */);
             } finally {
                 Binder.restoreCallingIdentity(origId);
             }
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 541a8bb..56367f4 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -944,7 +944,7 @@
                 continue;
             }
 
-            final ActivityManager.RecentTaskInfo rti = createRecentTaskInfo(tr);
+            final ActivityManager.RecentTaskInfo rti = createRecentTaskInfo(tr, getTasksAllowed);
             if (!getDetailedTasks) {
                 rti.baseIntent.replaceExtras((Bundle) null);
             }
@@ -1715,12 +1715,15 @@
     /**
      * Creates a new RecentTaskInfo from a TaskRecord.
      */
-    ActivityManager.RecentTaskInfo createRecentTaskInfo(TaskRecord tr) {
+    ActivityManager.RecentTaskInfo createRecentTaskInfo(TaskRecord tr, boolean getTasksAllowed) {
         ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo();
         tr.fillTaskInfo(rti);
         // Fill in some deprecated values
         rti.id = rti.isRunning ? rti.taskId : INVALID_TASK_ID;
         rti.persistentId = rti.taskId;
+        if (!getTasksAllowed) {
+            TaskRecord.trimIneffectiveInfo(tr, rti);
+        }
         return rti;
     }
 
diff --git a/services/core/java/com/android/server/wm/RunningTasks.java b/services/core/java/com/android/server/wm/RunningTasks.java
index 3bf437d..20cb336 100644
--- a/services/core/java/com/android/server/wm/RunningTasks.java
+++ b/services/core/java/com/android/server/wm/RunningTasks.java
@@ -68,7 +68,7 @@
             }
 
             final TaskRecord task = iter.next();
-            list.add(createRunningTaskInfo(task));
+            list.add(createRunningTaskInfo(task, allowed));
             maxNum--;
         }
     }
@@ -76,11 +76,15 @@
     /**
      * Constructs a {@link RunningTaskInfo} from a given {@param task}.
      */
-    private RunningTaskInfo createRunningTaskInfo(TaskRecord task) {
+    private RunningTaskInfo createRunningTaskInfo(TaskRecord task, boolean allowed) {
         final RunningTaskInfo rti = new RunningTaskInfo();
         task.fillTaskInfo(rti);
         // Fill in some deprecated values
         rti.id = rti.taskId;
+
+        if (!allowed) {
+            TaskRecord.trimIneffectiveInfo(task, rti);
+        }
         return rti;
     }
 }
diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java
index 361f66e..9de4c81 100644
--- a/services/core/java/com/android/server/wm/TaskRecord.java
+++ b/services/core/java/com/android/server/wm/TaskRecord.java
@@ -2437,6 +2437,40 @@
     }
 
     /**
+     * Removes the activity info if the activity belongs to a different uid, which is
+     * different from the app that hosts the task.
+     */
+    static void trimIneffectiveInfo(TaskRecord task, TaskInfo info) {
+        int topActivityUid = task.effectiveUid;
+        for (int i = task.mActivities.size() - 1; i >= 0; --i) {
+            final ActivityRecord r = task.mActivities.get(i);
+            if (r.finishing || r.isState(ActivityState.INITIALIZING)) {
+                continue;
+            }
+            topActivityUid = r.info.applicationInfo.uid;
+            break;
+        }
+
+        if (task.effectiveUid != topActivityUid) {
+            info.topActivity = null;
+        }
+
+        int baseActivityUid = task.effectiveUid;
+        for (int i = 0; i < task.mActivities.size(); ++i) {
+            final ActivityRecord r = task.mActivities.get(i);
+            if (r.finishing) {
+                continue;
+            }
+            baseActivityUid = r.info.applicationInfo.uid;
+            break;
+        }
+
+        if (task.effectiveUid != baseActivityUid) {
+            info.baseActivity = null;
+        }
+    }
+
+    /**
      * Returns a  {@link TaskInfo} with information from this task.
      */
     ActivityManager.RunningTaskInfo getTaskInfo() {