Merge "Show snoozed conversations in conversation header" into rvc-dev
diff --git a/apex/statsd/aidl/Android.bp b/apex/statsd/aidl/Android.bp
index 487c8e1..404c632 100644
--- a/apex/statsd/aidl/Android.bp
+++ b/apex/statsd/aidl/Android.bp
@@ -31,7 +31,7 @@
     ],
     backend: {
         java: {
-            enabled: false, // the platform uses statsd_java_aidl
+            enabled: false, // framework-statsd and service-statsd use framework-statsd-aidl-sources
         },
         cpp: {
             enabled: false,
diff --git a/apex/statsd/tests/libstatspull/Android.bp b/apex/statsd/tests/libstatspull/Android.bp
index e813964..2d64f19 100644
--- a/apex/statsd/tests/libstatspull/Android.bp
+++ b/apex/statsd/tests/libstatspull/Android.bp
@@ -48,9 +48,13 @@
         "-Werror",
     ],
     shared_libs: [
-        "libbinder",
-        "libutils",
-        "libstatspull",
-        "libstatssocket",
+        "libbinder_ndk",
+        "statsd-aidl-ndk_platform",
     ],
-}
\ No newline at end of file
+    static_libs: [
+        "libstatspull_private",
+        "libstatssocket_private",
+        "libutils",
+        "libcutils",
+    ],
+}
diff --git a/apex/statsd/tests/libstatspull/jni/stats_pull_helper.cpp b/apex/statsd/tests/libstatspull/jni/stats_pull_helper.cpp
index 22daa8e..eb97f65 100644
--- a/apex/statsd/tests/libstatspull/jni/stats_pull_helper.cpp
+++ b/apex/statsd/tests/libstatspull/jni/stats_pull_helper.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <binder/ProcessState.h>
+#include <android/binder_process.h>
 #include <jni.h>
 #include <log/log.h>
 #include <stats_event.h>
@@ -24,7 +24,6 @@
 #include <thread>
 
 using std::this_thread::sleep_for;
-using namespace android;
 
 namespace {
 static int32_t sAtomTag;
@@ -39,10 +38,8 @@
     if (!initialized) {
         initialized = true;
         // Set up the binder
-        sp<ProcessState> ps(ProcessState::self());
-        ps->setThreadPoolMaxThreadCount(9);
-        ps->startThreadPool();
-        ps->giveThreadPoolName();
+        ABinderProcess_setThreadPoolMaxThreadCount(9);
+        ABinderProcess_startThreadPool();
     }
 }
 
diff --git a/api/current.txt b/api/current.txt
index 2ec3bcc..ca19c39 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -27059,7 +27059,7 @@
     method public void unregisterTransferCallback(@NonNull android.media.MediaRouter2.TransferCallback);
   }
 
-  public static class MediaRouter2.ControllerCallback {
+  public abstract static class MediaRouter2.ControllerCallback {
     ctor public MediaRouter2.ControllerCallback();
     method public void onControllerUpdated(@NonNull android.media.MediaRouter2.RoutingController);
   }
@@ -27068,7 +27068,7 @@
     method @Nullable public android.os.Bundle onGetControllerHints(@NonNull android.media.MediaRoute2Info);
   }
 
-  public static class MediaRouter2.RouteCallback {
+  public abstract static class MediaRouter2.RouteCallback {
     ctor public MediaRouter2.RouteCallback();
     method public void onRoutesAdded(@NonNull java.util.List<android.media.MediaRoute2Info>);
     method public void onRoutesChanged(@NonNull java.util.List<android.media.MediaRoute2Info>);
@@ -27091,7 +27091,7 @@
     method public void setVolume(int);
   }
 
-  public static class MediaRouter2.TransferCallback {
+  public abstract static class MediaRouter2.TransferCallback {
     ctor public MediaRouter2.TransferCallback();
     method public void onTransferFailed(@NonNull android.media.MediaRoute2Info);
     method public void onTransferred(@NonNull android.media.MediaRouter2.RoutingController, @Nullable android.media.MediaRouter2.RoutingController);
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 73a8f66..0c3a49a 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -302,11 +302,7 @@
     static_libs: [
         "libgmock",
         "libplatformprotos",
-
-        // TODO(b/149842105): Make libstatssocket shared and remove libcutils once statsd_test is
-        // moved to the apex.
-        "libstatssocket",
-        "libcutils",
+        "libstatssocket_private",
     ],
 
     proto: {
diff --git a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
index e7d91c2..115d6c4 100644
--- a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
+++ b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
@@ -40,11 +40,6 @@
 import android.content.pm.ServiceInfo;
 import android.content.pm.Signature;
 import android.content.pm.SigningInfo;
-import android.content.pm.parsing.ParsingPackage;
-import android.os.Environment;
-import android.os.UserHandle;
-
-import com.android.internal.util.ArrayUtils;
 import android.content.pm.parsing.component.ComponentParseUtils;
 import android.content.pm.parsing.component.ParsedActivity;
 import android.content.pm.parsing.component.ParsedComponent;
@@ -54,6 +49,10 @@
 import android.content.pm.parsing.component.ParsedPermissionGroup;
 import android.content.pm.parsing.component.ParsedProvider;
 import android.content.pm.parsing.component.ParsedService;
+import android.os.Environment;
+import android.os.UserHandle;
+
+import com.android.internal.util.ArrayUtils;
 
 import libcore.util.EmptyArray;
 
@@ -186,6 +185,22 @@
             return null;
         }
 
+        return generateWithoutComponentsUnchecked(pkg, gids, flags, firstInstallTime,
+                lastUpdateTime, grantedPermissions, state, userId, apexInfo, applicationInfo);
+    }
+
+    /**
+     * This bypasses critical checks that are necessary for usage with data passed outside of
+     * system server.
+     *
+     * Prefer {@link #generateWithoutComponents(ParsingPackageRead, int[], int, long, long, Set,
+     * PackageUserState, int, ApexInfo, ApplicationInfo)}.
+     */
+    @NonNull
+    public static PackageInfo generateWithoutComponentsUnchecked(ParsingPackageRead pkg, int[] gids,
+            @PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime,
+            Set<String> grantedPermissions, PackageUserState state, int userId,
+            @Nullable ApexInfo apexInfo, @NonNull ApplicationInfo applicationInfo) {
         PackageInfo pi = new PackageInfo();
         pi.packageName = pkg.getPackageName();
         pi.splitNames = pkg.getSplitNames();
@@ -317,6 +332,18 @@
             return null;
         }
 
+        return generateApplicationInfoUnchecked(pkg, flags, state, userId);
+    }
+
+    /**
+     * This bypasses critical checks that are necessary for usage with data passed outside of
+     * system server.
+     *
+     * Prefer {@link #generateApplicationInfo(ParsingPackageRead, int, PackageUserState, int)}.
+     */
+    @NonNull
+    public static ApplicationInfo generateApplicationInfoUnchecked(@NonNull ParsingPackageRead pkg,
+            @PackageManager.ApplicationInfoFlags int flags, PackageUserState state, int userId) {
         // Make shallow copy so we can store the metadata/libraries safely
         ApplicationInfo ai = pkg.toAppInfoWithoutState();
         // Init handles data directories
@@ -378,6 +405,23 @@
         if (applicationInfo == null) {
             applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
         }
+        if (applicationInfo == null) {
+            return null;
+        }
+
+        return generateActivityInfoUnchecked(a, applicationInfo);
+    }
+
+    /**
+     * This bypasses critical checks that are necessary for usage with data passed outside of
+     * system server.
+     *
+     * Prefer {@link #generateActivityInfo(ParsingPackageRead, ParsedActivity, int,
+     * PackageUserState, ApplicationInfo, int)}.
+     */
+    @NonNull
+    public static ActivityInfo generateActivityInfoUnchecked(@NonNull ParsedActivity a,
+            @NonNull ApplicationInfo applicationInfo) {
         // Make shallow copies so we can store the metadata safely
         ActivityInfo ai = new ActivityInfo();
         assignSharedFieldsForComponentInfo(ai, a);
@@ -431,6 +475,23 @@
         if (applicationInfo == null) {
             applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
         }
+        if (applicationInfo == null) {
+            return null;
+        }
+
+        return generateServiceInfoUnchecked(s, applicationInfo);
+    }
+
+    /**
+     * This bypasses critical checks that are necessary for usage with data passed outside of
+     * system server.
+     *
+     * Prefer {@link #generateServiceInfo(ParsingPackageRead, ParsedService, int, PackageUserState,
+     * ApplicationInfo, int)}.
+     */
+    @NonNull
+    public static ServiceInfo generateServiceInfoUnchecked(@NonNull ParsedService s,
+            @NonNull ApplicationInfo applicationInfo) {
         // Make shallow copies so we can store the metadata safely
         ServiceInfo si = new ServiceInfo();
         assignSharedFieldsForComponentInfo(si, s);
@@ -461,6 +522,24 @@
         if (applicationInfo == null) {
             applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
         }
+        if (applicationInfo == null) {
+            return null;
+        }
+
+        return generateProviderInfoUnchecked(p, flags, applicationInfo);
+    }
+
+    /**
+     * This bypasses critical checks that are necessary for usage with data passed outside of
+     * system server.
+     *
+     * Prefer {@link #generateProviderInfo(ParsingPackageRead, ParsedProvider, int,
+     * PackageUserState, ApplicationInfo, int)}.
+     */
+    @NonNull
+    public static ProviderInfo generateProviderInfoUnchecked(@NonNull ParsedProvider p,
+            @PackageManager.ComponentInfoFlags int flags,
+            @NonNull ApplicationInfo applicationInfo) {
         // Make shallow copies so we can store the metadata safely
         ProviderInfo pi = new ProviderInfo();
         assignSharedFieldsForComponentInfo(pi, p);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index f2d415a..fa2b014 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -53,7 +53,9 @@
 import android.net.ConnectivityManager;
 import android.net.NetworkScoreManager;
 import android.net.Uri;
+import android.net.wifi.SoftApConfiguration;
 import android.net.wifi.WifiManager;
+import android.net.wifi.p2p.WifiP2pManager;
 import android.os.BatteryManager;
 import android.os.Binder;
 import android.os.Build.VERSION_CODES;
@@ -10272,7 +10274,8 @@
        /**
         * Setting to allow scans to be enabled even wifi is turned off for connectivity.
         * @hide
-        * @deprecated To be removed.
+        * @deprecated To be removed. Use {@link WifiManager#setScanAlwaysAvailable(boolean)} for
+        * setting the value and {@link WifiManager#isScanAlwaysAvailable()} for query.
         */
        public static final String WIFI_SCAN_ALWAYS_AVAILABLE =
                 "wifi_scan_always_enabled";
@@ -10292,7 +10295,9 @@
          *
          * Type: int (0 for false, 1 for true)
          * @hide
-         * @deprecated To be removed.
+         * @deprecated To be removed. Use {@link SoftApConfiguration.Builder#
+         * setAutoShutdownEnabled(boolean)} for setting the value and {@link SoftApConfiguration#
+         * isAutoShutdownEnabled()} for query.
          */
         public static final String SOFT_AP_TIMEOUT_ENABLED = "soft_ap_timeout_enabled";
 
@@ -10301,7 +10306,8 @@
          *
          * Type: int (0 for false, 1 for true)
          * @hide
-         * @deprecated Use {@link WifiManager#isAutoWakeupEnabled()} instead.
+         * @deprecated Use {@link WifiManager#setAutoWakeupEnabled(boolean)} for setting the value
+         * and {@link WifiManager#isAutoWakeupEnabled()} for query.
          */
         @Deprecated
         @SystemApi
@@ -10381,7 +10387,8 @@
          *
          * Type: int (0 for false, 1 for true)
          * @hide
-         * @deprecated To be removed.
+         * @deprecated Use {@link WifiManager#setScanThrottleEnabled(boolean)} for setting the value
+         * and {@link WifiManager#isScanThrottleEnabled()} for query.
          */
         public static final String WIFI_SCAN_THROTTLE_ENABLED = "wifi_scan_throttle_enabled";
 
@@ -10484,7 +10491,8 @@
         * Setting to enable verbose logging in Wi-Fi; disabled by default, and setting to 1
         * will enable it. In the future, additional values may be supported.
         * @hide
-        * @deprecated To be removed.
+        * @deprecated Use {@link WifiManager#setVerboseLoggingEnabled(boolean)} for setting the
+        * value and {@link WifiManager#isVerboseLoggingEnabled()} for query.
         */
        public static final String WIFI_VERBOSE_LOGGING_ENABLED =
                "wifi_verbose_logging_enabled";
@@ -10553,7 +10561,9 @@
        /**
         * The Wi-Fi peer-to-peer device name
         * @hide
-        * @deprecated To be removed.
+        * @deprecated Use {@link WifiP2pManager#setDeviceName(WifiP2pManager.Channel, String,
+        * WifiP2pManager.ActionListener)} for setting the value and
+        * {@link android.net.wifi.p2p.WifiP2pDevice#deviceName} for query.
         */
        public static final String WIFI_P2P_DEVICE_NAME = "wifi_p2p_device_name";
 
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index 3410919..68df7d2 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -749,7 +749,7 @@
     /**
      * Callback for receiving events about media route discovery.
      */
-    public static class RouteCallback {
+    public abstract static class RouteCallback {
         /**
          * Called when routes are added. Whenever you registers a callback, this will
          * be invoked with known routes.
@@ -777,7 +777,7 @@
     /**
      * Callback for receiving events on media transfer.
      */
-    public static class TransferCallback {
+    public abstract static class TransferCallback {
         /**
          * Called when a media is transferred between two different routing controllers.
          * This can happen by calling {@link #transferTo(MediaRoute2Info)} or
@@ -826,7 +826,7 @@
     /**
      * Callback for receiving {@link RoutingController} updates.
      */
-    public static class ControllerCallback {
+    public abstract static class ControllerCallback {
         /**
          * Called when a controller is updated. (e.g., the selected routes of the
          * controller is changed or the volume of the controller is changed.)
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
index bcff6a1..4e12859 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
@@ -123,7 +123,7 @@
 
     @Test
     public void testOnRoutesRemovedAndAdded() throws Exception {
-        RouteCallback routeCallback = new RouteCallback();
+        RouteCallback routeCallback = new RouteCallback() {};
         mRouteCallbacks.add(routeCallback);
         mRouter2.registerRouteCallback(mExecutor, routeCallback,
                 new RouteDiscoveryPreference.Builder(FEATURES_ALL, true).build());
@@ -201,7 +201,7 @@
 
         addManagerCallback(new MediaRouter2Manager.Callback());
         //TODO: remove this when it's not necessary.
-        addRouterCallback(new MediaRouter2.RouteCallback());
+        addRouterCallback(new MediaRouter2.RouteCallback() {});
         addTransferCallback(new MediaRouter2.TransferCallback() {
             @Override
             public void onTransferred(MediaRouter2.RoutingController oldController,
@@ -228,7 +228,7 @@
         CountDownLatch latch = new CountDownLatch(1);
 
         Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(FEATURES_ALL);
-        addRouterCallback(new RouteCallback());
+        addRouterCallback(new RouteCallback() {});
         addManagerCallback(new MediaRouter2Manager.Callback() {
             @Override
             public void onSessionCreated(MediaRouter2Manager.RoutingController controller) {
@@ -263,7 +263,7 @@
     @Test
     public void testSelectAndTransferAndRelease() throws Exception {
         Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(FEATURES_ALL);
-        addRouterCallback(new RouteCallback());
+        addRouterCallback(new RouteCallback() {});
 
         CountDownLatch onSessionCreatedLatch = new CountDownLatch(1);
 
@@ -346,7 +346,7 @@
     @Test
     public void testSetSessionVolume() throws Exception {
         Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(FEATURES_ALL);
-        addRouterCallback(new RouteCallback());
+        addRouterCallback(new RouteCallback() {});
 
         CountDownLatch onSessionCreatedLatch = new CountDownLatch(1);
         CountDownLatch volumeChangedLatch = new CountDownLatch(2);
@@ -471,7 +471,7 @@
         CountDownLatch featuresLatch = new CountDownLatch(1);
 
         // A dummy callback is required to send route feature info.
-        RouteCallback routeCallback = new RouteCallback();
+        RouteCallback routeCallback = new RouteCallback() {};
         MediaRouter2Manager.Callback managerCallback = new MediaRouter2Manager.Callback() {
             @Override
             public void onRoutesAdded(List<MediaRoute2Info> routes) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index ba8a1a9..3cf07d1 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -19,7 +19,9 @@
 import static android.view.ViewRootImpl.sNewInsetsMode;
 import static android.view.WindowInsets.Type.ime;
 import static android.view.WindowInsets.Type.systemBars;
+
 import static com.android.systemui.DejankUtils.whitelistIpcs;
+
 import static java.lang.Integer.max;
 
 import android.app.Activity;
@@ -28,7 +30,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.ColorStateList;
-import android.graphics.Rect;
 import android.metrics.LogMaker;
 import android.os.Handler;
 import android.os.Looper;
@@ -511,6 +512,8 @@
         boolean finish = false;
         boolean strongAuth = false;
         int eventSubtype = -1;
+        mCurrentSecuritySelection = whitelistIpcs(() ->
+                mSecurityModel.getSecurityMode(targetUserId));
         if (mUpdateMonitor.getUserHasTrust(targetUserId)) {
             finish = true;
             eventSubtype = BOUNCER_DISMISS_EXTENDED_ACCESS;
@@ -518,13 +521,8 @@
             finish = true;
             eventSubtype = BOUNCER_DISMISS_BIOMETRIC;
         } else if (SecurityMode.None == mCurrentSecuritySelection) {
-            SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId);
-            if (SecurityMode.None == securityMode) {
-                finish = true; // no security required
-                eventSubtype = BOUNCER_DISMISS_NONE_SECURITY;
-            } else {
-                showSecurityScreen(securityMode); // switch to the alternate security view
-            }
+            finish = true; // no security required
+            eventSubtype = BOUNCER_DISMISS_NONE_SECURITY;
         } else if (authenticated) {
             switch (mCurrentSecuritySelection) {
                 case Pattern:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
index b3561c2..8ee2f50 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar.notification.stack;
 
+import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_GENTLE;
+
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
 import android.annotation.IntDef;
@@ -100,14 +102,11 @@
     private boolean mInitialized = false;
 
     private SectionHeaderView mGentleHeader;
-    private boolean mGentleHeaderVisible;
     @Nullable private View.OnClickListener mOnClearGentleNotifsClickListener;
 
     private SectionHeaderView mAlertingHeader;
-    private boolean mAlertingHeaderVisible;
 
     private PeopleHubView mPeopleHubView;
-    private boolean mPeopleHeaderVisible;
     private boolean mPeopleHubVisible = false;
     @Nullable private Subscription mPeopleHubSubscription;
 
@@ -231,88 +230,135 @@
             return;
         }
 
+        // The overall strategy here is to iterate over the current children of mParent, looking
+        // for where the sections headers are currently positioned, and where each section begins.
+        // Then, once we find the start of a new section, we track that position as the "target" for
+        // the section header, adjusted for the case where existing headers are in front of that
+        // target, but won't be once they are moved / removed after the pass has completed.
+
         final boolean showHeaders = mStatusBarStateController.getState() != StatusBarState.KEYGUARD;
         final boolean usingPeopleFiltering = mSectionsFeatureManager.isFilteringEnabled();
 
         boolean peopleNotifsPresent = false;
+
+        int currentPeopleHeaderIdx = -1;
         int peopleHeaderTarget = -1;
+        int currentAlertingHeaderIdx = -1;
         int alertingHeaderTarget = -1;
+        int currentGentleHeaderIdx = -1;
         int gentleHeaderTarget = -1;
 
-        int viewCount = 0;
+        int lastNotifIndex = 0;
 
-        if (showHeaders) {
-            final int childCount = mParent.getChildCount();
-            for (int i = 0; i < childCount; i++) {
-                View child = mParent.getChildAt(i);
-                if (child.getVisibility() == View.GONE
-                        || !(child instanceof ExpandableNotificationRow)) {
-                    continue;
-                }
-                ExpandableNotificationRow row = (ExpandableNotificationRow) child;
-                switch (row.getEntry().getBucket()) {
-                    case BUCKET_PEOPLE:
-                        if (peopleHeaderTarget == -1) {
-                            peopleNotifsPresent = true;
-                            peopleHeaderTarget = viewCount;
-                            viewCount++;
-                        }
-                        break;
-                    case BUCKET_ALERTING:
-                        if (usingPeopleFiltering && alertingHeaderTarget == -1) {
-                            alertingHeaderTarget = viewCount;
-                            viewCount++;
-                        }
-                        break;
-                    case BUCKET_SILENT:
-                        if (gentleHeaderTarget == -1) {
-                            gentleHeaderTarget = viewCount;
-                            viewCount++;
-                        }
-                        break;
-                }
-                viewCount++;
+        final int childCount = mParent.getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View child = mParent.getChildAt(i);
+
+            // Track the existing positions of the headers
+            if (child == mPeopleHubView) {
+                currentPeopleHeaderIdx = i;
+                continue;
             }
-            if (usingPeopleFiltering && mPeopleHubVisible && peopleHeaderTarget == -1) {
-                // Insert the people header even if there are no people visible, in order to show
-                // the hub. Put it directly above the next header.
-                if (alertingHeaderTarget != -1) {
-                    peopleHeaderTarget = alertingHeaderTarget;
-                    alertingHeaderTarget++;
-                    gentleHeaderTarget++;
-                } else if (gentleHeaderTarget != -1) {
-                    peopleHeaderTarget = gentleHeaderTarget;
-                    gentleHeaderTarget++;
-                } else {
-                    // Put it at the end of the list.
-                    peopleHeaderTarget = viewCount;
-                }
+            if (child == mAlertingHeader) {
+                currentAlertingHeaderIdx = i;
+                continue;
+            }
+            if (child == mGentleHeader) {
+                currentGentleHeaderIdx = i;
+                continue;
+            }
+
+            if (!(child instanceof ExpandableNotificationRow)) {
+                continue;
+            }
+            lastNotifIndex = i;
+            ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+            // Once we enter a new section, calculate the target position for the header.
+            switch (row.getEntry().getBucket()) {
+                case BUCKET_HEADS_UP:
+                    break;
+                case BUCKET_PEOPLE:
+                    peopleNotifsPresent = true;
+                    if (showHeaders && peopleHeaderTarget == -1) {
+                        peopleHeaderTarget = i;
+                        // Offset the target if there are other headers before this that will be
+                        // moved.
+                        if (currentPeopleHeaderIdx != -1) {
+                            peopleHeaderTarget--;
+                        }
+                        if (currentAlertingHeaderIdx != -1) {
+                            peopleHeaderTarget--;
+                        }
+                        if (currentGentleHeaderIdx != -1) {
+                            peopleHeaderTarget--;
+                        }
+                    }
+                    break;
+                case BUCKET_ALERTING:
+                    if (showHeaders && usingPeopleFiltering && alertingHeaderTarget == -1) {
+                        alertingHeaderTarget = i;
+                        // Offset the target if there are other headers before this that will be
+                        // moved.
+                        if (currentAlertingHeaderIdx != -1) {
+                            alertingHeaderTarget--;
+                        }
+                        if (currentGentleHeaderIdx != -1) {
+                            alertingHeaderTarget--;
+                        }
+                    }
+                    break;
+                case BUCKET_SILENT:
+                    if (showHeaders && gentleHeaderTarget == -1) {
+                        gentleHeaderTarget = i;
+                        // Offset the target if there are other headers before this that will be
+                        // moved.
+                        if (currentGentleHeaderIdx != -1) {
+                            gentleHeaderTarget--;
+                        }
+                    }
+                    break;
+                default:
+                    throw new IllegalStateException("Cannot find section bucket for view");
+            }
+        }
+        if (showHeaders && usingPeopleFiltering && mPeopleHubVisible && peopleHeaderTarget == -1) {
+            // Insert the people header even if there are no people visible, in order to show
+            // the hub. Put it directly above the next header.
+            if (alertingHeaderTarget != -1) {
+                peopleHeaderTarget = alertingHeaderTarget;
+            } else if (gentleHeaderTarget != -1) {
+                peopleHeaderTarget = gentleHeaderTarget;
+            } else {
+                // Put it at the end of the list.
+                peopleHeaderTarget = lastNotifIndex;
             }
         }
 
-        // Allow swiping the people header if the section is empty
-        mPeopleHubView.setCanSwipe(mPeopleHubVisible && !peopleNotifsPresent);
+        // Add headers in reverse order to preserve indices
+        adjustHeaderVisibilityAndPosition(
+                gentleHeaderTarget, mGentleHeader, currentGentleHeaderIdx);
+        adjustHeaderVisibilityAndPosition(
+                alertingHeaderTarget, mAlertingHeader, currentAlertingHeaderIdx);
+        adjustHeaderVisibilityAndPosition(
+                peopleHeaderTarget, mPeopleHubView, currentPeopleHeaderIdx);
 
-        mPeopleHeaderVisible = adjustHeaderVisibilityAndPosition(
-                peopleHeaderTarget, mPeopleHubView, mPeopleHeaderVisible);
-        mAlertingHeaderVisible = adjustHeaderVisibilityAndPosition(
-                alertingHeaderTarget, mAlertingHeader, mAlertingHeaderVisible);
-        mGentleHeaderVisible = adjustHeaderVisibilityAndPosition(
-                gentleHeaderTarget, mGentleHeader, mGentleHeaderVisible);
+        // Update headers to reflect state of section contents
+        mGentleHeader.setAreThereDismissableGentleNotifs(
+                mParent.hasActiveClearableNotifications(ROWS_GENTLE));
+        mPeopleHubView.setCanSwipe(showHeaders && mPeopleHubVisible && !peopleNotifsPresent);
+        if (peopleHeaderTarget != currentPeopleHeaderIdx) {
+            mPeopleHubView.resetTranslation();
+        }
     }
 
-    private boolean adjustHeaderVisibilityAndPosition(
-            int targetIndex, StackScrollerDecorView header, boolean isCurrentlyVisible) {
-        if (targetIndex == -1) {
-            if (isCurrentlyVisible) {
+    private void adjustHeaderVisibilityAndPosition(
+            int targetPosition, StackScrollerDecorView header, int currentPosition) {
+        if (targetPosition == -1) {
+            if (currentPosition != -1) {
                 mParent.removeView(header);
             }
-            return false;
         } else {
-            if (header instanceof SwipeableView) {
-                ((SwipeableView) header).resetTranslation();
-            }
-            if (!isCurrentlyVisible) {
+            if (currentPosition == -1) {
                 // If the header is animating away, it will still have a parent, so detach it first
                 // TODO: We should really cancel the active animations here. This will happen
                 // automatically when the view's intro animation starts, but it's a fragile link.
@@ -321,11 +367,10 @@
                     header.setTransientContainer(null);
                 }
                 header.setContentVisible(true);
-                mParent.addView(header, targetIndex);
-            } else if (mParent.indexOfChild(header) != targetIndex) {
-                mParent.changeViewPosition(header, targetIndex);
+                mParent.addView(header, targetPosition);
+            } else {
+                mParent.changeViewPosition(header, targetPosition);
             }
-            return true;
         }
     }
 
@@ -400,10 +445,20 @@
 
 
     @VisibleForTesting
-    SectionHeaderView getGentleHeaderView() {
+    ExpandableView getGentleHeaderView() {
         return mGentleHeader;
     }
 
+    @VisibleForTesting
+    ExpandableView getAlertingHeaderView() {
+        return mAlertingHeader;
+    }
+
+    @VisibleForTesting
+    ExpandableView getPeopleHeaderView() {
+        return mPeopleHubView;
+    }
+
     private final ConfigurationListener mConfigurationListener = new ConfigurationListener() {
         @Override
         public void onLocaleListChanged() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
index abfbcd9..c64dd09 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
@@ -19,6 +19,8 @@
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 
 import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING;
+import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_HEADS_UP;
+import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_PEOPLE;
 import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT;
 
 import static org.mockito.ArgumentMatchers.any;
@@ -107,7 +109,7 @@
     @Test
     public void testInsertHeader() {
         // GIVEN a stack with HI and LO rows but no section headers
-        setStackState(ChildType.HIPRI, ChildType.HIPRI, ChildType.HIPRI, ChildType.LOPRI);
+        setStackState(ChildType.ALERTING, ChildType.ALERTING, ChildType.ALERTING, ChildType.GENTLE);
 
         // WHEN we update the section headers
         mSectionsManager.updateSectionBoundaries();
@@ -119,11 +121,15 @@
     @Test
     public void testRemoveHeader() {
         // GIVEN a stack that originally had a header between the HI and LO sections
-        setStackState(ChildType.HIPRI, ChildType.HIPRI, ChildType.LOPRI);
+        setStackState(ChildType.ALERTING, ChildType.ALERTING, ChildType.GENTLE);
         mSectionsManager.updateSectionBoundaries();
 
         // WHEN the last LO row is replaced with a HI row
-        setStackState(ChildType.HIPRI, ChildType.HIPRI, ChildType.HEADER, ChildType.HIPRI);
+        setStackState(
+                ChildType.ALERTING,
+                ChildType.ALERTING,
+                ChildType.GENTLE_HEADER,
+                ChildType.ALERTING);
         clearInvocations(mNssl);
         mSectionsManager.updateSectionBoundaries();
 
@@ -134,7 +140,7 @@
     @Test
     public void testDoNothingIfHeaderAlreadyRemoved() {
         // GIVEN a stack with only HI rows
-        setStackState(ChildType.HIPRI, ChildType.HIPRI, ChildType.HIPRI);
+        setStackState(ChildType.ALERTING, ChildType.ALERTING, ChildType.ALERTING);
 
         // WHEN we update the sections headers
         mSectionsManager.updateSectionBoundaries();
@@ -147,19 +153,19 @@
     public void testMoveHeaderForward() {
         // GIVEN a stack that originally had a header between the HI and LO sections
         setStackState(
-                ChildType.HIPRI,
-                ChildType.HIPRI,
-                ChildType.HIPRI,
-                ChildType.LOPRI);
+                ChildType.ALERTING,
+                ChildType.ALERTING,
+                ChildType.ALERTING,
+                ChildType.GENTLE);
         mSectionsManager.updateSectionBoundaries();
 
         // WHEN the LO section moves forward
         setStackState(
-                ChildType.HIPRI,
-                ChildType.HIPRI,
-                ChildType.LOPRI,
-                ChildType.HEADER,
-                ChildType.LOPRI);
+                ChildType.ALERTING,
+                ChildType.ALERTING,
+                ChildType.GENTLE,
+                ChildType.GENTLE_HEADER,
+                ChildType.GENTLE);
         mSectionsManager.updateSectionBoundaries();
 
         // THEN the LO section header is also moved forward
@@ -170,19 +176,19 @@
     public void testMoveHeaderBackward() {
         // GIVEN a stack that originally had a header between the HI and LO sections
         setStackState(
-                ChildType.HIPRI,
-                ChildType.LOPRI,
-                ChildType.LOPRI,
-                ChildType.LOPRI);
+                ChildType.ALERTING,
+                ChildType.GENTLE,
+                ChildType.GENTLE,
+                ChildType.GENTLE);
         mSectionsManager.updateSectionBoundaries();
 
         // WHEN the LO section moves backward
         setStackState(
-                ChildType.HIPRI,
-                ChildType.HEADER,
-                ChildType.HIPRI,
-                ChildType.HIPRI,
-                ChildType.LOPRI);
+                ChildType.ALERTING,
+                ChildType.GENTLE_HEADER,
+                ChildType.ALERTING,
+                ChildType.ALERTING,
+                ChildType.GENTLE);
         mSectionsManager.updateSectionBoundaries();
 
         // THEN the LO section header is also moved backward (with appropriate index shifting)
@@ -193,14 +199,14 @@
     public void testHeaderRemovedFromTransientParent() {
         // GIVEN a stack where the header is animating away
         setStackState(
-                ChildType.HIPRI,
-                ChildType.LOPRI,
-                ChildType.LOPRI,
-                ChildType.LOPRI);
+                ChildType.ALERTING,
+                ChildType.GENTLE,
+                ChildType.GENTLE,
+                ChildType.GENTLE);
         mSectionsManager.updateSectionBoundaries();
         setStackState(
-                ChildType.HIPRI,
-                ChildType.HEADER);
+                ChildType.ALERTING,
+                ChildType.GENTLE_HEADER);
         mSectionsManager.updateSectionBoundaries();
         clearInvocations(mNssl);
 
@@ -209,8 +215,8 @@
 
         // WHEN the LO section reappears
         setStackState(
-                ChildType.HIPRI,
-                ChildType.LOPRI);
+                ChildType.ALERTING,
+                ChildType.GENTLE);
         mSectionsManager.updateSectionBoundaries();
 
         // THEN the header is first removed from the transient parent before being added to the
@@ -223,7 +229,7 @@
     public void testHeaderNotShownOnLockscreen() {
         // GIVEN a stack of HI and LO notifs on the lockscreen
         when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
-        setStackState(ChildType.HIPRI, ChildType.HIPRI, ChildType.HIPRI, ChildType.LOPRI);
+        setStackState(ChildType.ALERTING, ChildType.ALERTING, ChildType.ALERTING, ChildType.GENTLE);
 
         // WHEN we update the section headers
         mSectionsManager.updateSectionBoundaries();
@@ -236,7 +242,7 @@
     public void testHeaderShownWhenEnterLockscreen() {
         // GIVEN a stack of HI and LO notifs on the lockscreen
         when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
-        setStackState(ChildType.HIPRI, ChildType.HIPRI, ChildType.HIPRI, ChildType.LOPRI);
+        setStackState(ChildType.ALERTING, ChildType.ALERTING, ChildType.ALERTING, ChildType.GENTLE);
         mSectionsManager.updateSectionBoundaries();
 
         // WHEN we unlock
@@ -250,37 +256,104 @@
     @Test
     public void testHeaderHiddenWhenEnterLockscreen() {
         // GIVEN a stack of HI and LO notifs on the shade
-        when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE_LOCKED);
-        setStackState(ChildType.HIPRI, ChildType.HIPRI, ChildType.HIPRI, ChildType.LOPRI);
-        mSectionsManager.updateSectionBoundaries();
+        setStackState(ChildType.ALERTING, ChildType.GENTLE_HEADER, ChildType.GENTLE);
 
         // WHEN we go back to the keyguard
         when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
         mSectionsManager.updateSectionBoundaries();
 
         // Then the section header is removed
-        verify(mNssl).removeView(eq(mSectionsManager.getGentleHeaderView()));
+        verify(mNssl).removeView(mSectionsManager.getGentleHeaderView());
     }
 
-    private enum ChildType { HEADER, HIPRI, LOPRI }
+    @Test
+    public void testPeopleFiltering_addHeadersFromShowingOnlyGentle() {
+        enablePeopleFiltering();
+
+        setStackState(
+                ChildType.GENTLE_HEADER,
+                ChildType.PERSON,
+                ChildType.ALERTING,
+                ChildType.GENTLE);
+        mSectionsManager.updateSectionBoundaries();
+
+        verify(mNssl).changeViewPosition(mSectionsManager.getGentleHeaderView(), 2);
+        verify(mNssl).addView(mSectionsManager.getAlertingHeaderView(), 1);
+        verify(mNssl).addView(mSectionsManager.getPeopleHeaderView(), 0);
+    }
+
+    @Test
+    public void testPeopleFiltering_addAllHeaders() {
+        enablePeopleFiltering();
+
+        setStackState(
+                ChildType.PERSON,
+                ChildType.ALERTING,
+                ChildType.GENTLE);
+        mSectionsManager.updateSectionBoundaries();
+
+        verify(mNssl).addView(mSectionsManager.getGentleHeaderView(), 2);
+        verify(mNssl).addView(mSectionsManager.getAlertingHeaderView(), 1);
+        verify(mNssl).addView(mSectionsManager.getPeopleHeaderView(), 0);
+    }
+
+    @Test
+    public void testPeopleFiltering_moveAllHeaders() {
+        enablePeopleFiltering();
+
+        setStackState(
+                ChildType.PEOPLE_HEADER,
+                ChildType.ALERTING_HEADER,
+                ChildType.GENTLE_HEADER,
+                ChildType.PERSON,
+                ChildType.ALERTING,
+                ChildType.GENTLE);
+        mSectionsManager.updateSectionBoundaries();
+
+        verify(mNssl).changeViewPosition(mSectionsManager.getGentleHeaderView(), 4);
+        verify(mNssl).changeViewPosition(mSectionsManager.getAlertingHeaderView(), 2);
+        verify(mNssl).changeViewPosition(mSectionsManager.getPeopleHeaderView(), 0);
+    }
+
+    private void enablePeopleFiltering() {
+        when(mSectionsFeatureManager.isFilteringEnabled()).thenReturn(true);
+        when(mSectionsFeatureManager.getNumberOfBuckets()).thenReturn(4);
+    }
+
+    private enum ChildType {
+        PEOPLE_HEADER, ALERTING_HEADER, GENTLE_HEADER, HEADS_UP, PERSON, ALERTING, GENTLE, OTHER
+    }
 
     private void setStackState(ChildType... children) {
         when(mNssl.getChildCount()).thenReturn(children.length);
         for (int i = 0; i < children.length; i++) {
             View child;
             switch (children[i]) {
-                case HEADER:
+                case PEOPLE_HEADER:
+                    child = mSectionsManager.getPeopleHeaderView();
+                    break;
+                case ALERTING_HEADER:
+                    child = mSectionsManager.getAlertingHeaderView();
+                    break;
+                case GENTLE_HEADER:
                     child = mSectionsManager.getGentleHeaderView();
                     break;
-                case HIPRI:
-                case LOPRI:
-                    ExpandableNotificationRow notifRow = mock(ExpandableNotificationRow.class,
-                            RETURNS_DEEP_STUBS);
-                    when(notifRow.getVisibility()).thenReturn(View.VISIBLE);
-                    when(notifRow.getEntry().getBucket()).thenReturn(
-                            children[i] == ChildType.HIPRI ? BUCKET_ALERTING : BUCKET_SILENT);
-                    when(notifRow.getParent()).thenReturn(mNssl);
-                    child = notifRow;
+                case HEADS_UP:
+                    child = mockNotification(BUCKET_HEADS_UP);
+                    break;
+                case PERSON:
+                    child = mockNotification(BUCKET_PEOPLE);
+                    break;
+                case ALERTING:
+                    child = mockNotification(BUCKET_ALERTING);
+                    break;
+                case GENTLE:
+                    child = mockNotification(BUCKET_SILENT);
+                    break;
+                case OTHER:
+                    child = mock(View.class);
+                    when(child.getVisibility()).thenReturn(View.VISIBLE);
+                    when(child.getParent()).thenReturn(mNssl);
                     break;
                 default:
                     throw new RuntimeException("Unknown ChildType: " + children[i]);
@@ -289,4 +362,13 @@
             when(mNssl.indexOfChild(child)).thenReturn(i);
         }
     }
+
+    private View mockNotification(int bucket) {
+        ExpandableNotificationRow notifRow = mock(ExpandableNotificationRow.class,
+                RETURNS_DEEP_STUBS);
+        when(notifRow.getVisibility()).thenReturn(View.VISIBLE);
+        when(notifRow.getEntry().getBucket()).thenReturn(bucket);
+        when(notifRow.getParent()).thenReturn(mNssl);
+        return notifRow;
+    }
 }
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 1b1e06a..485127a 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -845,18 +845,11 @@
             "android.content.pm.extra.ENABLE_ROLLBACK_TOKEN";
 
     /**
-     * Extra field name for the installFlags of a request to enable rollback
+     * Extra field name for the session id of a request to enable rollback
      * for a package.
      */
-    public static final String EXTRA_ENABLE_ROLLBACK_INSTALL_FLAGS =
-            "android.content.pm.extra.ENABLE_ROLLBACK_INSTALL_FLAGS";
-
-    /**
-     * Extra field name for the user id an install is associated with when
-     * enabling rollback.
-     */
-    public static final String EXTRA_ENABLE_ROLLBACK_USER =
-            "android.content.pm.extra.ENABLE_ROLLBACK_USER";
+    public static final String EXTRA_ENABLE_ROLLBACK_SESSION_ID =
+            "android.content.pm.extra.ENABLE_ROLLBACK_SESSION_ID";
 
     /**
      * Used as the {@code enableRollbackCode} argument for
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 3441a5f..7840b19 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -1670,6 +1670,7 @@
             Intent intent = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
             intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
                     | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND
+                    | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
                     | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
             intent.putExtra("time-zone", zone.getID());
             getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index f2bc1fe..5d1b0e3 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -2334,6 +2334,19 @@
             if (sb == null) sb = new StringBuilder();
             sb.append("seq=" + app.startSeq + ",expected=" + expectedStartSeq + ";");
         }
+        try {
+            AppGlobals.getPackageManager().checkPackageStartable(app.info.packageName, app.userId);
+        } catch (RemoteException e) {
+            // unexpected; ignore
+        } catch (SecurityException e) {
+            if (mService.mConstants.FLAG_PROCESS_START_ASYNC) {
+                if (sb == null) sb = new StringBuilder();
+                sb.append("Package is frozen;");
+            } else {
+                // we're not being started async and so should throw to the caller.
+                throw e;
+            }
+        }
         return sb == null ? null : sb.toString();
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 41988d6..5cc5059 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -1689,8 +1689,8 @@
         }
 
         mRelinquished = true;
-        return new PackageManagerService.ActiveInstallSession(mPackageName, stageDir,
-                localObserver, params, mInstallerUid, mInstallSource, user, mSigningDetails);
+        return new PackageManagerService.ActiveInstallSession(mPackageName, stageDir, localObserver,
+                sessionId, params, mInstallerUid, mInstallSource, user, mSigningDetails);
     }
 
     private static void maybeRenameFile(File from, File to) throws PackageManagerException {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 74cb93d..36843d4 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1967,6 +1967,7 @@
                 }
                 case ENABLE_ROLLBACK_TIMEOUT: {
                     final int enableRollbackToken = msg.arg1;
+                    final int sessionId = msg.arg2;
                     final InstallParams params = mPendingEnableRollback.get(enableRollbackToken);
                     if (params != null) {
                         final InstallArgs args = params.mArgs;
@@ -1982,8 +1983,8 @@
                         Intent rollbackTimeoutIntent = new Intent(
                                 Intent.ACTION_CANCEL_ENABLE_ROLLBACK);
                         rollbackTimeoutIntent.putExtra(
-                                PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN,
-                                enableRollbackToken);
+                                PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_SESSION_ID,
+                                sessionId);
                         rollbackTimeoutIntent.addFlags(
                                 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
                         mContext.sendBroadcastAsUser(rollbackTimeoutIntent, UserHandle.SYSTEM,
@@ -14260,6 +14261,7 @@
         final long requiredInstalledVersionCode;
         final boolean forceQueryableOverride;
         final int mDataLoaderType;
+        final int mSessionId;
 
         InstallParams(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer,
                 int installFlags, InstallSource installSource, String volumeUuid,
@@ -14283,6 +14285,7 @@
             this.requiredInstalledVersionCode = requiredInstalledVersionCode;
             this.forceQueryableOverride = false;
             this.mDataLoaderType = dataLoaderType;
+            this.mSessionId = -1;
         }
 
         InstallParams(ActiveInstallSession activeInstallSession) {
@@ -14318,6 +14321,7 @@
             forceQueryableOverride = sessionParams.forceQueryableOverride;
             mDataLoaderType = (sessionParams.dataLoaderParams != null)
                     ? sessionParams.dataLoaderParams.getType() : DataLoaderType.NONE;
+            mSessionId = activeInstallSession.getSessionId();
         }
 
         @Override
@@ -14549,13 +14553,9 @@
                             PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN,
                             enableRollbackToken);
                     enableRollbackIntent.putExtra(
-                            PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALL_FLAGS,
-                            installFlags);
-                    enableRollbackIntent.putExtra(
-                            PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_USER,
-                            getRollbackUser().getIdentifier());
-                    enableRollbackIntent.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)),
-                            PACKAGE_MIME_TYPE);
+                            PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_SESSION_ID,
+                            mSessionId);
+                    enableRollbackIntent.setType(PACKAGE_MIME_TYPE);
                     enableRollbackIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
 
                     // Allow the broadcast to be sent before boot complete.
@@ -14581,6 +14581,7 @@
                                     final Message msg = mHandler.obtainMessage(
                                             ENABLE_ROLLBACK_TIMEOUT);
                                     msg.arg1 = enableRollbackToken;
+                                    msg.arg2 = mSessionId;
                                     mHandler.sendMessageDelayed(msg, rollbackTimeout);
                                 }
                             }, null, 0, null, null);
@@ -24590,6 +24591,7 @@
         private final String mPackageName;
         private final File mStagedDir;
         private final IPackageInstallObserver2 mObserver;
+        private final int mSessionId;
         private final PackageInstaller.SessionParams mSessionParams;
         private final int mInstallerUid;
         @NonNull private final InstallSource mInstallSource;
@@ -24597,11 +24599,12 @@
         private final SigningDetails mSigningDetails;
 
         ActiveInstallSession(String packageName, File stagedDir, IPackageInstallObserver2 observer,
-                PackageInstaller.SessionParams sessionParams, int installerUid,
+                int sessionId, PackageInstaller.SessionParams sessionParams, int installerUid,
                 InstallSource installSource, UserHandle user, SigningDetails signingDetails) {
             mPackageName = packageName;
             mStagedDir = stagedDir;
             mObserver = observer;
+            mSessionId = sessionId;
             mSessionParams = sessionParams;
             mInstallerUid = installerUid;
             mInstallSource = Preconditions.checkNotNull(installSource);
@@ -24621,6 +24624,10 @@
             return mObserver;
         }
 
+        public int getSessionId() {
+            return mSessionId;
+        }
+
         public PackageInstaller.SessionParams getSessionParams() {
             return mSessionParams;
         }
diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
index 4ab1f396..d3f668c 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -61,7 +61,6 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
-import java.util.Objects;
 import java.util.Set;
 
 
@@ -110,12 +109,9 @@
             return null;
         }
 
-        PackageInfo info = PackageInfoWithoutStateUtils.generateWithoutComponents(pkg, gids, flags,
-                firstInstallTime, lastUpdateTime, grantedPermissions, state, userId, apexInfo,
-                applicationInfo);
-        if (info == null) {
-            return null;
-        }
+        PackageInfo info = PackageInfoWithoutStateUtils.generateWithoutComponentsUnchecked(pkg,
+                gids, flags, firstInstallTime, lastUpdateTime, grantedPermissions, state, userId,
+                apexInfo, applicationInfo);
 
         info.isStub = pkg.isStub();
         info.coreApp = pkg.isCoreApp();
@@ -220,11 +216,8 @@
             return null;
         }
 
-        ApplicationInfo info = PackageInfoWithoutStateUtils.generateApplicationInfo(pkg, flags,
-                state, userId);
-        if (info == null) {
-            return null;
-        }
+        ApplicationInfo info = PackageInfoWithoutStateUtils.generateApplicationInfoUnchecked(pkg,
+                flags, state, userId);
 
         if (pkgSetting != null) {
             // TODO(b/135203078): Remove PackageParser1/toAppInfoWithoutState and clean all this up
@@ -267,12 +260,13 @@
         if (applicationInfo == null) {
             applicationInfo = generateApplicationInfo(pkg, flags, state, userId, pkgSetting);
         }
-        ActivityInfo info = PackageInfoWithoutStateUtils.generateActivityInfo(pkg, a, flags, state,
-                applicationInfo, userId);
-        if (info == null) {
+
+        if (applicationInfo == null) {
             return null;
         }
 
+        ActivityInfo info =
+                PackageInfoWithoutStateUtils.generateActivityInfoUnchecked(a, applicationInfo);
         assignSharedFieldsForComponentInfo(info, a, pkgSetting);
         return info;
     }
@@ -302,12 +296,12 @@
         if (applicationInfo == null) {
             applicationInfo = generateApplicationInfo(pkg, flags, state, userId, pkgSetting);
         }
-        ServiceInfo info = PackageInfoWithoutStateUtils.generateServiceInfo(pkg, s, flags, state,
-                applicationInfo, userId);
-        if (info == null) {
+        if (applicationInfo == null) {
             return null;
         }
 
+        ServiceInfo info =
+                PackageInfoWithoutStateUtils.generateServiceInfoUnchecked(s, applicationInfo);
         assignSharedFieldsForComponentInfo(info, s, pkgSetting);
         return info;
     }
@@ -321,21 +315,20 @@
             @NonNull ApplicationInfo applicationInfo, int userId,
             @Nullable PackageSetting pkgSetting) {
         if (p == null) return null;
+        if (!checkUseInstalledOrHidden(pkg, pkgSetting, state, flags)) {
+            return null;
+        }
         if (applicationInfo == null || !pkg.getPackageName().equals(applicationInfo.packageName)) {
             Slog.wtf(TAG, "AppInfo's package name is different. Expected=" + pkg.getPackageName()
                     + " actual=" + (applicationInfo == null ? "(null AppInfo)"
                     : applicationInfo.packageName));
             applicationInfo = generateApplicationInfo(pkg, flags, state, userId, pkgSetting);
         }
-        if (!checkUseInstalledOrHidden(pkg, pkgSetting, state, flags)) {
+        if (applicationInfo == null) {
             return null;
         }
-        ProviderInfo info = PackageInfoWithoutStateUtils.generateProviderInfo(pkg, p, flags, state,
-                applicationInfo, userId);
-        if (info == null) {
-            return null;
-        }
-
+        ProviderInfo info = PackageInfoWithoutStateUtils.generateProviderInfoUnchecked(p, flags,
+                applicationInfo);
         assignSharedFieldsForComponentInfo(info, p, pkgSetting);
         return info;
     }
diff --git a/services/core/java/com/android/server/rollback/Rollback.java b/services/core/java/com/android/server/rollback/Rollback.java
index 7b96777..885f561 100644
--- a/services/core/java/com/android/server/rollback/Rollback.java
+++ b/services/core/java/com/android/server/rollback/Rollback.java
@@ -159,13 +159,6 @@
     @Nullable public final String mInstallerPackageName;
 
     /**
-     * This array holds all of the rollback tokens associated with package sessions included in
-     * this rollback.
-     */
-    @GuardedBy("mLock")
-    private final IntArray mTokens = new IntArray();
-
-    /**
      * Session ids for all packages in the install. For multi-package sessions, this is the list
      * of child session ids. For normal sessions, this list is a single element with the normal
      * session id.
@@ -769,26 +762,6 @@
     }
 
     /**
-     * Adds a rollback token to be associated with this rollback. This may be used to
-     * identify which rollback should be removed in case {@link PackageManager} sends an
-     * {@link Intent#ACTION_CANCEL_ENABLE_ROLLBACK} intent.
-     */
-    void addToken(int token) {
-        synchronized (mLock) {
-            mTokens.add(token);
-        }
-    }
-
-    /**
-     * Returns true if this rollback is associated with the provided {@code token}.
-     */
-    boolean hasToken(int token) {
-        synchronized (mLock) {
-            return mTokens.indexOf(token) != -1;
-        }
-    }
-
-    /**
      * Returns true if this rollback contains the provided {@code packageSessionId}.
      */
     boolean containsSessionId(int packageSessionId) {
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index f9981d0..42fada1 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -20,7 +20,6 @@
 import android.annotation.AnyThread;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UserIdInt;
 import android.annotation.WorkerThread;
 import android.app.AppOpsManager;
 import android.content.BroadcastReceiver;
@@ -201,18 +200,13 @@
                 if (Intent.ACTION_PACKAGE_ENABLE_ROLLBACK.equals(intent.getAction())) {
                     int token = intent.getIntExtra(
                             PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN, -1);
-                    int installFlags = intent.getIntExtra(
-                            PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALL_FLAGS, 0);
-                    int user = intent.getIntExtra(
-                            PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_USER, 0);
-
-                    File newPackageCodePath = new File(intent.getData().getPath());
+                    int sessionId = intent.getIntExtra(
+                            PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_SESSION_ID, -1);
 
                     queueSleepIfNeeded();
 
                     getHandler().post(() -> {
-                        boolean success =
-                                enableRollback(installFlags, newPackageCodePath, user, token);
+                        boolean success = enableRollback(sessionId);
                         int ret = PackageManagerInternal.ENABLE_ROLLBACK_SUCCEEDED;
                         if (!success) {
                             ret = PackageManagerInternal.ENABLE_ROLLBACK_FAILED;
@@ -238,19 +232,16 @@
             @Override
             public void onReceive(Context context, Intent intent) {
                 if (Intent.ACTION_CANCEL_ENABLE_ROLLBACK.equals(intent.getAction())) {
-                    int token = intent.getIntExtra(
-                            PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN, -1);
+                    int sessionId = intent.getIntExtra(
+                            PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_SESSION_ID, -1);
                     if (LOCAL_LOGV) {
-                        Slog.v(TAG, "broadcast=ACTION_CANCEL_ENABLE_ROLLBACK token=" + token);
+                        Slog.v(TAG, "broadcast=ACTION_CANCEL_ENABLE_ROLLBACK id=" + sessionId);
                     }
                     synchronized (mLock) {
-                        for (int i = 0; i < mRollbacks.size(); ++i) {
-                            Rollback rollback = mRollbacks.get(i);
-                            if (rollback.hasToken(token) && rollback.isEnabling()) {
-                                mRollbacks.remove(i);
-                                rollback.delete(mAppDataRollbackHelper);
-                                break;
-                            }
+                        Rollback rollback = getRollbackForSessionLocked(sessionId);
+                        if (rollback != null && rollback.isEnabling()) {
+                            mRollbacks.remove(rollback);
+                            rollback.delete(mAppDataRollbackHelper);
                         }
                     }
                 }
@@ -684,24 +675,6 @@
         return mHandlerThread.getThreadHandler();
     }
 
-    // Returns true if <code>session</code> has installFlags and code path
-    // matching the installFlags and new package code path given to
-    // enableRollback.
-    @WorkerThread
-    private boolean sessionMatchesForEnableRollback(PackageInstaller.SessionInfo session,
-            int installFlags, File newPackageCodePath) {
-        if (session == null || session.resolvedBaseCodePath == null) {
-            return false;
-        }
-
-        File packageCodePath = new File(session.resolvedBaseCodePath).getParentFile();
-        if (newPackageCodePath.equals(packageCodePath) && installFlags == session.installFlags) {
-            return true;
-        }
-
-        return false;
-    }
-
     @AnyThread
     private Context getContextAsUser(UserHandle user) {
         try {
@@ -716,58 +689,26 @@
      * staged for install with rollback enabled. Called before the package has
      * been installed.
      *
-     * @param installFlags information about what is being installed.
-     * @param newPackageCodePath path to the package about to be installed.
-     * @param user the user that owns the install session to enable rollback on.
-     * @param token the distinct rollback token sent by package manager.
+     * @param sessionId the id of the install session
      * @return true if enabling the rollback succeeds, false otherwise.
      */
     @WorkerThread
-    private boolean enableRollback(
-            int installFlags, File newPackageCodePath, @UserIdInt int user, int token) {
+    private boolean enableRollback(int sessionId) {
         if (LOCAL_LOGV) {
-            Slog.v(TAG, "enableRollback user=" + user + " token=" + token
-                    + " path=" + newPackageCodePath.getAbsolutePath());
+            Slog.v(TAG, "enableRollback sessionId=" + sessionId);
         }
 
-        // Find the session id associated with this install.
-        // TODO: It would be nice if package manager or package installer told
-        // us the session directly, rather than have to search for it
-        // ourselves.
-
-        // getAllSessions only returns sessions for the associated user.
-        // Create a context with the right user so we can find the matching
-        // session.
-        final Context context = getContextAsUser(UserHandle.of(user));
-        if (context == null) {
-            Slog.e(TAG, "Unable to create context for install session user.");
+        PackageInstaller installer = mContext.getPackageManager().getPackageInstaller();
+        PackageInstaller.SessionInfo packageSession = installer.getSessionInfo(sessionId);
+        if (packageSession == null) {
+            Slog.e(TAG, "Unable to find session for enabled rollback.");
             return false;
         }
 
-        PackageInstaller.SessionInfo parentSession = null;
-        PackageInstaller.SessionInfo packageSession = null;
-        PackageInstaller installer = context.getPackageManager().getPackageInstaller();
-        for (PackageInstaller.SessionInfo info : installer.getAllSessions()) {
-            if (info.isMultiPackage()) {
-                for (int childId : info.getChildSessionIds()) {
-                    PackageInstaller.SessionInfo child = installer.getSessionInfo(childId);
-                    if (sessionMatchesForEnableRollback(child, installFlags, newPackageCodePath)) {
-                        // TODO: Check we only have one matching session?
-                        parentSession = info;
-                        packageSession = child;
-                        break;
-                    }
-                }
-            } else if (sessionMatchesForEnableRollback(info, installFlags, newPackageCodePath)) {
-                // TODO: Check we only have one matching session?
-                parentSession = info;
-                packageSession = info;
-                break;
-            }
-        }
-
-        if (parentSession == null || packageSession == null) {
-            Slog.e(TAG, "Unable to find session for enabled rollback.");
+        PackageInstaller.SessionInfo parentSession = packageSession.hasParentSessionId()
+                ? installer.getSessionInfo(packageSession.getParentSessionId()) : packageSession;
+        if (parentSession == null) {
+            Slog.e(TAG, "Unable to find parent session for enabled rollback.");
             return false;
         }
 
@@ -804,7 +745,6 @@
                 newRollback = createNewRollbackLocked(parentSession);
             }
         }
-        newRollback.addToken(token);
 
         return enableRollbackForPackageSession(newRollback, packageSession);
     }
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 4916c31..f86aeb2 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -172,6 +172,7 @@
     private static final int MAX_CLIP_REVEAL_TRANSITION_DURATION = 420;
     private static final int THUMBNAIL_APP_TRANSITION_DURATION = 336;
     private static final long APP_TRANSITION_TIMEOUT_MS = 5000;
+    static final int MAX_APP_TRANSITION_DURATION = 3 * 1000; // 3 secs.
 
     private final Context mContext;
     private final WindowManagerService mService;
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index f6cdac5..68975b9 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -205,7 +205,7 @@
             SurfaceControl.ScreenshotGraphicBuffer gb =
                     mService.mDisplayManagerInternal.screenshot(displayId);
             if (gb != null) {
-                mStartLuma = RotationAnimationUtils.getAvgBorderLuma(gb.getGraphicBuffer(),
+                mStartLuma = RotationAnimationUtils.getMedianBorderLuma(gb.getGraphicBuffer(),
                         gb.getColorSpace());
                 try {
                     surface.attachAndQueueBufferWithColorSpace(gb.getGraphicBuffer(),
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index a0a70dc..b12c698 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -29,6 +29,7 @@
 import static android.view.SurfaceControl.Transaction;
 
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static com.android.server.wm.AppTransition.MAX_APP_TRANSITION_DURATION;
 import static com.android.server.wm.IdentifierProto.HASH_CODE;
 import static com.android.server.wm.IdentifierProto.TITLE;
 import static com.android.server.wm.IdentifierProto.USER_ID;
@@ -2172,7 +2173,16 @@
                 displayConfig.uiMode, displayConfig.orientation, frame, displayFrame, insets,
                 surfaceInsets, stableInsets, isVoiceInteraction, inFreeformWindowingMode(), this);
         if (a != null) {
-            if (DEBUG_ANIM) logWithStack(TAG, "Loaded animation " + a + " for " + this);
+            if (a != null) {
+                // Setup the maximum app transition duration to prevent malicious app may set a long
+                // animation duration or infinite repeat counts for the app transition through
+                // ActivityOption#makeCustomAnimation or WindowManager#overridePendingTransition.
+                a.restrictDuration(MAX_APP_TRANSITION_DURATION);
+            }
+            if (DEBUG_ANIM) {
+                logWithStack(TAG, "Loaded animation " + a + " for " + this
+                        + ", duration: " + ((a != null) ? a.getDuration() : 0));
+            }
             final int containingWidth = frame.width();
             final int containingHeight = frame.height();
             a.initialize(containingWidth, containingHeight, width, height);
diff --git a/services/core/java/com/android/server/wm/utils/RotationAnimationUtils.java b/services/core/java/com/android/server/wm/utils/RotationAnimationUtils.java
index 0c09c88..d02f79f 100644
--- a/services/core/java/com/android/server/wm/utils/RotationAnimationUtils.java
+++ b/services/core/java/com/android/server/wm/utils/RotationAnimationUtils.java
@@ -26,6 +26,8 @@
 import android.view.Surface;
 import android.view.SurfaceControl;
 
+import java.util.Arrays;
+
 
 /** Helper functions for the {@link com.android.server.wm.ScreenRotationAnimation} class*/
 public class RotationAnimationUtils {
@@ -35,31 +37,35 @@
      * luminance at the borders of the bitmap
      * @return the average luminance of all the pixels at the borders of the bitmap
      */
-    public static float getAvgBorderLuma(GraphicBuffer graphicBuffer, ColorSpace colorSpace) {
+    public static float getMedianBorderLuma(GraphicBuffer graphicBuffer, ColorSpace colorSpace) {
         Bitmap hwBitmap = Bitmap.wrapHardwareBuffer(graphicBuffer, colorSpace);
         if (hwBitmap == null) {
             return 0;
         }
 
         Bitmap swaBitmap = hwBitmap.copy(Bitmap.Config.ARGB_8888, false);
-        float totalLuma = 0;
         int height = swaBitmap.getHeight();
         int width = swaBitmap.getWidth();
+        float[] borderLumas = new float[2 * width + 2 * height];
         int i;
-        for (i = 0; i < width; i++) {
-            totalLuma += swaBitmap.getColor(i, 0).luminance();
-            totalLuma += swaBitmap.getColor(i, height - 1).luminance();
+        int index = 0;
+        for (i = 0; i < width; i++, index += 2) {
+            borderLumas[index] = swaBitmap.getColor(i, 0).luminance();
+            borderLumas[index + 1] = swaBitmap.getColor(i, height - 1).luminance();
         }
-        for (i = 0; i < height; i++) {
-            totalLuma += swaBitmap.getColor(0, i).luminance();
-            totalLuma += swaBitmap.getColor(width - 1, i).luminance();
+        for (i = 0; i < height; i++, index += 2) {
+            borderLumas[index] = swaBitmap.getColor(0, i).luminance();
+            borderLumas[index + 1] = swaBitmap.getColor(width - 1, i).luminance();
         }
-        return totalLuma / (2 * width + 2 * height);
+        // Oh, is this too simple and inefficient for you?
+        // How about implementing a O(n) solution? https://en.wikipedia.org/wiki/Median_of_medians
+        Arrays.sort(borderLumas);
+        return borderLumas[borderLumas.length / 2];
     }
 
     /**
      * Gets the average border luma by taking a screenshot of the {@param surfaceControl}.
-     * @see #getAvgBorderLuma(GraphicBuffer, ColorSpace)
+     * @see #getMedianBorderLuma(GraphicBuffer, ColorSpace)
      */
     public static float getLumaOfSurfaceControl(Display display, SurfaceControl surfaceControl) {
         if (surfaceControl ==  null) {
@@ -75,7 +81,7 @@
             return 0;
         }
 
-        return RotationAnimationUtils.getAvgBorderLuma(buffer.getGraphicBuffer(),
+        return RotationAnimationUtils.getMedianBorderLuma(buffer.getGraphicBuffer(),
                 buffer.getColorSpace());
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/utils/RotationAnimationUtilsTest.java b/services/tests/wmtests/src/com/android/server/wm/utils/RotationAnimationUtilsTest.java
index 9cda084..e5497a2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/utils/RotationAnimationUtilsTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/utils/RotationAnimationUtilsTest.java
@@ -50,7 +50,7 @@
     public void blackLuma() {
         Bitmap swBitmap = createBitmap(0);
         GraphicBuffer gb = swBitmapToGraphicsBuffer(swBitmap);
-        float borderLuma = RotationAnimationUtils.getAvgBorderLuma(gb, mColorSpace);
+        float borderLuma = RotationAnimationUtils.getMedianBorderLuma(gb, mColorSpace);
         assertEquals(0, borderLuma, 0);
     }
 
@@ -58,7 +58,15 @@
     public void whiteLuma() {
         Bitmap swBitmap = createBitmap(1);
         GraphicBuffer gb = swBitmapToGraphicsBuffer(swBitmap);
-        float borderLuma = RotationAnimationUtils.getAvgBorderLuma(gb, mColorSpace);
+        float borderLuma = RotationAnimationUtils.getMedianBorderLuma(gb, mColorSpace);
+        assertEquals(1, borderLuma, 0);
+    }
+
+    @Test
+    public void unevenBitmapDimens() {
+        Bitmap swBitmap = createBitmap(1, BITMAP_WIDTH + 1, BITMAP_HEIGHT + 1);
+        GraphicBuffer gb = swBitmapToGraphicsBuffer(swBitmap);
+        float borderLuma = RotationAnimationUtils.getMedianBorderLuma(gb, mColorSpace);
         assertEquals(1, borderLuma, 0);
     }
 
@@ -67,7 +75,7 @@
         Bitmap swBitmap = createBitmap(1);
         setBorderLuma(swBitmap, 0);
         GraphicBuffer gb = swBitmapToGraphicsBuffer(swBitmap);
-        float borderLuma = RotationAnimationUtils.getAvgBorderLuma(gb, mColorSpace);
+        float borderLuma = RotationAnimationUtils.getMedianBorderLuma(gb, mColorSpace);
         assertEquals(0, borderLuma, 0);
     }
 
@@ -76,7 +84,7 @@
         Bitmap swBitmap = createBitmap(0);
         setBorderLuma(swBitmap, 1);
         GraphicBuffer gb = swBitmapToGraphicsBuffer(swBitmap);
-        float borderLuma = RotationAnimationUtils.getAvgBorderLuma(gb, mColorSpace);
+        float borderLuma = RotationAnimationUtils.getMedianBorderLuma(gb, mColorSpace);
         assertEquals(1, borderLuma, 0);
     }
 
@@ -123,9 +131,13 @@
     }
 
     private Bitmap createBitmap(float luma) {
-        Bitmap bitmap = Bitmap.createBitmap(BITMAP_WIDTH, BITMAP_HEIGHT, ARGB_8888);
-        for (int i = 0; i < BITMAP_WIDTH; i++) {
-            for (int j = 0; j < BITMAP_HEIGHT; j++) {
+        return createBitmap(luma, BITMAP_WIDTH, BITMAP_HEIGHT);
+    }
+
+    private Bitmap createBitmap(float luma, int width, int height) {
+        Bitmap bitmap = Bitmap.createBitmap(width, height, ARGB_8888);
+        for (int i = 0; i < width; i++) {
+            for (int j = 0; j < height; j++) {
                 bitmap.setPixel(i, j, Color.argb(1, luma, luma, luma));
             }
         }
diff --git a/tools/stats_log_api_gen/Android.bp b/tools/stats_log_api_gen/Android.bp
index d5031d7..843e820 100644
--- a/tools/stats_log_api_gen/Android.bp
+++ b/tools/stats_log_api_gen/Android.bp
@@ -121,7 +121,6 @@
     shared_libs: [
         "liblog",
         "libcutils",
-        "libstatssocket",
     ],
     apex_available: [
         "//apex_available:platform",
@@ -129,5 +128,13 @@
         "com.android.os.statsd",
         "test_com.android.os.statsd",
     ],
+    target: {
+        android: {
+            shared_libs: ["libstatssocket"],
+        },
+        host: {
+            static_libs: ["libstatssocket"],
+        },
+    },
 }
 
diff --git a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
index 4507cc2..d1d1780 100644
--- a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
+++ b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
@@ -722,7 +722,7 @@
         if (mSubscriptionUpdate != null && !mSubscriptionUpdate.validate()) {
             return false;
         }
-        return validateForCommonR1andR2(true);
+        return validateForCommonR1andR2();
     }
 
     /**
@@ -741,17 +741,17 @@
         if (mSubscriptionUpdate == null || !mSubscriptionUpdate.validate()) {
             return false;
         }
-        return validateForCommonR1andR2(false);
+        return validateForCommonR1andR2();
     }
 
-    private boolean validateForCommonR1andR2(boolean isR1) {
+    private boolean validateForCommonR1andR2() {
         // Required: PerProviderSubscription/<X+>/HomeSP
         if (mHomeSp == null || !mHomeSp.validate()) {
             return false;
         }
 
         // Required: PerProviderSubscription/<X+>/Credential
-        if (mCredential == null || !mCredential.validate(isR1)) {
+        if (mCredential == null || !mCredential.validate()) {
             return false;
         }
 
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
index 9c01d36..65e8b3d 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
+++ b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
@@ -1081,11 +1081,10 @@
     /**
      * Validate the configuration data.
      *
-     * @param isR1 {@code true} if the configuration is for R1
      * @return true on success or false on failure
      * @hide
      */
-    public boolean validate(boolean isR1) {
+    public boolean validate() {
         if (TextUtils.isEmpty(mRealm)) {
             Log.d(TAG, "Missing realm");
             return false;
@@ -1098,11 +1097,11 @@
 
         // Verify the credential.
         if (mUserCredential != null) {
-            if (!verifyUserCredential(isR1)) {
+            if (!verifyUserCredential()) {
                 return false;
             }
         } else if (mCertCredential != null) {
-            if (!verifyCertCredential(isR1)) {
+            if (!verifyCertCredential()) {
                 return false;
             }
         } else if (mSimCredential != null) {
@@ -1143,11 +1142,11 @@
 
     /**
      * Verify user credential.
+     * If no CA certificate is provided, then the system uses the CAs in the trust store.
      *
-     * @param isR1 {@code true} if credential is for R1
      * @return true if user credential is valid, false otherwise.
      */
-    private boolean verifyUserCredential(boolean isR1) {
+    private boolean verifyUserCredential() {
         if (mUserCredential == null) {
             Log.d(TAG, "Missing user credential");
             return false;
@@ -1160,24 +1159,17 @@
             return false;
         }
 
-        // CA certificate is required for R1 Passpoint profile.
-        // For R2, it is downloaded using cert URL provided in PPS MO after validation completes.
-        if (isR1 && mCaCertificates == null) {
-            Log.d(TAG, "Missing CA Certificate for user credential");
-            return false;
-        }
-
         return true;
     }
 
     /**
      * Verify certificate credential, which is used for EAP-TLS.  This will verify
      * that the necessary client key and certificates are provided.
+     * If no CA certificate is provided, then the system uses the CAs in the trust store.
      *
-     * @param isR1 {@code true} if credential is for R1
      * @return true if certificate credential is valid, false otherwise.
      */
-    private boolean verifyCertCredential(boolean isR1) {
+    private boolean verifyCertCredential() {
         if (mCertCredential == null) {
             Log.d(TAG, "Missing certificate credential");
             return false;
@@ -1191,13 +1183,6 @@
             return false;
         }
 
-        // Verify required key and certificates for certificate credential.
-        // CA certificate is required for R1 Passpoint profile.
-        // For R2, it is downloaded using cert URL provided in PPS MO after validation completes.
-        if (isR1 && mCaCertificates == null) {
-            Log.d(TAG, "Missing CA Certificate for certificate credential");
-            return false;
-        }
         if (mClientPrivateKey == null) {
             Log.d(TAG, "Missing client private key for certificate credential");
             return false;
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
index 0a3e989d..c682582 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
@@ -158,7 +158,7 @@
     }
 
     /**
-     * Verify parcel read/write for an user credential.
+     * Verify parcel read/write for a user credential.
      *
      * @throws Exception
      */
@@ -176,14 +176,14 @@
         Credential cred = createCredentialWithUserCredential();
 
         // For R1 validation
-        assertTrue(cred.validate(true));
+        assertTrue(cred.validate());
 
         // For R2 validation
-        assertTrue(cred.validate(false));
+        assertTrue(cred.validate());
     }
 
     /**
-     * Verify that an user credential without CA Certificate is invalid.
+     * Verify that a user credential without CA Certificate is valid.
      *
      * @throws Exception
      */
@@ -192,15 +192,12 @@
         Credential cred = createCredentialWithUserCredential();
         cred.setCaCertificate(null);
 
-        // For R1 validation
-        assertFalse(cred.validate(true));
-
-        // For R2 validation
-        assertTrue(cred.validate(false));
+        // Accept a configuration with no CA certificate, the system will use the default cert store
+        assertTrue(cred.validate());
     }
 
     /**
-     * Verify that an user credential with EAP type other than EAP-TTLS is invalid.
+     * Verify that a user credential with EAP type other than EAP-TTLS is invalid.
      *
      * @throws Exception
      */
@@ -210,15 +207,15 @@
         cred.getUserCredential().setEapType(EAPConstants.EAP_TLS);
 
         // For R1 validation
-        assertFalse(cred.validate(true));
+        assertFalse(cred.validate());
 
         // For R2 validation
-        assertFalse(cred.validate(false));
+        assertFalse(cred.validate());
     }
 
 
     /**
-     * Verify that an user credential without realm is invalid.
+     * Verify that a user credential without realm is invalid.
      *
      * @throws Exception
      */
@@ -228,14 +225,14 @@
         cred.setRealm(null);
 
         // For R1 validation
-        assertFalse(cred.validate(true));
+        assertFalse(cred.validate());
 
         // For R2 validation
-        assertFalse(cred.validate(false));
+        assertFalse(cred.validate());
     }
 
     /**
-     * Verify that an user credential without username is invalid.
+     * Verify that a user credential without username is invalid.
      *
      * @throws Exception
      */
@@ -245,14 +242,14 @@
         cred.getUserCredential().setUsername(null);
 
         // For R1 validation
-        assertFalse(cred.validate(true));
+        assertFalse(cred.validate());
 
         // For R2 validation
-        assertFalse(cred.validate(false));
+        assertFalse(cred.validate());
     }
 
     /**
-     * Verify that an user credential without password is invalid.
+     * Verify that a user credential without password is invalid.
      *
      * @throws Exception
      */
@@ -262,14 +259,14 @@
         cred.getUserCredential().setPassword(null);
 
         // For R1 validation
-        assertFalse(cred.validate(true));
+        assertFalse(cred.validate());
 
         // For R2 validation
-        assertFalse(cred.validate(false));
+        assertFalse(cred.validate());
     }
 
     /**
-     * Verify that an user credential without auth methoh (non-EAP inner method) is invalid.
+     * Verify that a user credential without auth methoh (non-EAP inner method) is invalid.
      *
      * @throws Exception
      */
@@ -279,10 +276,10 @@
         cred.getUserCredential().setNonEapInnerMethod(null);
 
         // For R1 validation
-        assertFalse(cred.validate(true));
+        assertFalse(cred.validate());
 
         // For R2 validation
-        assertFalse(cred.validate(false));
+        assertFalse(cred.validate());
     }
 
     /**
@@ -297,10 +294,10 @@
         Credential cred = createCredentialWithCertificateCredential();
 
         // For R1 validation
-        assertTrue(cred.validate(true));
+        assertTrue(cred.validate());
 
         // For R2 validation
-        assertTrue(cred.validate(true));
+        assertTrue(cred.validate());
     }
 
     /**
@@ -313,11 +310,8 @@
         Credential cred = createCredentialWithCertificateCredential();
         cred.setCaCertificate(null);
 
-        // For R1 validation
-        assertFalse(cred.validate(true));
-
-        // For R2 validation
-        assertTrue(cred.validate(false));
+        // Accept a configuration with no CA certificate, the system will use the default cert store
+        assertTrue(cred.validate());
     }
 
     /**
@@ -331,10 +325,10 @@
         cred.setClientCertificateChain(null);
 
         // For R1 validation
-        assertFalse(cred.validate(true));
+        assertFalse(cred.validate());
 
         // For R2 validation
-        assertFalse(cred.validate(false));
+        assertFalse(cred.validate());
     }
 
     /**
@@ -348,10 +342,10 @@
         cred.setClientPrivateKey(null);
 
         // For R1 validation
-        assertFalse(cred.validate(true));
+        assertFalse(cred.validate());
 
         // For R2 validation
-        assertFalse(cred.validate(false));
+        assertFalse(cred.validate());
     }
 
     /**
@@ -366,10 +360,10 @@
         cred.getCertCredential().setCertSha256Fingerprint(new byte[32]);
 
         // For R1 validation
-        assertFalse(cred.validate(true));
+        assertFalse(cred.validate());
 
         // For R2 validation
-        assertFalse(cred.validate(false));
+        assertFalse(cred.validate());
     }
 
     /**
@@ -382,10 +376,10 @@
         Credential cred = createCredentialWithSimCredential();
 
         // For R1 validation
-        assertTrue(cred.validate(true));
+        assertTrue(cred.validate());
 
         // For R2 validation
-        assertTrue(cred.validate(false));
+        assertTrue(cred.validate());
     }
 
     /**
@@ -399,10 +393,10 @@
         cred.getSimCredential().setEapType(EAPConstants.EAP_AKA);
 
         // For R1 validation
-        assertTrue(cred.validate(true));
+        assertTrue(cred.validate());
 
         // For R2 validation
-        assertTrue(cred.validate(false));
+        assertTrue(cred.validate());
     }
 
     /**
@@ -416,10 +410,10 @@
         cred.getSimCredential().setEapType(EAPConstants.EAP_AKA_PRIME);
 
         // For R1 validation
-        assertTrue(cred.validate(true));
+        assertTrue(cred.validate());
 
         // For R2 validation
-        assertTrue(cred.validate(false));
+        assertTrue(cred.validate());
     }
 
     /**
@@ -433,10 +427,10 @@
         cred.getSimCredential().setImsi(null);
 
         // For R1 validation
-        assertFalse(cred.validate(true));
+        assertFalse(cred.validate());
 
         // For R2 validation
-        assertFalse(cred.validate(false));
+        assertFalse(cred.validate());
     }
 
     /**
@@ -450,10 +444,10 @@
         cred.getSimCredential().setImsi("dummy");
 
         // For R1 validation
-        assertFalse(cred.validate(true));
+        assertFalse(cred.validate());
 
         // For R2 validation
-        assertFalse(cred.validate(false));
+        assertFalse(cred.validate());
     }
 
     /**
@@ -467,14 +461,14 @@
         cred.getSimCredential().setEapType(EAPConstants.EAP_TLS);
 
         // For R1 validation
-        assertFalse(cred.validate(true));
+        assertFalse(cred.validate());
 
         // For R2 validation
-        assertFalse(cred.validate(false));
+        assertFalse(cred.validate());
     }
 
     /**
-     * Verify that a credential contained both an user and a SIM credential is invalid.
+     * Verify that a credential contained both a user and a SIM credential is invalid.
      *
      * @throws Exception
      */
@@ -488,10 +482,10 @@
         cred.setSimCredential(simCredential);
 
         // For R1 validation
-        assertFalse(cred.validate(true));
+        assertFalse(cred.validate());
 
         // For R2 validation
-        assertFalse(cred.validate(false));
+        assertFalse(cred.validate());
     }
 
     /**