From f315ba91df3829d862371fbab9da584ce0a59bc6 Mon Sep 17 00:00:00 2001 From: Julia Reynolds Date: Fri, 11 Feb 2022 17:08:58 -0500 Subject: [PATCH 1/9] Filter notification APIs by user Specifically getActiveNotifications and getHistoricalNotifications Test: atest NotificationManagerServiceTest Bug: 214999128 Change-Id: I2eba0a592fa33ed25e1ac3919f1b2631e5db4258 Merged-In: I2eba0a592fa33ed25e1ac3919f1b2631e5db4258 (cherry picked from commit 73745b16e89b51dfe4328faa817ba50024382050) Merged-In: I2eba0a592fa33ed25e1ac3919f1b2631e5db4258 --- .../NotificationManagerService.java | 37 ++++++++++++---- .../server/notification/ArchiveTest.java | 42 +++++++++++++++---- .../NotificationManagerServiceTest.java | 35 +++++++++++++++- 3 files changed, 96 insertions(+), 18 deletions(-) diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 211f8d6e3ec78..f1087cc7ab3aa 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -658,7 +658,14 @@ public class NotificationManagerService extends SystemService { return mBuffer.descendingIterator(); } - public StatusBarNotification[] getArray(int count, boolean includeSnoozed) { + public StatusBarNotification[] getArray(UserManager um, int count, boolean includeSnoozed) { + ArrayList currentUsers = new ArrayList<>(); + currentUsers.add(UserHandle.USER_ALL); + Binder.withCleanCallingIdentity(() -> { + for (int user : um.getProfileIds(ActivityManager.getCurrentUser(), false)) { + currentUsers.add(user); + } + }); synchronized (mBufferLock) { if (count == 0) count = mBufferSize; List a = new ArrayList(); @@ -667,8 +674,10 @@ public class NotificationManagerService extends SystemService { while (iter.hasNext() && i < count) { Pair pair = iter.next(); if (pair.second != REASON_SNOOZED || includeSnoozed) { - i++; - a.add(pair.first); + if (currentUsers.contains(pair.first.getUserId())) { + i++; + a.add(pair.first); + } } } return a.toArray(new StatusBarNotification[a.size()]); @@ -4042,22 +4051,32 @@ public class NotificationManagerService extends SystemService { android.Manifest.permission.ACCESS_NOTIFICATIONS, "NotificationManagerService.getActiveNotifications"); - StatusBarNotification[] tmp = null; + ArrayList tmp = new ArrayList<>(); int uid = Binder.getCallingUid(); + ArrayList currentUsers = new ArrayList<>(); + currentUsers.add(UserHandle.USER_ALL); + Binder.withCleanCallingIdentity(() -> { + for (int user : mUm.getProfileIds(ActivityManager.getCurrentUser(), false)) { + currentUsers.add(user); + } + }); + // noteOp will check to make sure the callingPkg matches the uid if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg, callingAttributionTag, null) == AppOpsManager.MODE_ALLOWED) { synchronized (mNotificationLock) { - tmp = new StatusBarNotification[mNotificationList.size()]; final int N = mNotificationList.size(); - for (int i=0; i expected = new ArrayList<>(); @@ -81,13 +92,29 @@ public class ArchiveTest extends UiServiceTestCase { mArchive.record(sbn, REASON_CANCEL); } - List actual = Arrays.asList(mArchive.getArray(SIZE, true)); + List actual = Arrays.asList(mArchive.getArray(mUm, SIZE, true)); assertThat(actual).hasSize(expected.size()); for (StatusBarNotification sbn : actual) { assertThat(expected).contains(sbn.getKey()); } } + @Test + public void testCrossUser() { + mArchive.record(getNotification("pkg", 1, UserHandle.of(USER_SYSTEM)), REASON_CANCEL); + mArchive.record(getNotification("pkg", 2, UserHandle.of(USER_CURRENT)), REASON_CANCEL); + mArchive.record(getNotification("pkg", 3, UserHandle.of(USER_ALL)), REASON_CANCEL); + mArchive.record(getNotification("pkg", 4, UserHandle.of(USER_NULL)), REASON_CANCEL); + + List actual = Arrays.asList(mArchive.getArray(mUm, SIZE, true)); + assertThat(actual).hasSize(3); + for (StatusBarNotification sbn : actual) { + if (sbn.getUserId() == USER_NULL) { + fail("leaked notification from wrong user"); + } + } + } + @Test public void testRecordAndRead_overLimit() { List expected = new ArrayList<>(); @@ -99,7 +126,8 @@ public class ArchiveTest extends UiServiceTestCase { } } - List actual = Arrays.asList(mArchive.getArray((SIZE * 2), true)); + List actual = Arrays.asList( + mArchive.getArray(mUm, (SIZE * 2), true)); assertThat(actual).hasSize(expected.size()); for (StatusBarNotification sbn : actual) { assertThat(expected).contains(sbn.getKey()); @@ -119,7 +147,7 @@ public class ArchiveTest extends UiServiceTestCase { } } - List actual = Arrays.asList(mArchive.getArray(SIZE, true)); + List actual = Arrays.asList(mArchive.getArray(mUm, SIZE, true)); assertThat(actual).hasSize(expected.size()); for (StatusBarNotification sbn : actual) { assertThat(expected).contains(sbn.getKey()); @@ -140,7 +168,7 @@ public class ArchiveTest extends UiServiceTestCase { } mArchive.updateHistoryEnabled(USER_CURRENT, false); - List actual = Arrays.asList(mArchive.getArray(SIZE, true)); + List actual = Arrays.asList(mArchive.getArray(mUm, SIZE, true)); assertThat(actual).hasSize(expected.size()); for (StatusBarNotification sbn : actual) { assertThat(expected).contains(sbn.getKey()); @@ -165,7 +193,7 @@ public class ArchiveTest extends UiServiceTestCase { } mArchive.removeChannelNotifications("pkg", USER_CURRENT, "test0"); mArchive.removeChannelNotifications("pkg", USER_CURRENT, "test" + (SIZE - 2)); - List actual = Arrays.asList(mArchive.getArray(SIZE, true)); + List actual = Arrays.asList(mArchive.getArray(mUm, SIZE, true)); assertThat(actual).hasSize(expected.size()); for (StatusBarNotification sbn : actual) { assertThat(expected).contains(sbn.getKey()); @@ -215,7 +243,7 @@ public class ArchiveTest extends UiServiceTestCase { fail("Concurrent modification exception"); } - List actual = Arrays.asList(mArchive.getArray(SIZE, true)); + List actual = Arrays.asList(mArchive.getArray(mUm, SIZE, true)); assertThat(actual).hasSize(expected.size()); for (StatusBarNotification sbn : actual) { assertThat(expected).contains(sbn.getKey()); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index e98d077836e0e..339a0a8606cbc 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -475,6 +475,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { when(mPackageManager.getPackagesForUid(mUid)).thenReturn(new String[]{PKG}); when(mPackageManagerClient.getPackagesForUid(anyInt())).thenReturn(new String[]{PKG}); mContext.addMockSystemService(AppOpsManager.class, mock(AppOpsManager.class)); + when(mUm.getProfileIds(0, false)).thenReturn(new int[]{0}); // write to a test file; the system file isn't readable from tests mFile = new File(mContext.getCacheDir(), "test.xml"); @@ -6970,8 +6971,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { waitForIdle(); // A notification exists for the given record - StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(PKG); - assertEquals(1, notifsBefore.length); + List notifsBefore = + mBinderService.getAppActiveNotifications(PKG, nr.getSbn().getUserId()).getList(); + assertEquals(1, notifsBefore.size()); reset(mPackageManager); @@ -8289,4 +8291,33 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertTrue(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 1001))); assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("test", 1002))); } + + @Test + public void testGetActiveNotification_filtersUsers() throws Exception { + when(mUm.getProfileIds(0, false)).thenReturn(new int[]{0, 10}); + + NotificationRecord nr0 = + generateNotificationRecord(mTestNotificationChannel, 0); + mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag0", + nr0.getSbn().getId(), nr0.getSbn().getNotification(), nr0.getSbn().getUserId()); + + NotificationRecord nr10 = + generateNotificationRecord(mTestNotificationChannel, 10); + mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag10", + nr10.getSbn().getId(), nr10.getSbn().getNotification(), nr10.getSbn().getUserId()); + + NotificationRecord nr11 = + generateNotificationRecord(mTestNotificationChannel, 11); + mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag11", + nr11.getSbn().getId(), nr11.getSbn().getNotification(), nr11.getSbn().getUserId()); + waitForIdle(); + + StatusBarNotification[] notifs = mBinderService.getActiveNotifications(PKG); + assertEquals(2, notifs.length); + for (StatusBarNotification sbn : notifs) { + if (sbn.getUserId() == 11) { + fail("leaked data across users"); + } + } + } } From abb41637225c95d5530bff275531a446be66a18c Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Mon, 31 Jan 2022 14:59:08 -0800 Subject: [PATCH 2/9] Update permissions for ServiceState broadcast Require FINE_LOCATION_ACCESS to get the full service state broadcast, otherwise send the location sanitized copy. Test: manual verify with app Bug: 210118427 Change-Id: Ibfa66624a4157b7c2c7d764e2b6bdb26ac5f1447 Merged-In: Ibfa66624a4157b7c2c7d764e2b6bdb26ac5f1447 (cherry picked from commit d852b695e7a93c973b8a3e8335c43a3724ef3847) (cherry picked from commit 8bfc53154863752fe03d6374ed6876e8807167ce) Merged-In: Ibfa66624a4157b7c2c7d764e2b6bdb26ac5f1447 --- .../com/android/server/TelephonyRegistry.java | 32 +++++++++++++++---- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index ab220b5e42e49..a8a24f19f6ba6 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -2901,14 +2901,32 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId); intent.putExtra(PHONE_CONSTANTS_SLOT_KEY, phoneId); intent.putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, phoneId); + // Send the broadcast twice -- once for all apps with READ_PHONE_STATE, then again - // for all apps with READ_PRIV but not READ_PHONE_STATE. This ensures that any app holding - // either READ_PRIV or READ_PHONE get this broadcast exactly once. - mContext.sendBroadcastAsUser(intent, UserHandle.ALL, Manifest.permission.READ_PHONE_STATE); - mContext.createContextAsUser(UserHandle.ALL, 0) - .sendBroadcastMultiplePermissions(intent, - new String[] { Manifest.permission.READ_PRIVILEGED_PHONE_STATE }, - new String[] { Manifest.permission.READ_PHONE_STATE }); + // for all apps with READ_PRIVILEGED_PHONE_STATE but not READ_PHONE_STATE. + // Do this again twice, the first time for apps with ACCESS_FINE_LOCATION, then again with + // the location-sanitized service state for all apps without ACCESS_FINE_LOCATION. + // This ensures that any app holding either READ_PRIVILEGED_PHONE_STATE or READ_PHONE_STATE + // get this broadcast exactly once, and we are not exposing location without permission. + mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(intent, + new String[] {Manifest.permission.READ_PHONE_STATE, + Manifest.permission.ACCESS_FINE_LOCATION}); + mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(intent, + new String[] {Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + Manifest.permission.ACCESS_FINE_LOCATION}, + new String[] {Manifest.permission.READ_PHONE_STATE}); + + // Replace bundle with location-sanitized ServiceState + data = new Bundle(); + state.createLocationInfoSanitizedCopy(true).fillInNotifierBundle(data); + intent.putExtras(data); + mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(intent, + new String[] {Manifest.permission.READ_PHONE_STATE}, + new String[] {Manifest.permission.ACCESS_FINE_LOCATION}); + mContext.createContextAsUser(UserHandle.ALL, 0).sendBroadcastMultiplePermissions(intent, + new String[] {Manifest.permission.READ_PRIVILEGED_PHONE_STATE}, + new String[] {Manifest.permission.READ_PHONE_STATE, + Manifest.permission.ACCESS_FINE_LOCATION}); } private void broadcastSignalStrengthChanged(SignalStrength signalStrength, int phoneId, From 9a1dfd9a9de3bb33cd81e3003251b49f7862f276 Mon Sep 17 00:00:00 2001 From: Jeff Chang Date: Tue, 25 Jan 2022 10:37:29 +0800 Subject: [PATCH 3/9] [RESTRICT AUTOMERGE] Do not resume activity if behind a translucent task The top-focusable activity resides in the RESUMED state while the app process is newly created and attached. The behavior may enable UI hijacking attacks against apps implementing authentication. This CL disallows the system to resume the activity for the case if it is not visible or is occluded by other translucent tasks. Bug: 211481342 Test: atest CtsWindowManagerDeviceTestCases:ActivityLifecycleTests Change-Id: I7903494cf928b5b5613700262b7c5fff10f3c5a0 (cherry picked from commit 0a4f661ec6a18a0ddc47b6d9280a10b8d16c9457) Merged-In: I7903494cf928b5b5613700262b7c5fff10f3c5a0 --- .../com/android/server/wm/EnsureActivitiesVisibleHelper.java | 2 +- .../core/java/com/android/server/wm/RootWindowContainer.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java index badb1f5a0a12d..4708d00269310 100644 --- a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java +++ b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java @@ -97,7 +97,7 @@ class EnsureActivitiesVisibleHelper { // activities are actually behind other fullscreen activities, but still required // to be visible (such as performing Recents animation). final boolean resumeTopActivity = mTop != null && !mTop.mLaunchTaskBehind - && mTaskFragment.isTopActivityFocusable() + && mTaskFragment.canBeResumed(starting) && (starting == null || !starting.isDescendantOf(mTaskFragment)); ArrayList adjacentTaskFragments = null; diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index fbc8f73b53b00..628e124877e9b 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -1979,7 +1979,8 @@ class RootWindowContainer extends WindowContainer try { if (mTaskSupervisor.realStartActivityLocked(r, app, - top == r && r.isFocusable() /*andResume*/, true /*checkConfig*/)) { + top == r && r.getTask().canBeResumed(r) /*andResume*/, + true /*checkConfig*/)) { mTmpBoolean = true; } } catch (RemoteException e) { From b1b01433f5b8dc0702c0e1abde5f7b86b708a849 Mon Sep 17 00:00:00 2001 From: Vincent Wang Date: Fri, 7 Jan 2022 12:40:00 +0800 Subject: [PATCH 4/9] Replace BitmapRegionDecoder with ImageDecoder 1. generateCrop() couldn't handle super huge size because BitmapRegionDecoder will occupy too much native heap during process, We replace old decoder with ImageDecoder 2. Fix overflow problem in debug message 3. Add a record file to note if ImageDecoder work well Bug: 204087139 Test: Manually set wallpaper, no PDoS observed. Change-Id: I59cf3c21edce836ffbe9f24a08b3a8e077c5fcf3 Merged-In: I59cf3c21edce836ffbe9f24a08b3a8e077c5fcf3 (cherry picked from commit 08d14944212a7026218bde79091f0d1d48bc1c79) Merged-In: I59cf3c21edce836ffbe9f24a08b3a8e077c5fcf3 --- .../wallpaper/WallpaperManagerService.java | 71 ++++++++++++++++--- 1 file changed, 63 insertions(+), 8 deletions(-) diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index 6fda72e1267b4..eddb5e977fa2f 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -59,8 +59,8 @@ import android.content.pm.UserInfo; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; -import android.graphics.BitmapRegionDecoder; import android.graphics.Color; +import android.graphics.ImageDecoder; import android.graphics.Rect; import android.graphics.RectF; import android.hardware.display.DisplayManager; @@ -193,6 +193,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub static final String WALLPAPER_LOCK_ORIG = "wallpaper_lock_orig"; static final String WALLPAPER_LOCK_CROP = "wallpaper_lock"; static final String WALLPAPER_INFO = "wallpaper_info.xml"; + private static final String RECORD_FILE = "decode_record"; + private static final String RECORD_LOCK_FILE = "decode_lock_record"; // All the various per-user state files we need to be aware of private static final String[] sPerUserFiles = new String[] { @@ -674,8 +676,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } if (DEBUG) { - // This is just a quick estimation, may be smaller than it is. - long estimateSize = options.outWidth * options.outHeight * 4; + long estimateSize = (long) options.outWidth * options.outHeight * 4; Slog.v(TAG, "Null crop of new wallpaper, estimate size=" + estimateSize + ", success=" + success); } @@ -684,9 +685,6 @@ public class WallpaperManagerService extends IWallpaperManager.Stub FileOutputStream f = null; BufferedOutputStream bos = null; try { - BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance( - wallpaper.wallpaperFile.getAbsolutePath(), false); - // This actually downsamples only by powers of two, but that's okay; we do // a proper scaling blit later. This is to minimize transient RAM use. // We calculate the largest power-of-two under the actual ratio rather than @@ -740,8 +738,24 @@ public class WallpaperManagerService extends IWallpaperManager.Stub Slog.v(TAG, " maxTextureSize=" + GLHelper.getMaxTextureSize()); } - Bitmap cropped = decoder.decodeRegion(cropHint, options); - decoder.recycle(); + //Create a record file and will delete if ImageDecoder work well. + final String recordName = + (wallpaper.wallpaperFile.getName().equals(WALLPAPER) + ? RECORD_FILE : RECORD_LOCK_FILE); + final File record = new File(getWallpaperDir(wallpaper.userId), recordName); + record.createNewFile(); + Slog.v(TAG, "record path =" + record.getPath() + + ", record name =" + record.getName()); + + final ImageDecoder.Source srcData = + ImageDecoder.createSource(wallpaper.wallpaperFile); + final int sampleSize = scale; + Bitmap cropped = ImageDecoder.decodeBitmap(srcData, (decoder, info, src) -> { + decoder.setTargetSampleSize(sampleSize); + decoder.setCrop(estimateCrop); + }); + + record.delete(); if (cropped == null) { Slog.e(TAG, "Could not decode new wallpaper"); @@ -1779,6 +1793,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub new UserSwitchObserver() { @Override public void onUserSwitching(int newUserId, IRemoteCallback reply) { + errorCheck(newUserId); switchUser(newUserId, reply); } }, TAG); @@ -1816,6 +1831,14 @@ public class WallpaperManagerService extends IWallpaperManager.Stub @Override public void onBootPhase(int phase) { + // If someone set too large jpg file as wallpaper, system_server may be killed by lmk in + // generateCrop(), so we create a file in generateCrop() before ImageDecoder starts working + // and delete this file after ImageDecoder finishing. If the specific file exists, that + // means ImageDecoder can't handle the original wallpaper file, in order to avoid + // system_server restart again and again and rescue party will trigger factory reset, + // so we reset default wallpaper in case system_server is trapped into a restart loop. + errorCheck(UserHandle.USER_SYSTEM); + if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) { systemReady(); } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) { @@ -1823,6 +1846,38 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } } + private static final HashMap sWallpaperType = new HashMap() { + { + put(FLAG_SYSTEM, RECORD_FILE); + put(FLAG_LOCK, RECORD_LOCK_FILE); + } + }; + + private void errorCheck(int userID) { + sWallpaperType.forEach((type, filename) -> { + final File record = new File(getWallpaperDir(userID), filename); + if (record.exists()) { + Slog.w(TAG, "User:" + userID + ", wallpaper tyep = " + type + + ", wallpaper fail detect!! reset to default wallpaper"); + clearWallpaperData(userID, type); + record.delete(); + } + }); + } + + private void clearWallpaperData(int userID, int wallpaperType) { + final WallpaperData wallpaper = new WallpaperData(userID, getWallpaperDir(userID), + (wallpaperType == FLAG_LOCK) ? WALLPAPER_LOCK_ORIG : WALLPAPER, + (wallpaperType == FLAG_LOCK) ? WALLPAPER_LOCK_CROP : WALLPAPER_CROP); + if (wallpaper.sourceExists()) { + wallpaper.wallpaperFile.delete(); + } + if (wallpaper.cropExists()) { + wallpaper.cropFile.delete(); + } + + } + @Override public void onUnlockUser(final int userId) { TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG); From b55656825844f8ac1d776da0b3290a4e9948ba4f Mon Sep 17 00:00:00 2001 From: Pinyao Ting Date: Thu, 3 Mar 2022 18:24:37 +0000 Subject: [PATCH 5/9] Verify caller before auto granting slice permission Currently SliceManagerService#checkSlicePermission does not verify the caller's identity. This leads to a security vulnerability because checkSlicePermission does more than checking the permission as opposed to simply return a boolean value -- it additionally grants slice access under a certain condition. A malicious app can spoof the calling package to acquire slice access. This CL verifies the caller before granting slice access. Bug: 208232850, 179699767 Test: manual Change-Id: I2539c9ff5ea977c91bb58185c95280b4d533a520 Merged-In: I2539c9ff5ea977c91bb58185c95280b4d533a520 (cherry picked from commit 5bd2196c537ae42a5c1626bdc23c3c6db41fb97f) (cherry picked from commit 3c92d74d7d74e1d781ae1b071da97b3b2cbc6be9) Merged-In: I2539c9ff5ea977c91bb58185c95280b4d533a520 --- .../core/java/com/android/server/slice/SliceManagerService.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/services/core/java/com/android/server/slice/SliceManagerService.java b/services/core/java/com/android/server/slice/SliceManagerService.java index ee0e5ba916b9c..e3dcfd0c89c06 100644 --- a/services/core/java/com/android/server/slice/SliceManagerService.java +++ b/services/core/java/com/android/server/slice/SliceManagerService.java @@ -247,6 +247,8 @@ public class SliceManagerService extends ISliceManager.Stub { if (autoGrantPermissions != null && callingPkg != null) { // Need to own the Uri to call in with permissions to grant. enforceOwner(callingPkg, uri, userId); + // b/208232850: Needs to verify caller before granting slice access + verifyCaller(callingPkg); for (String perm : autoGrantPermissions) { if (mContext.checkPermission(perm, pid, uid) == PERMISSION_GRANTED) { int providerUser = ContentProvider.getUserIdFromUri(uri, userId); From 5df6c3f7099d3d2e237f54c41692bdef5f090d45 Mon Sep 17 00:00:00 2001 From: Alex Buynytskyy Date: Thu, 24 Feb 2022 21:40:13 -0800 Subject: [PATCH 6/9] Always restart apps if base.apk gets updated. Bug: 219044664 Fixes: 219044664 Test: atest PackageManagerShellCommandTest Change-Id: I27a0c5009b2d5f1ea51618b9acfa1e6ccee71296 Merged-In: I27a0c5009b2d5f1ea51618b9acfa1e6ccee71296 (cherry picked from commit 36b0e9e94c3af7e5f81b88d68447c890d1126498) Merged-In: I27a0c5009b2d5f1ea51618b9acfa1e6ccee71296 --- .../android/content/pm/IPackageInstallerSession.aidl | 1 + core/java/android/content/pm/PackageInstaller.java | 12 ++++++++++++ .../android/server/pm/PackageInstallerSession.java | 11 +++++++++++ 3 files changed, 24 insertions(+) diff --git a/core/java/android/content/pm/IPackageInstallerSession.aidl b/core/java/android/content/pm/IPackageInstallerSession.aidl index f72288c670d92..9a7a949e3cd2f 100644 --- a/core/java/android/content/pm/IPackageInstallerSession.aidl +++ b/core/java/android/content/pm/IPackageInstallerSession.aidl @@ -55,4 +55,5 @@ interface IPackageInstallerSession { int getParentSessionId(); boolean isStaged(); + int getInstallFlags(); } diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index 3f8aedb31ea9c..4030708d6a53b 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -1431,6 +1431,18 @@ public class PackageInstaller { } } + /** + * @return Session's {@link SessionParams#installFlags}. + * @hide + */ + public int getInstallFlags() { + try { + return mSession.getInstallFlags(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * @return the session ID of the multi-package session that this belongs to or * {@link SessionInfo#INVALID_ID} if it does not belong to a multi-package session. diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index d0e4457496988..3ddcf17d0a476 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -126,6 +126,7 @@ import android.system.StructStat; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; +import android.util.EventLog; import android.util.ExceptionUtils; import android.util.MathUtils; import android.util.Slog; @@ -3097,6 +3098,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { if (mResolvedBaseFile == null) { mResolvedBaseFile = new File(appInfo.getBaseCodePath()); inheritFileLocked(mResolvedBaseFile); + } else if ((params.installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) { + EventLog.writeEvent(0x534e4554, "219044664"); + + // Installing base.apk. Make sure the app is restarted. + params.setDontKillApp(false); } // Inherit splits if not overridden. @@ -3742,6 +3748,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { return params.isStaged; } + @Override + public int getInstallFlags() { + return params.installFlags; + } + @Override public DataLoaderParamsParcel getDataLoaderParams() { mContext.enforceCallingOrSelfPermission(Manifest.permission.USE_INSTALLER_V2, null); From 9f62ea551f70573a284a4f64ec5635616e28529a Mon Sep 17 00:00:00 2001 From: wilsonshih Date: Tue, 1 Mar 2022 16:12:53 +0800 Subject: [PATCH 7/9] Revert "Fixes cannot leave dozing when dismiss keyguard" Regression from I62be9283a1d22119eceae5585960b5775a019153. When dismiss keyguard from shell command, the wakeup signal should only be used when dream activity is on top. Bug: 219376804 Bug: 222429976 Test: atest KeyguardTests KeyguardLockedTests Test: atest WindowManagerServiceTests Change-Id: I4edab8588421b3e341cf3bde07e989ff5e651cfe Merged-In: I4edab8588421b3e341cf3bde07e989ff5e651cfe (cherry picked from commit 0063c2488e0eacb103ed33f2b1397a7d83c225d0) Merged-In: I4edab8588421b3e341cf3bde07e989ff5e651cfe --- .../com/android/server/wm/WindowManagerService.java | 3 --- .../android/server/wm/WindowManagerServiceTests.java | 12 ------------ 2 files changed, 15 deletions(-) diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 4258e073429ee..575ae691dbe89 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -3277,9 +3277,6 @@ public class WindowManagerService extends IWindowManager.Stub if (!checkCallingPermission(permission.CONTROL_KEYGUARD, "dismissKeyguard")) { throw new SecurityException("Requires CONTROL_KEYGUARD permission"); } - if (mAtmInternal.isDreaming()) { - mAtmService.mTaskSupervisor.wakeUp("dismissKeyguard"); - } synchronized (mGlobalLock) { mPolicy.dismissKeyguardLw(callback, message); } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java index a91298f73d08c..10011fd4e6e3e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java @@ -31,7 +31,6 @@ import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.never; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; @@ -42,7 +41,6 @@ import static org.junit.Assert.assertFalse; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -157,16 +155,6 @@ public class WindowManagerServiceTests extends WindowTestsBase { verify(mWm.mAtmService).setFocusedTask(tappedTask.mTaskId, null); } - @Test - public void testDismissKeyguardCanWakeUp() { - doReturn(true).when(mWm).checkCallingPermission(anyString(), anyString()); - spyOn(mWm.mAtmInternal); - doReturn(true).when(mWm.mAtmInternal).isDreaming(); - doNothing().when(mWm.mAtmService.mTaskSupervisor).wakeUp(anyString()); - mWm.dismissKeyguard(null, "test-dismiss-keyguard"); - verify(mWm.mAtmService.mTaskSupervisor).wakeUp(anyString()); - } - @Test public void testMoveWindowTokenToDisplay_NullToken_DoNothing() { mWm.moveWindowTokenToDisplay(null, mDisplayContent.getDisplayId()); From 810d71245ce8a899dd18df0784ec41a23c1bd2f3 Mon Sep 17 00:00:00 2001 From: Matt Pietal Date: Fri, 1 Oct 2021 11:03:16 -0400 Subject: [PATCH 8/9] Keyguard - Treat messsages to lock with priority When switching users and attempting to lock the device, the sysui main thread becomes overwhelmed with events, creating a significant lag between the time a message is posted and processed on the main thread. This can be dangerous when these events are critical for security, such as calls coming from PhoneWindowManager#lockNow() that call KeyguardViewMediator#doKeyguardTimeout(). On older devices with slower CPUs and less memory, the delay in processing can be significant (15 - 30s). The result of not prioritizing these events leads to a window of time where a guest user can switch back to the owner, and gain access to the owner's homescreen without needing to unlock the device with the owner's credentials. As a mitigation, prioritize two events originating in two specific methods to make sure the device locks as soon as possible as well as have the system server preemptively update its local cache. Bug: 151095871 Test: Very manual race condition - follow steps listed in bug Change-Id: I7585a0a5eeb308e0e32a4f77f581556d883b5cda Merged-In: I7585a0a5eeb308e0e32a4f77f581556d883b5cda (cherry picked from commit 28c53ab8bca26af58b45625c1ebba8b9051c107d) (cherry picked from commit f8023c9829890ede1bdcbd04314d26c122b1f3f1) (cherry picked from commit 256b5f08a89e441f7e01f87346945e9350fa7a3c) Merged-In: I7585a0a5eeb308e0e32a4f77f581556d883b5cda --- .../internal/policy/IKeyguardStateCallback.aidl | 2 +- .../systemui/keyguard/KeyguardViewMediator.java | 16 +++++++++++----- .../policy/keyguard/KeyguardServiceWrapper.java | 6 ++++++ .../policy/keyguard/KeyguardStateMonitor.java | 8 +++++++- 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/core/java/com/android/internal/policy/IKeyguardStateCallback.aidl b/core/java/com/android/internal/policy/IKeyguardStateCallback.aidl index 419b1f8feac7a..d69a240b140b7 100644 --- a/core/java/com/android/internal/policy/IKeyguardStateCallback.aidl +++ b/core/java/com/android/internal/policy/IKeyguardStateCallback.aidl @@ -16,7 +16,7 @@ package com.android.internal.policy; interface IKeyguardStateCallback { - void onShowingStateChanged(boolean showing); + void onShowingStateChanged(boolean showing, int userId); void onSimSecureStateChanged(boolean simSecure); void onInputRestrictedStateChanged(boolean inputRestricted); void onTrustedChanged(boolean trusted); diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index e9f288d51317b..112bfafbdc204 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -1484,7 +1484,9 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable, public void doKeyguardTimeout(Bundle options) { mHandler.removeMessages(KEYGUARD_TIMEOUT); Message msg = mHandler.obtainMessage(KEYGUARD_TIMEOUT, options); - mHandler.sendMessage(msg); + // Treat these messages with priority - A call to timeout means the device should lock + // as soon as possible and not wait for other messages on the thread to process first. + mHandler.sendMessageAtFrontOfQueue(msg); } /** @@ -1673,12 +1675,15 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable, * @see #handleShow */ private void showLocked(Bundle options) { - Trace.beginSection("KeyguardViewMediator#showLocked aqcuiring mShowKeyguardWakeLock"); + Trace.beginSection("KeyguardViewMediator#showLocked acquiring mShowKeyguardWakeLock"); if (DEBUG) Log.d(TAG, "showLocked"); // ensure we stay awake until we are finished displaying the keyguard mShowKeyguardWakeLock.acquire(); Message msg = mHandler.obtainMessage(SHOW, options); - mHandler.sendMessage(msg); + // Treat these messages with priority - This call can originate from #doKeyguardTimeout, + // meaning the device should lock as soon as possible and not wait for other messages on + // the thread to process first. + mHandler.sendMessageAtFrontOfQueue(msg); Trace.endSection(); } @@ -1879,6 +1884,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable, case KEYGUARD_TIMEOUT: synchronized (KeyguardViewMediator.this) { doKeyguardLocked((Bundle) msg.obj); + notifyDefaultDisplayCallbacks(mShowing); } break; case DISMISS: @@ -2888,7 +2894,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable, for (int i = size - 1; i >= 0; i--) { IKeyguardStateCallback callback = mKeyguardStateCallbacks.get(i); try { - callback.onShowingStateChanged(showing); + callback.onShowingStateChanged(showing, KeyguardUpdateMonitor.getCurrentUser()); } catch (RemoteException e) { Slog.w(TAG, "Failed to call onShowingStateChanged", e); if (e instanceof DeadObjectException) { @@ -2922,7 +2928,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable, mKeyguardStateCallbacks.add(callback); try { callback.onSimSecureStateChanged(mUpdateMonitor.isSimPinSecure()); - callback.onShowingStateChanged(mShowing); + callback.onShowingStateChanged(mShowing, KeyguardUpdateMonitor.getCurrentUser()); callback.onInputRestrictedStateChanged(mInputRestricted); callback.onTrustedChanged(mUpdateMonitor.getUserHasTrust( KeyguardUpdateMonitor.getCurrentUser())); diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java index ac650ec0f564a..2029f869802ee 100644 --- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java +++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java @@ -195,6 +195,12 @@ public class KeyguardServiceWrapper implements IKeyguardService { @Override // Binder interface public void doKeyguardTimeout(Bundle options) { + int userId = mKeyguardStateMonitor.getCurrentUser(); + if (mKeyguardStateMonitor.isSecure(userId)) { + // Preemptively inform the cache that the keyguard will soon be showing, as calls to + // doKeyguardTimeout are a signal to lock the device as soon as possible. + mKeyguardStateMonitor.onShowingStateChanged(true, userId); + } try { mService.doKeyguardTimeout(options); } catch (RemoteException e) { diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java index e6511372d62ca..c0aa8aeff7111 100644 --- a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java +++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java @@ -78,8 +78,14 @@ public class KeyguardStateMonitor extends IKeyguardStateCallback.Stub { return mTrusted; } + public int getCurrentUser() { + return mCurrentUserId; + } + @Override // Binder interface - public void onShowingStateChanged(boolean showing) { + public void onShowingStateChanged(boolean showing, int userId) { + if (userId != mCurrentUserId) return; + mIsShowing = showing; mCallback.onShowingChanged(); From 35998a72b71c1c18a77815e40a6b08bd9e93c97b Mon Sep 17 00:00:00 2001 From: Caitlin Cassidy Date: Wed, 2 Mar 2022 20:33:30 +0000 Subject: [PATCH 9/9] [Ongoing Call] Don't call #getIntent to avoid a security vulnerability. Fixes: 212467440 Test: atest OngoingCallControllerTest Test: verified clicking the chip can still open valid activities. Change-Id: I7707d01be37582461227edcecf5d559f2019c8a5 Merged-In: I7707d01be37582461227edcecf5d559f2019c8a5 (cherry picked from commit 08d94cbabb44207f1ebfddc76d9f11b6b328fdee) (cherry picked from commit b029b005d8d4122d29cffc86b752fce13b1d4da6) (cherry picked from commit ccac141cc774a76a2aaef76399fa6790252363cf) Merged-In: I7707d01be37582461227edcecf5d559f2019c8a5 --- .../phone/ongoingcall/OngoingCallController.kt | 7 +++---- .../ongoingcall/OngoingCallControllerTest.kt | 15 +++++++++++++-- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt index 12258136c011f..67985b95dda4a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt @@ -21,7 +21,7 @@ import android.app.IActivityManager import android.app.IUidObserver import android.app.Notification import android.app.Notification.CallStyle.CALL_TYPE_ONGOING -import android.content.Intent +import android.app.PendingIntent import android.util.Log import android.view.View import androidx.annotation.VisibleForTesting @@ -98,7 +98,7 @@ class OngoingCallController @Inject constructor( val newOngoingCallInfo = CallNotificationInfo( entry.sbn.key, entry.sbn.notification.`when`, - entry.sbn.notification.contentIntent?.intent, + entry.sbn.notification.contentIntent, entry.sbn.uid, entry.sbn.notification.extras.getInt( Notification.EXTRA_CALL_TYPE, -1) == CALL_TYPE_ONGOING, @@ -230,7 +230,6 @@ class OngoingCallController @Inject constructor( logger.logChipClicked() activityStarter.postStartActivityDismissingKeyguard( intent, - 0, ActivityLaunchAnimator.Controller.fromView( backgroundView, InteractionJankMonitor.CUJ_STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP) @@ -351,7 +350,7 @@ class OngoingCallController @Inject constructor( private data class CallNotificationInfo( val key: String, val callStartTime: Long, - val intent: Intent?, + val intent: PendingIntent?, val uid: Int, /** True if the call is currently ongoing (as opposed to incoming, screening, etc.). */ val isOngoing: Boolean, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt index b385b7d62cff8..45c6be936eb9d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt @@ -22,7 +22,6 @@ import android.app.IUidObserver import android.app.Notification import android.app.PendingIntent import android.app.Person -import android.content.Intent import android.service.notification.NotificationListenerService.REASON_USER_STOPPED import android.testing.AndroidTestingRunner import android.testing.TestableLooper @@ -429,6 +428,19 @@ class OngoingCallControllerTest : SysuiTestCase() { .isEqualTo(OngoingCallLogger.OngoingCallEvents.ONGOING_CALL_CLICKED.id) } + /** Regression test for b/212467440. */ + @Test + fun chipClicked_activityStarterTriggeredWithUnmodifiedIntent() { + val notifEntry = createOngoingCallNotifEntry() + val pendingIntent = notifEntry.sbn.notification.contentIntent + notifCollectionListener.onEntryUpdated(notifEntry) + + chipView.performClick() + + // Ensure that the sysui didn't modify the notification's intent -- see b/212467440. + verify(mockActivityStarter).postStartActivityDismissingKeyguard(eq(pendingIntent), any()) + } + @Test fun notifyChipVisibilityChanged_visibleEventLogged() { controller.notifyChipVisibilityChanged(true) @@ -570,7 +582,6 @@ class OngoingCallControllerTest : SysuiTestCase() { notificationEntryBuilder.modifyNotification(context).setContentIntent(null) } else { val contentIntent = mock(PendingIntent::class.java) - `when`(contentIntent.intent).thenReturn(mock(Intent::class.java)) notificationEntryBuilder.modifyNotification(context).setContentIntent(contentIntent) }