Merge branch 'q' of https://github.com/BlissRoms/platform_frameworks_base into pixel

Change-Id: Iee47bdd51304f04a359ed69d0ad166868e491c89
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index a15caa0..44842c6 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -2082,6 +2082,7 @@
 
         /**
          * Get the value set in {@link SessionParams#setOriginatingUri(Uri)}.
+         * Note: This value will only be non-null for the owner of the session.
          */
         public @Nullable Uri getOriginatingUri() {
             return originatingUri;
@@ -2096,6 +2097,7 @@
 
         /**
          * Get the value set in {@link SessionParams#setReferrerUri(Uri)}
+         * Note: This value will only be non-null for the owner of the session.
          */
         public @Nullable Uri getReferrerUri() {
             return referrerUri;
diff --git a/core/res/res/values/bliss_config.xml b/core/res/res/values/bliss_config.xml
index 71d8f69..0ad0ad9 100644
--- a/core/res/res/values/bliss_config.xml
+++ b/core/res/res/values/bliss_config.xml
@@ -176,4 +176,7 @@
     <!-- Default fod pressed icon -->
     <integer name="config_pressed_fod_icon">0</integer>
 
+    <!-- Whether device uses linear screen brightness slider -->
+    <bool name="config_linearBrightnessSlider">false</bool>
+
 </resources>
diff --git a/core/res/res/values/bliss_symbols.xml b/core/res/res/values/bliss_symbols.xml
index a6befd1..6e4cbc8 100644
--- a/core/res/res/values/bliss_symbols.xml
+++ b/core/res/res/values/bliss_symbols.xml
@@ -241,4 +241,6 @@
     <!-- Default fod pressed icon -->
     <java-symbol type="integer" name="config_pressed_fod_icon" />
 
+    <!-- Whether device uses linear screen brightness slider -->
+    <java-symbol type="bool" name="config_linearBrightnessSlider" />
 </resources>
diff --git a/core/tests/bugreports/src/android/server/bugreports/BugreportManagerTest.java b/core/tests/bugreports/src/android/server/bugreports/BugreportManagerTest.java
index c72707db..1533377 100644
--- a/core/tests/bugreports/src/android/server/bugreports/BugreportManagerTest.java
+++ b/core/tests/bugreports/src/android/server/bugreports/BugreportManagerTest.java
@@ -58,6 +58,8 @@
     private Handler mHandler;
     private Executor mExecutor;
     private BugreportManager mBrm;
+    private File mBugreportFile;
+    private File mScreenshotFile;
     private ParcelFileDescriptor mBugreportFd;
     private ParcelFileDescriptor mScreenshotFd;
 
@@ -73,8 +75,10 @@
         };
 
         mBrm = getBugreportManager();
-        mBugreportFd = parcelFd("bugreport_" + name.getMethodName(), ".zip");
-        mScreenshotFd = parcelFd("screenshot_" + name.getMethodName(), ".png");
+        mBugreportFile = createTempFile("bugreport_" + name.getMethodName(), ".zip");
+        mScreenshotFile = createTempFile("screenshot_" + name.getMethodName(), ".png");
+        mBugreportFd = parcelFd(mBugreportFile);
+        mScreenshotFd = parcelFd(mScreenshotFile);
 
         getPermissions();
     }
@@ -121,6 +125,21 @@
     }
 
     @Test
+    public void normalFlow_full() throws Exception {
+        BugreportCallbackImpl callback = new BugreportCallbackImpl();
+        mBrm.startBugreport(mBugreportFd, mScreenshotFd, full(), mExecutor, callback);
+
+        waitTillDoneOrTimeout(callback);
+        assertThat(callback.isDone()).isTrue();
+        assertThat(callback.getErrorCode()).isEqualTo(
+                BugreportCallback.BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
+        // bugreport and screenshot files should be empty when user consent timed out.
+        assertThat(mBugreportFile.length()).isEqualTo(0);
+        assertThat(mScreenshotFile.length()).isEqualTo(0);
+        assertFdsAreClosed(mBugreportFd, mScreenshotFd);
+    }
+
+    @Test
     public void simultaneousBugreportsNotAllowed() throws Exception {
         // Start bugreport #1
         BugreportCallbackImpl callback = new BugreportCallbackImpl();
@@ -129,9 +148,10 @@
         // Before #1 is done, try to start #2.
         assertThat(callback.isDone()).isFalse();
         BugreportCallbackImpl callback2 = new BugreportCallbackImpl();
-        ParcelFileDescriptor bugreportFd2 = parcelFd("bugreport_2_" + name.getMethodName(), ".zip");
-        ParcelFileDescriptor screenshotFd2 =
-                parcelFd("screenshot_2_" + name.getMethodName(), ".png");
+        File bugreportFile2 = createTempFile("bugreport_2_" + name.getMethodName(), ".zip");
+        File screenshotFile2 = createTempFile("screenshot_2_" + name.getMethodName(), ".png");
+        ParcelFileDescriptor bugreportFd2 = parcelFd(bugreportFile2);
+        ParcelFileDescriptor screenshotFd2 = parcelFd(screenshotFile2);
         mBrm.startBugreport(bugreportFd2, screenshotFd2, wifi(), mExecutor, callback2);
         Thread.sleep(500 /* .5s */);
 
@@ -271,12 +291,16 @@
         return bm;
     }
 
-    private static ParcelFileDescriptor parcelFd(String prefix, String extension) throws Exception {
-        File f = File.createTempFile(prefix, extension);
+    private static File createTempFile(String prefix, String extension) throws Exception {
+        final File f = File.createTempFile(prefix, extension);
         f.setReadable(true, true);
         f.setWritable(true, true);
+        f.deleteOnExit();
+        return f;
+    }
 
-        return ParcelFileDescriptor.open(f,
+    private static ParcelFileDescriptor parcelFd(File file) throws Exception {
+        return ParcelFileDescriptor.open(file,
                 ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_APPEND);
     }
 
@@ -342,4 +366,13 @@
     private static BugreportParams interactive() {
         return new BugreportParams(BugreportParams.BUGREPORT_MODE_INTERACTIVE);
     }
+
+    /*
+     * Returns a {@link BugreportParams} for full bugreport that includes a screenshot.
+     *
+     * <p> This can take on the order of minutes to finish
+     */
+    private static BugreportParams full() {
+        return new BugreportParams(BugreportParams.BUGREPORT_MODE_FULL);
+    }
 }
diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
index 325eb17..a6f3006 100644
--- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
+++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
@@ -18,7 +18,6 @@
 
 import android.app.Notification;
 import android.app.NotificationManager;
-import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -392,13 +391,9 @@
             mNiNotificationBuilder.setDefaults(0);
         }
 
-        // if not to popup dialog immediately, pending intent will open the dialog
-        Intent intent = !mPopupImmediately ? getDlgIntent(notif) : new Intent();
-        PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, intent, 0);
         mNiNotificationBuilder.setTicker(getNotifTicker(notif, mContext))
                 .setContentTitle(title)
-                .setContentText(message)
-                .setContentIntent(pi);
+                .setContentText(message);
 
         notificationManager.notifyAsUser(null, notif.notificationId, mNiNotificationBuilder.build(),
                 UserHandle.ALL);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index 1b6acc1..511367a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -226,7 +226,7 @@
 
     @Nullable
     private TouchAnimator createFooterAnimator() {
-        if (isQsSettingsEnabled()) {
+        if (isSettingsDisabled() == 2) {
             return new TouchAnimator.Builder()
                     .addFloat(mActionsContainer, "alpha", 1, 1) // contains mRunningServicesButton
                     .addFloat(mEditContainer, "alpha", 0, 1)
@@ -352,15 +352,25 @@
     private void updateClickabilities() {
         mMultiUserSwitch.setClickable(mMultiUserSwitch.getVisibility() == View.VISIBLE);
         mEdit.setClickable(mEdit.getVisibility() == View.VISIBLE);
-        mSettingsButton.setClickable(mSettingsButton.getVisibility() == View.VISIBLE);
+        if (isSettingsDisabled() == 0) {
+            mSettingsButton.setClickable(false);
+        } else if (isSettingsDisabled() == 1) { 
+            if (mExpanded) {
+                mSettingsButton.setClickable(true);
+            } else {
+                mSettingsButton.setClickable(false);
+            }
+        } else if (isSettingsDisabled() == 2) {
+            mSettingsButton.setClickable(true);
+        }
     }
 
     private void updateVisibilities() {
         mSettingsContainer.findViewById(R.id.tuner_icon).setVisibility(
                 TunerService.isTunerEnabled(mContext) ? View.VISIBLE : View.INVISIBLE);
         final boolean isDemo = UserManager.isDeviceInDemoMode(mContext);
-        mSettingsContainer.setVisibility(isSettingsDisabled() || mQsDisabled ? View.GONE : View.VISIBLE);
-        mSettingsButton.setVisibility(isSettingsDisabled() ? View.GONE : (isDemo || !mExpanded ? View.VISIBLE : View.VISIBLE));
+        mSettingsContainer.setVisibility(isSettingsDisabled() == 0 || mQsDisabled ? View.GONE : View.VISIBLE);
+        mSettingsButton.setVisibility(isSettingsDisabled() == 0 ? View.GONE : (isDemo || !mExpanded ? (isSettingsDisabled() == 1 ? View.GONE: View.VISIBLE) : View.VISIBLE));
         mRunningServicesButton.setVisibility(isServicesEnabled() ? (isDemo || !mExpanded ? View.INVISIBLE : View.VISIBLE) : View.GONE);
         mMultiUserSwitch.setVisibility(isUserEnabled() ? (showUserSwitcher() ? View.VISIBLE : View.INVISIBLE) : View.GONE);
         mEditContainer.setVisibility(isDemo || !mExpanded ? View.INVISIBLE : View.VISIBLE);
@@ -391,9 +401,9 @@
         }
     }
 
-    public boolean isSettingsDisabled() {
+    public int isSettingsDisabled() {
         return Settings.System.getInt(mContext.getContentResolver(),
-            Settings.System.QS_FOOTER_SHOW_SETTINGS, 1) == 0;
+            Settings.System.QS_FOOTER_SHOW_SETTINGS, 1);
     }
 
     public boolean isQsSettingsEnabled() {
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
index 52a6c4e..d2f8196 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
@@ -543,7 +543,7 @@
                         this,
                         REQUEST_CODE,
                         viewIntent,
-                        Intent.FLAG_GRANT_READ_URI_PERMISSION))
+                        PendingIntent.FLAG_IMMUTABLE))
                 .addAction(shareAction)
                 .addAction(deleteAction)
                 .setAutoCancel(true);
diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
index fc1f655..cf24044 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
@@ -73,6 +73,7 @@
     private final ImageView mIcon;
     private final ToggleSlider mControl;
     private final boolean mAutomaticAvailable;
+    private final boolean mLinearBrightnessSlider;
     private final DisplayManager mDisplayManager;
     private final CurrentUserTracker mUserTracker;
     private final IVrManager mVrManager;
@@ -291,6 +292,8 @@
 
         mAutomaticAvailable = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_automatic_brightness_available);
+        mLinearBrightnessSlider = context.getResources().getBoolean(
+                com.android.internal.R.bool.config_linearBrightnessSlider);
         mDisplayManager = context.getSystemService(DisplayManager.class);
         mVrManager = IVrManager.Stub.asInterface(ServiceManager.getService(
                 Context.VR_SERVICE));
@@ -398,7 +401,12 @@
             setting = Settings.System.SCREEN_BRIGHTNESS;
         }
 
-        final int val = convertGammaToLinear(value, min, max);
+        final int val;
+        if (!mLinearBrightnessSlider) {
+            val = convertGammaToLinear(value, min, max);
+        } else {
+            val = (value < min) ? min : value;
+        }
 
         if (stopTracking) {
             MetricsLogger.action(mContext, metric, val);
@@ -466,16 +474,22 @@
             min = mMinimumBacklight;
             max = mMaximumBacklight;
         }
-        if (val == convertGammaToLinear(mControl.getValue(), min, max)) {
-            // If we have more resolution on the slider than we do in the actual setting, then
-            // multiple slider positions will map to the same setting value. Thus, if we see a
-            // setting value here that maps to the current slider position, we don't bother to
-            // calculate the new slider position since it may differ and look like a brightness
-            // change to the user even though it isn't one.
-            return;
+        if (!mLinearBrightnessSlider) {
+            if (val == convertGammaToLinear(mControl.getValue(), min, max)) {
+                // If we have more resolution on the slider than we do in the actual setting, then
+                // multiple slider positions will map to the same setting value. Thus, if we see a
+                // setting value here that maps to the current slider position, we don't bother to
+                // calculate the new slider position since it may differ and look like a brightness
+                // change to the user even though it isn't one.
+                return;
+            }
+            final int sliderVal = convertLinearToGamma(val, min, max);
+            mControl.setMax(GAMMA_SPACE_MAX);
+            animateSliderTo(sliderVal);
+        } else {
+            mControl.setMax(max - min);
+            animateSliderTo(val - min);
         }
-        final int sliderVal = convertLinearToGamma(val, min, max);
-        animateSliderTo(sliderVal);
     }
 
     private void animateSliderTo(int target) {
diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/LeakReporter.java b/packages/SystemUI/src/com/android/systemui/util/leak/LeakReporter.java
index b25df5f..5e72808 100644
--- a/packages/SystemUI/src/com/android/systemui/util/leak/LeakReporter.java
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/LeakReporter.java
@@ -104,9 +104,13 @@
                     .setContentText(String.format(
                             "SystemUI has detected %d leaked objects. Tap to send", garbageCount))
                     .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
-                    .setContentIntent(PendingIntent.getActivityAsUser(mContext, 0,
+                    .setContentIntent(PendingIntent.getActivityAsUser(
+                            mContext,
+                            0,
                             getIntent(hprofFile, dumpFile),
-                            PendingIntent.FLAG_UPDATE_CURRENT, null, UserHandle.CURRENT));
+                            PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE,
+                            null,
+                            UserHandle.CURRENT));
             notiMan.notify(TAG, 0, builder.build());
         } catch (IOException e) {
             Log.e(TAG, "Couldn't dump heap for leak", e);
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 067becb..a434733 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -316,12 +316,14 @@
                             .toString());
             long identity = Binder.clearCallingIdentity();
             try {
-                return PendingIntent.getActivity(getContext(),
+                return PendingIntent.getActivityAsUser(getContext(),
                         0 /* request code */,
                         NotificationAccessConfirmationActivityContract.launcherIntent(
                                 userId, component, packageTitle),
                         PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT
-                                | PendingIntent.FLAG_CANCEL_CURRENT);
+                                | PendingIntent.FLAG_CANCEL_CURRENT,
+                        null /* options */,
+                        new UserHandle(userId));
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index f979661..27d66f8 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3219,6 +3219,10 @@
     @Override
     public boolean setProcessMemoryTrimLevel(String process, int userId, int level)
             throws RemoteException {
+        if (!isCallerShell()) {
+            EventLog.writeEvent(0x534e4554, 160390416, Binder.getCallingUid(), "");
+            throw new SecurityException("Only shell can call it");
+        }
         synchronized (this) {
             final ProcessRecord app = findProcessLocked(process, userId, "setProcessMemoryTrimLevel");
             if (app == null) {
diff --git a/services/core/java/com/android/server/biometrics/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/AuthenticationClient.java
index 4a9ccde..13a2c19 100644
--- a/services/core/java/com/android/server/biometrics/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/AuthenticationClient.java
@@ -217,6 +217,9 @@
                     }
                 }
                 result = lockoutMode != LOCKOUT_NONE; // in a lockout mode
+                if(result) { // lockde out
+                    mAlreadyDone = true;
+                }
             }
         } catch (RemoteException e) {
             Slog.e(getLogTag(), "Remote exception", e);
diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
index d056763..262ecc4 100644
--- a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
+++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
@@ -967,6 +967,7 @@
             if (!client.onError(getHalDeviceId(), errorCode, 0 /* vendorCode */)) {
                 Slog.w(getTag(), "Cannot send permanent lockout message to client");
             }
+
             return;
         }
         startClient(client, true /* initiatedByClient */);
diff --git a/services/core/java/com/android/server/biometrics/ClientMonitor.java b/services/core/java/com/android/server/biometrics/ClientMonitor.java
index 6631345..f9d89d6 100644
--- a/services/core/java/com/android/server/biometrics/ClientMonitor.java
+++ b/services/core/java/com/android/server/biometrics/ClientMonitor.java
@@ -235,6 +235,10 @@
 
     @Override
     public void binderDied() {
+        if (isAlreadyDone()) {
+            Slog.w(getLogTag(), "Binder died but client is finished, ignoring");
+            return;
+        }
         // If the current client dies we should cancel the current operation.
         Slog.e(getLogTag(), "Binder died, cancelling client");
         stop(false /* initiatedByClient */);
diff --git a/services/core/java/com/android/server/location/GnssVisibilityControl.java b/services/core/java/com/android/server/location/GnssVisibilityControl.java
index dd522b9..0f38473 100644
--- a/services/core/java/com/android/server/location/GnssVisibilityControl.java
+++ b/services/core/java/com/android/server/location/GnssVisibilityControl.java
@@ -21,7 +21,6 @@
 import android.app.AppOpsManager;
 import android.app.Notification;
 import android.app.NotificationManager;
-import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -645,7 +644,6 @@
                 .setTicker(accessibilityServicesText)
                 .setContentTitle(firstLineText)
                 .setContentText(secondLineText)
-                .setContentIntent(PendingIntent.getBroadcast(context, 0, new Intent(), 0))
                 .build();
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 8227e58..ba83762 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -770,26 +770,30 @@
     public SessionInfo getSessionInfo(int sessionId) {
         synchronized (mSessions) {
             final PackageInstallerSession session = mSessions.get(sessionId);
-            return session != null ? session.generateInfo() : null;
+
+            return session != null
+                    ? session.generateInfoForCaller(true /*withIcon*/, Binder.getCallingUid())
+                    : null;
         }
     }
 
     @Override
     public ParceledListSlice<SessionInfo> getStagedSessions() {
-        return mStagingManager.getSessions();
+        return mStagingManager.getSessions(Binder.getCallingUid());
     }
 
     @Override
     public ParceledListSlice<SessionInfo> getAllSessions(int userId) {
+        final int callingUid = Binder.getCallingUid();
         mPermissionManager.enforceCrossUserPermission(
-                Binder.getCallingUid(), userId, true, false, "getAllSessions");
+                callingUid, userId, true, false, "getAllSessions");
 
         final List<SessionInfo> result = new ArrayList<>();
         synchronized (mSessions) {
             for (int i = 0; i < mSessions.size(); i++) {
                 final PackageInstallerSession session = mSessions.valueAt(i);
                 if (session.userId == userId && !session.hasParentSessionId()) {
-                    result.add(session.generateInfo(false));
+                    result.add(session.generateInfoForCaller(false, callingUid));
                 }
             }
         }
@@ -807,7 +811,8 @@
             for (int i = 0; i < mSessions.size(); i++) {
                 final PackageInstallerSession session = mSessions.valueAt(i);
 
-                SessionInfo info = session.generateInfo(false);
+                SessionInfo info =
+                        session.generateInfoForCaller(false /*withIcon*/, Process.SYSTEM_UID);
                 if (Objects.equals(info.getInstallerPackageName(), installerPackageName)
                         && session.userId == userId && !session.hasParentSessionId()) {
                     result.add(info);
@@ -1251,7 +1256,10 @@
             session.markUpdated();
             writeSessionsAsync();
             if (mOkToSendBroadcasts) {
-                mPm.sendSessionUpdatedBroadcast(session.generateInfo(false),
+                // we don't scrub the data here as this is sent only to the installer several
+                // privileged system packages
+                mPm.sendSessionUpdatedBroadcast(
+                        session.generateInfoForCaller(false/*icon*/, Process.SYSTEM_UID),
                         session.userId);
             }
         }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index b661a85..1976ffd 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -457,11 +457,41 @@
                 stagedSessionErrorMessage != null ? stagedSessionErrorMessage : "";
     }
 
-    public SessionInfo generateInfo() {
-        return generateInfo(true);
+    /**
+     * Returns {@code true} if the {@link SessionInfo} object should be produced with potentially
+     * sensitive data scrubbed from its fields.
+     *
+     * @param callingUid the uid of the caller; the recipient of the {@link SessionInfo} that may
+     *                   need to be scrubbed
+     */
+    private boolean shouldScrubData(int callingUid) {
+        return !(callingUid < Process.FIRST_APPLICATION_UID || getInstallerUid() == callingUid);
     }
 
-    public SessionInfo generateInfo(boolean includeIcon) {
+    /**
+     * Generates a {@link SessionInfo} object for the provided uid. This may result in some fields
+     * that may contain sensitive info being filtered.
+     *
+     * @param includeIcon true if the icon should be included in the object
+     * @param callingUid the uid of the caller; the recipient of the {@link SessionInfo} that may
+     *                   need to be scrubbed
+     * @see #shouldScrubData(int)
+     */
+    public SessionInfo generateInfoForCaller(boolean includeIcon, int callingUid) {
+        return generateInfoInternal(includeIcon, shouldScrubData(callingUid));
+    }
+
+    /**
+     * Generates a {@link SessionInfo} object to ensure proper hiding of sensitive fields.
+     *
+     * @param includeIcon true if the icon should be included in the object
+     * @see #generateInfoForCaller(boolean, int)
+     */
+    public SessionInfo generateInfoScrubbed(boolean includeIcon) {
+        return generateInfoInternal(includeIcon, true /*scrubData*/);
+    }
+
+    private SessionInfo generateInfoInternal(boolean includeIcon, boolean scrubData) {
         final SessionInfo info = new SessionInfo();
         synchronized (mLock) {
             info.sessionId = sessionId;
@@ -484,9 +514,13 @@
             info.appLabel = params.appLabel;
 
             info.installLocation = params.installLocation;
-            info.originatingUri = params.originatingUri;
+            if (!scrubData) {
+                info.originatingUri = params.originatingUri;
+            }
             info.originatingUid = params.originatingUid;
-            info.referrerUri = params.referrerUri;
+            if (!scrubData) {
+                info.referrerUri = params.referrerUri;
+            }
             info.grantedRuntimePermissions = params.grantedRuntimePermissions;
             info.whitelistedRestrictedPermissions = params.whitelistedRestrictedPermissions;
             info.installFlags = params.installFlags;
@@ -2190,7 +2224,7 @@
         final boolean isNewInstall = extras == null || !extras.getBoolean(Intent.EXTRA_REPLACING);
         if (success && isNewInstall && mPm.mInstallerService.okToSendBroadcasts()
                 && (params.installFlags & PackageManager.INSTALL_DRY_RUN) == 0) {
-            mPm.sendSessionCommitBroadcast(generateInfo(), userId);
+            mPm.sendSessionCommitBroadcast(generateInfoScrubbed(true /*icon*/), userId);
         }
 
         mCallback.onSessionFinished(this, success);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 8ba32ea..68b6b51 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1143,13 +1143,6 @@
                     int updatedStatus = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
                     boolean needUpdate = false;
 
-                    if (DEBUG_DOMAIN_VERIFICATION) {
-                        Slog.d(TAG,
-                                "Updating IntentFilterVerificationInfo for package " + packageName
-                                + " verificationId:" + verificationId
-                                + " verified=" + verified);
-                    }
-
                     // In a success case, we promote from undefined or ASK to ALWAYS.  This
                     // supports a flow where the app fails validation but then ships an updated
                     // APK that passes, and therefore deserves to be in ALWAYS.
@@ -11774,6 +11767,8 @@
                     ~ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE;
             pkg.applicationInfo.privateFlags &=
                     ~ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE;
+            // clear protected broadcasts
+            pkg.protectedBroadcasts = null;
             // cap permission priorities
             if (pkg.permissionGroups != null && pkg.permissionGroups.size() > 0) {
                 for (int i = pkg.permissionGroups.size() - 1; i >= 0; --i) {
@@ -11782,8 +11777,6 @@
             }
         }
         if ((scanFlags & SCAN_AS_PRIVILEGED) == 0) {
-            // clear protected broadcasts
-            pkg.protectedBroadcasts = null;
             // ignore export request for single user receivers
             if (pkg.receivers != null) {
                 for (int i = pkg.receivers.size() - 1; i >= 0; --i) {
@@ -14689,19 +14682,32 @@
 
             // Verify: if target already has an installer package, it must
             // be signed with the same cert as the caller.
-            if (targetPackageSetting.installerPackageName != null) {
-                PackageSetting setting = mSettings.mPackages.get(
-                        targetPackageSetting.installerPackageName);
-                // If the currently set package isn't valid, then it's always
-                // okay to change it.
-                if (setting != null) {
-                    if (compareSignatures(callerSignature,
-                            setting.signatures.mSigningDetails.signatures)
-                            != PackageManager.SIGNATURE_MATCH) {
-                        throw new SecurityException(
-                                "Caller does not have same cert as old installer package "
-                                + targetPackageSetting.installerPackageName);
-                    }
+            String targetInstallerPackageName =
+                    targetPackageSetting.installerPackageName;
+            PackageSetting targetInstallerPkgSetting = targetInstallerPackageName == null ? null :
+                    mSettings.mPackages.get(targetInstallerPackageName);
+
+            if (targetInstallerPkgSetting != null) {
+                if (compareSignatures(callerSignature,
+                        targetInstallerPkgSetting.signatures.mSigningDetails.signatures)
+                        != PackageManager.SIGNATURE_MATCH) {
+                    throw new SecurityException(
+                            "Caller does not have same cert as old installer package "
+                                    + targetInstallerPackageName);
+                }
+            } else if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES)
+                    != PackageManager.PERMISSION_GRANTED) {
+                // This is probably an attempt to exploit vulnerability b/150857253 of taking
+                // privileged installer permissions when the installer has been uninstalled or
+                // was never set.
+                EventLog.writeEvent(0x534e4554, "150857253", callingUid, "");
+
+                if (getUidTargetSdkVersionLockedLPr(callingUid) > Build.VERSION_CODES.Q) {
+                    throw new SecurityException("Neither user " + callingUid
+                            + " nor current process has " + Manifest.permission.INSTALL_PACKAGES);
+                } else {
+                    // If not targeting >Q, fail silently for backwards compatibility
+                    return;
                 }
             }
 
@@ -18271,16 +18277,18 @@
 
         int count = 0;
         final String packageName = pkg.packageName;
-
         boolean handlesWebUris = false;
-        final boolean alreadyVerified;
+        ArraySet<String> domains = new ArraySet<>();
+        final boolean previouslyVerified;
+        boolean hostSetExpanded = false;
+        boolean needToRunVerify = false;
         synchronized (mPackages) {
             // If this is a new install and we see that we've already run verification for this
             // package, we have nothing to do: it means the state was restored from backup.
-            final IntentFilterVerificationInfo ivi =
+            IntentFilterVerificationInfo ivi =
                     mSettings.getIntentFilterVerificationLPr(packageName);
-            alreadyVerified = (ivi != null);
-            if (!replacing && alreadyVerified) {
+            previouslyVerified = (ivi != null);
+            if (!replacing && previouslyVerified) {
                 if (DEBUG_DOMAIN_VERIFICATION) {
                     Slog.i(TAG, "Package " + packageName + " already verified: status="
                             + ivi.getStatusString());
@@ -18288,77 +18296,107 @@
                 return;
             }
 
+            if (DEBUG_DOMAIN_VERIFICATION) {
+                Slog.i(TAG, "    Previous verified hosts: "
+                        + (ivi == null ? "[none]" : ivi.getDomainsString()));
+            }
+
             // If any filters need to be verified, then all need to be.  In addition, we need to
             // know whether an updating app has any web navigation intent filters, to re-
             // examine handling policy even if not re-verifying.
-            boolean needToVerify = false;
+            final boolean needsVerification = needsNetworkVerificationLPr(packageName);
             for (PackageParser.Activity a : pkg.activities) {
                 for (ActivityIntentInfo filter : a.intents) {
                     if (filter.handlesWebUris(true)) {
                         handlesWebUris = true;
                     }
-                    if (filter.needsVerification() && needsNetworkVerificationLPr(filter)) {
+                    if (needsVerification && filter.needsVerification()) {
                         if (DEBUG_DOMAIN_VERIFICATION) {
-                            Slog.d(TAG,
-                                    "Intent filter needs verification, so processing all filters");
+                            Slog.d(TAG, "autoVerify requested, processing all filters");
                         }
-                        needToVerify = true;
+                        needToRunVerify = true;
                         // It's safe to break out here because filter.needsVerification()
-                        // can only be true if filter.handlesWebUris(true) returns true, so
+                        // can only be true if filter.handlesWebUris(true) returned true, so
                         // we've already noted that.
                         break;
                     }
                 }
             }
 
-            // Note whether this app publishes any web navigation handling support at all,
-            // and whether there are any web-nav filters that fit the profile for running
-            // a verification pass now.
-            if (needToVerify) {
+            // Compare the new set of recognized hosts if the app is either requesting
+            // autoVerify or has previously used autoVerify but no longer does.
+            if (needToRunVerify || previouslyVerified) {
                 final int verificationId = mIntentFilterVerificationToken++;
                 for (PackageParser.Activity a : pkg.activities) {
                     for (ActivityIntentInfo filter : a.intents) {
                         // Run verification against hosts mentioned in any web-nav intent filter,
                         // even if the filter matches non-web schemes as well
-                        if (filter.handlesWebUris(false) && needsNetworkVerificationLPr(filter)) {
+                        if (filter.handlesWebUris(false /*onlyWebSchemes*/)) {
                             if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG,
                                     "Verification needed for IntentFilter:" + filter.toString());
                             mIntentFilterVerifier.addOneIntentFilterVerification(
                                     verifierUid, userId, verificationId, filter, packageName);
+                            domains.addAll(filter.getHostsList());
                             count++;
                         }
                     }
                 }
             }
+
+            if (DEBUG_DOMAIN_VERIFICATION) {
+                Slog.i(TAG, "    Update published hosts: " + domains.toString());
+            }
+
+            // If we've previously verified this same host set (or a subset), we can trust that
+            // a current ALWAYS policy is still applicable.  If this is the case, we're done.
+            // (If we aren't in ALWAYS, we want to reverify to allow for apps that had failing
+            // hosts in their intent filters, then pushed a new apk that removed them and now
+            // passes.)
+            //
+            // Cases:
+            //   + still autoVerify (needToRunVerify):
+            //      - preserve current state if all of: unexpanded, in always
+            //      - otherwise rerun as usual (fall through)
+            //   + no longer autoVerify (alreadyVerified && !needToRunVerify)
+            //      - wipe verification history always
+            //      - preserve current state if all of: unexpanded, in always
+            hostSetExpanded = !previouslyVerified
+                    || (ivi != null && !ivi.getDomains().containsAll(domains));
+            final int currentPolicy =
+                    mSettings.getIntentFilterVerificationStatusLPr(packageName, userId);
+            final boolean keepCurState = !hostSetExpanded
+                    && currentPolicy == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
+
+            if (needToRunVerify && keepCurState) {
+                if (DEBUG_DOMAIN_VERIFICATION) {
+                    Slog.i(TAG, "Host set not expanding + ALWAYS -> no need to reverify");
+                }
+                ivi.setDomains(domains);
+                scheduleWriteSettingsLocked();
+                return;
+            } else if (previouslyVerified && !needToRunVerify) {
+                // Prior autoVerify state but not requesting it now.  Clear autoVerify history,
+                // and preserve the always policy iff the host set is not expanding.
+                clearIntentFilterVerificationsLPw(packageName, userId, !keepCurState);
+                return;
+            }
         }
 
-        if (count > 0) {
-            // count > 0 means that we're running a full verification pass
+        if (needToRunVerify && count > 0) {
+            // app requested autoVerify and has at least one matching intent filter
             if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG, "Starting " + count
                     + " IntentFilter verification" + (count > 1 ? "s" : "")
                     +  " for userId:" + userId);
             mIntentFilterVerifier.startVerifications(userId);
-        } else if (alreadyVerified && handlesWebUris) {
-            // App used autoVerify in the past, no longer does, but still handles web
-            // navigation starts.
-            if (DEBUG_DOMAIN_VERIFICATION) {
-                Slog.d(TAG, "App changed web filters but no longer verifying - resetting policy");
-            }
-            synchronized (mPackages) {
-                clearIntentFilterVerificationsLPw(packageName, userId);
-            }
         } else {
             if (DEBUG_DOMAIN_VERIFICATION) {
-                Slog.d(TAG, "No web filters or no prior verify policy for " + packageName);
+                Slog.d(TAG, "No web filters or no new host policy for " + packageName);
             }
         }
     }
 
     @GuardedBy("mPackages")
-    private boolean needsNetworkVerificationLPr(ActivityIntentInfo filter) {
-        final ComponentName cn  = filter.activity.getComponentName();
-        final String packageName = cn.getPackageName();
-
+    private boolean needsNetworkVerificationLPr(String packageName) {
         IntentFilterVerificationInfo ivi = mSettings.getIntentFilterVerificationLPr(
                 packageName);
         if (ivi == null) {
@@ -19104,7 +19142,7 @@
             if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
                 final SparseBooleanArray changedUsers = new SparseBooleanArray();
                 synchronized (mPackages) {
-                    clearIntentFilterVerificationsLPw(deletedPs.name, UserHandle.USER_ALL);
+                    clearIntentFilterVerificationsLPw(deletedPs.name, UserHandle.USER_ALL, true);
                     clearDefaultBrowserIfNeeded(packageName);
                     mSettings.mKeySetManagerService.removeAppKeySetDataLPw(packageName);
                     removedAppId = mSettings.removePackageLPw(packageName);
@@ -20609,13 +20647,14 @@
         final int packageCount = mPackages.size();
         for (int i = 0; i < packageCount; i++) {
             PackageParser.Package pkg = mPackages.valueAt(i);
-            clearIntentFilterVerificationsLPw(pkg.packageName, userId);
+            clearIntentFilterVerificationsLPw(pkg.packageName, userId, true);
         }
     }
 
     /** This method takes a specific user id as well as UserHandle.USER_ALL. */
     @GuardedBy("mPackages")
-    void clearIntentFilterVerificationsLPw(String packageName, int userId) {
+    void clearIntentFilterVerificationsLPw(String packageName, int userId,
+            boolean alsoResetStatus) {
         if (userId == UserHandle.USER_ALL) {
             if (mSettings.removeIntentFilterVerificationLPw(packageName,
                     sUserManager.getUserIds())) {
@@ -20624,7 +20663,8 @@
                 }
             }
         } else {
-            if (mSettings.removeIntentFilterVerificationLPw(packageName, userId)) {
+            if (mSettings.removeIntentFilterVerificationLPw(packageName, userId,
+                    alsoResetStatus)) {
                 scheduleWritePackageRestrictionsLocked(userId);
             }
         }
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index d449db3..53ff627 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -1243,7 +1243,8 @@
         return result;
     }
 
-    boolean removeIntentFilterVerificationLPw(String packageName, int userId) {
+    boolean removeIntentFilterVerificationLPw(String packageName, int userId,
+            boolean alsoResetStatus) {
         PackageSetting ps = mPackages.get(packageName);
         if (ps == null) {
             if (DEBUG_DOMAIN_VERIFICATION) {
@@ -1251,7 +1252,9 @@
             }
             return false;
         }
-        ps.clearDomainVerificationStatusForUser(userId);
+        if (alsoResetStatus) {
+            ps.clearDomainVerificationStatusForUser(userId);
+        }
         ps.setIntentFilterVerificationInfo(null);
         return true;
     }
@@ -1259,7 +1262,7 @@
     boolean removeIntentFilterVerificationLPw(String packageName, int[] userIds) {
         boolean result = false;
         for (int userId : userIds) {
-            result |= removeIntentFilterVerificationLPw(packageName, userId);
+            result |= removeIntentFilterVerificationLPw(packageName, userId, true);
         }
         return result;
     }
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 895d2c5..dd71331 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -95,11 +95,12 @@
         }
     }
 
-    ParceledListSlice<PackageInstaller.SessionInfo> getSessions() {
+    ParceledListSlice<PackageInstaller.SessionInfo> getSessions(int callingUid) {
         final List<PackageInstaller.SessionInfo> result = new ArrayList<>();
         synchronized (mStagedSessions) {
             for (int i = 0; i < mStagedSessions.size(); i++) {
-                result.add(mStagedSessions.valueAt(i).generateInfo(false));
+                final PackageInstallerSession stagedSession = mStagedSessions.valueAt(i);
+                result.add(stagedSession.generateInfoForCaller(false /*icon*/, callingUid));
             }
         }
         return new ParceledListSlice<>(result);
diff --git a/services/core/java/com/android/server/policy/pocket/PocketLock.java b/services/core/java/com/android/server/policy/pocket/PocketLock.java
index a432d7c..2fa207e 100644
--- a/services/core/java/com/android/server/policy/pocket/PocketLock.java
+++ b/services/core/java/com/android/server/policy/pocket/PocketLock.java
@@ -93,10 +93,12 @@
                         @Override
                         public void run() {
                             mView.setAlpha(0.0f);
+                            mView.setVisibility(View.VISIBLE);
                             addView();
                         }
                     }).start();
                 } else {
+                    mView.setVisibility(View.VISIBLE);
                     mView.setAlpha(1.0f);
                     addView();
                 }
@@ -128,6 +130,7 @@
 
                         @Override
                         public void onAnimationEnd(Animator animator) {
+                            mView.setVisibility(View.GONE);
                             mView.setLayerType(View.LAYER_TYPE_NONE, null);
                             mAnimating = false;
                             removeView();
@@ -142,8 +145,9 @@
                         }
                     }).start();
                 } else {
-                    removeView();
+                    mView.setVisibility(View.GONE);
                     mView.setAlpha(0.0f);
+                    removeView();
                 }
             }
         };