Skip to content

Commit 9b67d75

Browse files
Christopher Tateandroid-build-team Robot
authored andcommitted
DO NOT MERGE - Disallow deletion of channels with FGS notifications
Bug: 156090809 Test: atest CtsAppTestCases:NotificationManagerTest Test: atest CtsAppTestCases:android.app.cts.ServiceTest Change-Id: I1c2bb78d86f194585d273661cecf3419f51965df (cherry picked from commit 39b3890268913bc2dc8b90671d042c0e9b4090d2) (cherry picked from commit 8cb7e0a)
1 parent f599ab8 commit 9b67d75

6 files changed

Lines changed: 114 additions & 11 deletions

File tree

core/java/android/app/ActivityManagerInternal.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,21 @@ public abstract void setDebugFlagsForStartingActivity(ActivityInfo aInfo, int st
377377
*/
378378
public abstract boolean hasRunningForegroundService(int uid, int foregroundServiceType);
379379

380+
/**
381+
* Returns {@code true} if the given notification channel currently has a
382+
* notification associated with a foreground service. This is an AMS check
383+
* because that is the source of truth for the FGS state.
384+
*/
385+
public abstract boolean hasForegroundServiceNotification(String pkg, @UserIdInt int userId,
386+
String channelId);
387+
388+
/**
389+
* If the given app has any FGSs whose notifications are in the given channel,
390+
* stop them.
391+
*/
392+
public abstract void stopForegroundServicesForChannel(String pkg, @UserIdInt int userId,
393+
String channelId);
394+
380395
/**
381396
* Registers the specified {@code processObserver} to be notified of future changes to
382397
* process state.

services/core/java/com/android/server/am/ActiveServices.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@
119119
import java.util.ArrayList;
120120
import java.util.Comparator;
121121
import java.util.List;
122+
import java.util.Objects;
122123
import java.util.Set;
123124
import java.util.function.Predicate;
124125

@@ -433,6 +434,45 @@ boolean hasBackgroundServicesLocked(int callingUser) {
433434
return smap != null ? smap.mStartingBackground.size() >= mMaxStartingBackground : false;
434435
}
435436

437+
boolean hasForegroundServiceNotificationLocked(String pkg, int userId, String channelId) {
438+
final ServiceMap smap = mServiceMap.get(userId);
439+
if (smap != null) {
440+
for (int i = 0; i < smap.mServicesByInstanceName.size(); i++) {
441+
final ServiceRecord sr = smap.mServicesByInstanceName.valueAt(i);
442+
if (sr.appInfo.packageName.equals(pkg) && sr.isForeground) {
443+
if (Objects.equals(sr.foregroundNoti.getChannelId(), channelId)) {
444+
if (DEBUG_FOREGROUND_SERVICE) {
445+
Slog.d(TAG_SERVICE, "Channel u" + userId + "/pkg=" + pkg
446+
+ "/channelId=" + channelId
447+
+ " has fg service notification");
448+
}
449+
return true;
450+
}
451+
}
452+
}
453+
}
454+
return false;
455+
}
456+
457+
void stopForegroundServicesForChannelLocked(String pkg, int userId, String channelId) {
458+
final ServiceMap smap = mServiceMap.get(userId);
459+
if (smap != null) {
460+
for (int i = 0; i < smap.mServicesByInstanceName.size(); i++) {
461+
final ServiceRecord sr = smap.mServicesByInstanceName.valueAt(i);
462+
if (sr.appInfo.packageName.equals(pkg) && sr.isForeground) {
463+
if (Objects.equals(sr.foregroundNoti.getChannelId(), channelId)) {
464+
if (DEBUG_FOREGROUND_SERVICE) {
465+
Slog.d(TAG_SERVICE, "Stopping FGS u" + userId + "/pkg=" + pkg
466+
+ "/channelId=" + channelId
467+
+ " for conversation channel clear");
468+
}
469+
stopServiceLocked(sr);
470+
}
471+
}
472+
}
473+
}
474+
}
475+
436476
private ServiceMap getServiceMapLocked(int callingUser) {
437477
ServiceMap smap = mServiceMap.get(callingUser);
438478
if (smap == null) {

services/core/java/com/android/server/am/ActivityManagerService.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19730,6 +19730,22 @@ public boolean hasRunningForegroundService(int uid, int foregroundServicetype) {
1973019730
return false;
1973119731
}
1973219732

19733+
@Override
19734+
public boolean hasForegroundServiceNotification(String pkg, int userId,
19735+
String channelId) {
19736+
synchronized (ActivityManagerService.this) {
19737+
return mServices.hasForegroundServiceNotificationLocked(pkg, userId, channelId);
19738+
}
19739+
}
19740+
19741+
@Override
19742+
public void stopForegroundServicesForChannel(String pkg, int userId,
19743+
String channelId) {
19744+
synchronized (ActivityManagerService.this) {
19745+
mServices.stopForegroundServicesForChannelLocked(pkg, userId, channelId);
19746+
}
19747+
}
19748+
1973319749
@Override
1973419750
public void registerProcessObserver(IProcessObserver processObserver) {
1973519751
ActivityManagerService.this.registerProcessObserver(processObserver);

services/core/java/com/android/server/notification/NotificationManagerService.java

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,7 @@ public class NotificationManagerService extends SystemService {
402402
private IActivityManager mAm;
403403
private ActivityTaskManagerInternal mAtm;
404404
private ActivityManager mActivityManager;
405+
private ActivityManagerInternal mAmi;
405406
private IPackageManager mPackageManager;
406407
private PackageManager mPackageManagerClient;
407408
AudioManager mAudioManager;
@@ -1875,7 +1876,7 @@ void init(WorkerHandler handler, RankingHandler rankingHandler,
18751876
DevicePolicyManagerInternal dpm, IUriGrantsManager ugm,
18761877
UriGrantsManagerInternal ugmInternal, AppOpsManager appOps, UserManager userManager,
18771878
NotificationHistoryManager historyManager, StatsManager statsManager,
1878-
TelephonyManager telephonyManager) {
1879+
TelephonyManager telephonyManager, ActivityManagerInternal ami) {
18791880
mHandler = handler;
18801881
Resources resources = getContext().getResources();
18811882
mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
@@ -1896,6 +1897,7 @@ void init(WorkerHandler handler, RankingHandler rankingHandler,
18961897
mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
18971898
mCompanionManager = companionManager;
18981899
mActivityManager = activityManager;
1900+
mAmi = ami;
18991901
mDeviceIdleController = IDeviceIdleController.Stub.asInterface(
19001902
ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
19011903
mDpm = dpm;
@@ -2111,7 +2113,8 @@ null, snoozeHelper, new NotificationUsageStats(getContext()),
21112113
new NotificationHistoryManager(getContext(), handler),
21122114
mStatsManager = (StatsManager) getContext().getSystemService(
21132115
Context.STATS_MANAGER),
2114-
getContext().getSystemService(TelephonyManager.class));
2116+
getContext().getSystemService(TelephonyManager.class),
2117+
LocalServices.getService(ActivityManagerInternal.class));
21152118

21162119
// register for various Intents
21172120
IntentFilter filter = new IntentFilter();
@@ -3395,15 +3398,30 @@ public NotificationChannel getNotificationChannelForPackage(String pkg, int uid,
33953398
pkg, uid, channelId, conversationId, true, includeDeleted);
33963399
}
33973400

3401+
// Returns 'true' if the given channel has a notification associated
3402+
// with an active foreground service.
3403+
private void enforceDeletingChannelHasNoFgService(String pkg, int userId,
3404+
String channelId) {
3405+
if (mAmi.hasForegroundServiceNotification(pkg, userId, channelId)) {
3406+
Slog.w(TAG, "Package u" + userId + "/" + pkg
3407+
+ " may not delete notification channel '"
3408+
+ channelId + "' with fg service");
3409+
throw new SecurityException("Not allowed to delete channel " + channelId
3410+
+ " with a foreground service");
3411+
}
3412+
}
3413+
33983414
@Override
33993415
public void deleteNotificationChannel(String pkg, String channelId) {
34003416
checkCallerIsSystemOrSameApp(pkg);
34013417
final int callingUid = Binder.getCallingUid();
3418+
final int callingUser = UserHandle.getUserId(callingUid);
34023419
if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
34033420
throw new IllegalArgumentException("Cannot delete default channel");
34043421
}
3422+
enforceDeletingChannelHasNoFgService(pkg, callingUser, channelId);
34053423
cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true,
3406-
UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null);
3424+
callingUser, REASON_CHANNEL_BANNED, null);
34073425
mPreferencesHelper.deleteNotificationChannel(pkg, callingUid, channelId);
34083426
mListeners.notifyNotificationChannelChanged(pkg,
34093427
UserHandle.getUserHandleForUid(callingUid),
@@ -3416,19 +3434,23 @@ public void deleteNotificationChannel(String pkg, String channelId) {
34163434
public void deleteConversationNotificationChannels(String pkg, int uid,
34173435
String conversationId) {
34183436
checkCallerIsSystem();
3419-
final int callingUid = Binder.getCallingUid();
34203437
List<NotificationChannel> channels =
34213438
mPreferencesHelper.getNotificationChannelsByConversationId(
34223439
pkg, uid, conversationId);
34233440
if (!channels.isEmpty()) {
3441+
// Preflight for fg service notifications in these channels: do nothing
3442+
// unless they're all eligible
3443+
final int appUserId = UserHandle.getUserId(uid);
34243444
for (NotificationChannel nc : channels) {
3445+
final String channelId = nc.getId();
3446+
mAmi.stopForegroundServicesForChannel(pkg, appUserId, channelId);
34253447
cancelAllNotificationsInt(MY_UID, MY_PID, pkg, nc.getId(), 0, 0, true,
3426-
UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null);
3427-
mPreferencesHelper.deleteNotificationChannel(pkg, callingUid, nc.getId());
3448+
appUserId, REASON_CHANNEL_BANNED, null);
3449+
mPreferencesHelper.deleteNotificationChannel(pkg, uid, channelId);
34283450
mListeners.notifyNotificationChannelChanged(pkg,
3429-
UserHandle.getUserHandleForUid(callingUid),
3451+
UserHandle.getUserHandleForUid(uid),
34303452
mPreferencesHelper.getNotificationChannel(
3431-
pkg, callingUid, nc.getId(), true),
3453+
pkg, uid, channelId, true),
34323454
NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
34333455
}
34343456
handleSavePolicyFile();
@@ -3459,13 +3481,20 @@ public void deleteNotificationChannelGroup(String pkg, String groupId) {
34593481
NotificationChannelGroup groupToDelete =
34603482
mPreferencesHelper.getNotificationChannelGroup(groupId, pkg, callingUid);
34613483
if (groupToDelete != null) {
3484+
// Preflight for allowability
3485+
final int userId = UserHandle.getUserId(callingUid);
3486+
List<NotificationChannel> groupChannels = groupToDelete.getChannels();
3487+
for (int i = 0; i < groupChannels.size(); i++) {
3488+
enforceDeletingChannelHasNoFgService(pkg, userId,
3489+
groupChannels.get(i).getId());
3490+
}
34623491
List<NotificationChannel> deletedChannels =
34633492
mPreferencesHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId);
34643493
for (int i = 0; i < deletedChannels.size(); i++) {
34653494
final NotificationChannel deletedChannel = deletedChannels.get(i);
34663495
cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0,
34673496
true,
3468-
UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
3497+
userId, REASON_CHANNEL_BANNED,
34693498
null);
34703499
mListeners.notifyNotificationChannelChanged(pkg,
34713500
UserHandle.getUserHandleForUid(callingUid),

services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,8 @@ null, new ComponentName(PKG, "test_class"),
496496
mGroupHelper, mAm, mAtm, mAppUsageStats,
497497
mock(DevicePolicyManagerInternal.class), mUgm, mUgmInternal,
498498
mAppOpsManager, mUm, mHistoryManager, mStatsManager,
499-
mock(TelephonyManager.class));
499+
mock(TelephonyManager.class),
500+
mock(ActivityManagerInternal.class));
500501
mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
501502

502503
mService.setAudioManager(mAudioManager);

services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import static org.mockito.Mockito.when;
3333

3434
import android.app.ActivityManager;
35+
import android.app.ActivityManagerInternal;
3536
import android.app.AppOpsManager;
3637
import android.app.IActivityManager;
3738
import android.app.IUriGrantsManager;
@@ -156,7 +157,8 @@ public void setUp() throws Exception {
156157
mock(DevicePolicyManagerInternal.class), mock(IUriGrantsManager.class),
157158
mock(UriGrantsManagerInternal.class),
158159
mock(AppOpsManager.class), mUm, mock(NotificationHistoryManager.class),
159-
mock(StatsManager.class), mock(TelephonyManager.class));
160+
mock(StatsManager.class), mock(TelephonyManager.class),
161+
mock(ActivityManagerInternal.class));
160162
} catch (SecurityException e) {
161163
if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
162164
throw e;

0 commit comments

Comments
 (0)