Merge "Revert "Clear notifications for packages whose permission is revoked"" into udc-qpr-dev

This commit is contained in:
Julia Reynolds
2023-07-19 16:21:37 +00:00
committed by Android (Google) Code Review
2 changed files with 49 additions and 163 deletions

View File

@@ -2491,16 +2491,6 @@ public class NotificationManagerService extends SystemService {
getContext().registerReceiver(mReviewNotificationPermissionsReceiver,
ReviewNotificationPermissionsReceiver.getFilter(),
Context.RECEIVER_NOT_EXPORTED);
mAppOps.startWatchingMode(AppOpsManager.OP_POST_NOTIFICATION, null,
new AppOpsManager.OnOpChangedInternalListener() {
@Override
public void onOpChanged(@NonNull String op, @NonNull String packageName,
int userId) {
mHandler.post(
() -> handleNotificationPermissionChange(packageName, userId));
}
});
}
/**
@@ -3560,16 +3550,20 @@ public class NotificationManagerService extends SystemService {
}
mPermissionHelper.setNotificationPermission(
pkg, UserHandle.getUserId(uid), enabled, true);
sendAppBlockStateChangedBroadcast(pkg, uid, !enabled);
mMetricsLogger.write(new LogMaker(MetricsEvent.ACTION_BAN_APP_NOTES)
.setType(MetricsEvent.TYPE_ACTION)
.setPackageName(pkg)
.setSubtype(enabled ? 1 : 0));
mNotificationChannelLogger.logAppNotificationsAllowed(uid, pkg, enabled);
// Now, cancel any outstanding notifications that are part of a just-disabled app
if (!enabled) {
cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0,
UserHandle.getUserId(uid), REASON_PACKAGE_BANNED);
}
// Outstanding notifications from this package will be cancelled, and the package will
// be sent the ACTION_APP_BLOCK_STATE_CHANGED broadcast, as soon as we get the
// callback from AppOpsManager.
handleSavePolicyFile();
}
/**
@@ -5892,21 +5886,6 @@ public class NotificationManagerService extends SystemService {
}
};
private void handleNotificationPermissionChange(String pkg, @UserIdInt int userId) {
int uid = mPackageManagerInternal.getPackageUid(pkg, 0, userId);
if (uid == INVALID_UID) {
Log.e(TAG, String.format("No uid found for %s, %s!", pkg, userId));
return;
}
boolean hasPermission = mPermissionHelper.hasPermission(uid);
sendAppBlockStateChangedBroadcast(pkg, uid, !hasPermission);
if (!hasPermission) {
cancelAllNotificationsInt(MY_UID, MY_PID, pkg, /* channelId= */ null,
/* mustHaveFlags= */ 0, /* mustNotHaveFlags= */ 0, userId,
REASON_PACKAGE_BANNED);
}
}
protected void checkNotificationListenerAccess() {
if (!isCallerSystemOrPhone()) {
getContext().enforceCallingPermission(

View File

@@ -406,7 +406,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
UriGrantsManagerInternal mUgmInternal;
@Mock
AppOpsManager mAppOpsManager;
private AppOpsManager.OnOpChangedListener mOnPermissionChangeListener;
@Mock
private TestableNotificationManagerService.NotificationAssistantAccessGrantedCallback
mNotificationAssistantAccessGrantedCallback;
@@ -606,12 +605,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
tr.addOverride(com.android.internal.R.string.config_defaultSearchSelectorPackageName,
SEARCH_SELECTOR_PKG);
doAnswer(invocation -> {
mOnPermissionChangeListener = invocation.getArgument(2);
return null;
}).when(mAppOpsManager).startWatchingMode(eq(AppOpsManager.OP_POST_NOTIFICATION), any(),
any());
mWorkerHandler = spy(mService.new WorkerHandler(mTestableLooper.getLooper()));
mService.init(mWorkerHandler, mRankingHandler, mPackageManager, mPackageManagerClient,
mockLightsManager, mListeners, mAssistants, mConditionProviders, mCompanionMgr,
@@ -3223,6 +3216,48 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
anyBoolean(), anyBoolean());
}
@Test
public void testUpdateAppNotifyCreatorBlock() throws Exception {
when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
mBinderService.setNotificationsEnabledForPackage(PKG, mUid, false);
Thread.sleep(500);
waitForIdle();
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null));
assertEquals(NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED,
captor.getValue().getAction());
assertEquals(PKG, captor.getValue().getPackage());
assertTrue(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, true));
}
@Test
public void testUpdateAppNotifyCreatorBlock_notIfMatchesExistingSetting() throws Exception {
when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
mBinderService.setNotificationsEnabledForPackage(PKG, 0, false);
verify(mContext, never()).sendBroadcastAsUser(any(), any(), eq(null));
}
@Test
public void testUpdateAppNotifyCreatorUnblock() throws Exception {
when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
mBinderService.setNotificationsEnabledForPackage(PKG, mUid, true);
Thread.sleep(500);
waitForIdle();
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null));
assertEquals(NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED,
captor.getValue().getAction());
assertEquals(PKG, captor.getValue().getPackage());
assertFalse(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, true));
}
@Test
public void testUpdateChannelNotifyCreatorBlock() throws Exception {
mService.setPreferencesHelper(mPreferencesHelper);
@@ -12139,134 +12174,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
any(), eq(FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER | FLAG_SERVICE_SENDER));
}
@Test
public void onOpChanged_permissionRevoked_cancelsAllNotificationsFromPackage()
throws RemoteException {
// Have preexisting posted notifications from revoked package and other packages.
mService.addNotification(new NotificationRecord(mContext,
generateSbn("revoked", 1001, 1, 0), mTestNotificationChannel));
mService.addNotification(new NotificationRecord(mContext,
generateSbn("other", 1002, 2, 0), mTestNotificationChannel));
// Have preexisting enqueued notifications from revoked package and other packages.
mService.addEnqueuedNotification(new NotificationRecord(mContext,
generateSbn("revoked", 1001, 3, 0), mTestNotificationChannel));
mService.addEnqueuedNotification(new NotificationRecord(mContext,
generateSbn("other", 1002, 4, 0), mTestNotificationChannel));
assertThat(mService.mNotificationList).hasSize(2);
assertThat(mService.mEnqueuedNotifications).hasSize(2);
when(mPackageManagerInternal.getPackageUid("revoked", 0, 0)).thenReturn(1001);
when(mPermissionHelper.hasPermission(eq(1001))).thenReturn(false);
mOnPermissionChangeListener.onOpChanged(
AppOpsManager.OPSTR_POST_NOTIFICATION, "revoked", 0);
waitForIdle();
assertThat(mService.mNotificationList).hasSize(1);
assertThat(mService.mNotificationList.get(0).getSbn().getPackageName()).isEqualTo("other");
assertThat(mService.mEnqueuedNotifications).hasSize(1);
assertThat(mService.mEnqueuedNotifications.get(0).getSbn().getPackageName()).isEqualTo(
"other");
}
@Test
public void onOpChanged_permissionStillGranted_notificationsAreNotAffected()
throws RemoteException {
// NOTE: This combination (receiving the onOpChanged broadcast for a package, the permission
// being now granted, AND having previously posted notifications from said package) should
// never happen (if we trust the broadcasts are correct). So this test is for a what-if
// scenario, to verify we still handle it reasonably.
// Have preexisting posted notifications from specific package and other packages.
mService.addNotification(new NotificationRecord(mContext,
generateSbn("granted", 1001, 1, 0), mTestNotificationChannel));
mService.addNotification(new NotificationRecord(mContext,
generateSbn("other", 1002, 2, 0), mTestNotificationChannel));
// Have preexisting enqueued notifications from specific package and other packages.
mService.addEnqueuedNotification(new NotificationRecord(mContext,
generateSbn("granted", 1001, 3, 0), mTestNotificationChannel));
mService.addEnqueuedNotification(new NotificationRecord(mContext,
generateSbn("other", 1002, 4, 0), mTestNotificationChannel));
assertThat(mService.mNotificationList).hasSize(2);
assertThat(mService.mEnqueuedNotifications).hasSize(2);
when(mPackageManagerInternal.getPackageUid("granted", 0, 0)).thenReturn(1001);
when(mPermissionHelper.hasPermission(eq(1001))).thenReturn(true);
mOnPermissionChangeListener.onOpChanged(
AppOpsManager.OPSTR_POST_NOTIFICATION, "granted", 0);
waitForIdle();
assertThat(mService.mNotificationList).hasSize(2);
assertThat(mService.mEnqueuedNotifications).hasSize(2);
}
@Test
public void onOpChanged_permissionGranted_notifiesAppUnblocked() throws Exception {
when(mPackageManagerInternal.getPackageUid(PKG, 0, 0)).thenReturn(1001);
when(mPermissionHelper.hasPermission(eq(1001))).thenReturn(true);
mOnPermissionChangeListener.onOpChanged(
AppOpsManager.OPSTR_POST_NOTIFICATION, PKG, 0);
waitForIdle();
mTestableLooper.moveTimeForward(500);
waitForIdle();
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
verify(mContext).sendBroadcastAsUser(captor.capture(), any(), eq(null));
assertThat(captor.getValue().getAction()).isEqualTo(
NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED);
assertThat(captor.getValue().getPackage()).isEqualTo(PKG);
assertThat(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, true)).isFalse();
}
@Test
public void onOpChanged_permissionRevoked_notifiesAppBlocked() throws Exception {
when(mPackageManagerInternal.getPackageUid(PKG, 0, 0)).thenReturn(1001);
when(mPermissionHelper.hasPermission(eq(1001))).thenReturn(false);
mOnPermissionChangeListener.onOpChanged(
AppOpsManager.OPSTR_POST_NOTIFICATION, PKG, 0);
waitForIdle();
mTestableLooper.moveTimeForward(500);
waitForIdle();
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
verify(mContext).sendBroadcastAsUser(captor.capture(), any(), eq(null));
assertThat(captor.getValue().getAction()).isEqualTo(
NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED);
assertThat(captor.getValue().getPackage()).isEqualTo(PKG);
assertThat(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, false)).isTrue();
}
@Test
public void setNotificationsEnabledForPackage_disabling_clearsNotifications() throws Exception {
mService.addNotification(new NotificationRecord(mContext,
generateSbn("package", 1001, 1, 0), mTestNotificationChannel));
assertThat(mService.mNotificationList).hasSize(1);
when(mPackageManagerInternal.getPackageUid("package", 0, 0)).thenReturn(1001);
when(mPermissionHelper.hasRequestedPermission(any(), eq("package"), anyInt())).thenReturn(
true);
// Start with granted permission and simulate effect of revoking it.
when(mPermissionHelper.hasPermission(1001)).thenReturn(true);
doAnswer(invocation -> {
when(mPermissionHelper.hasPermission(1001)).thenReturn(false);
mOnPermissionChangeListener.onOpChanged(
AppOpsManager.OPSTR_POST_NOTIFICATION, "package", 0);
return null;
}).when(mPermissionHelper).setNotificationPermission("package", 0, false, true);
mBinderService.setNotificationsEnabledForPackage("package", 1001, false);
waitForIdle();
assertThat(mService.mNotificationList).hasSize(0);
mTestableLooper.moveTimeForward(500);
waitForIdle();
verify(mContext).sendBroadcastAsUser(any(), eq(UserHandle.of(0)), eq(null));
}
private static <T extends Parcelable> T parcelAndUnparcel(T source,
Parcelable.Creator<T> creator) {
Parcel parcel = Parcel.obtain();