Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 33b7a223 authored by Christopher Tate's avatar Christopher Tate Committed by Automerger Merge Worker
Browse files

DO NOT MERGE - Disallow deletion of channels with FGS notifications am: 2a33098b

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/13533554

Change-Id: I2ef6e18ac31692cb083411cbac5e08eaee4fda0a
parents 32d949e4 2a33098b
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -377,6 +377,21 @@ public abstract class ActivityManagerInternal {
     */
    public abstract boolean hasRunningForegroundService(int uid, int foregroundServiceType);

    /**
     * Returns {@code true} if the given notification channel currently has a
     * notification associated with a foreground service.  This is an AMS check
     * because that is the source of truth for the FGS state.
     */
    public abstract boolean hasForegroundServiceNotification(String pkg, @UserIdInt int userId,
            String channelId);

    /**
     * If the given app has any FGSs whose notifications are in the given channel,
     * stop them.
     */
    public abstract void stopForegroundServicesForChannel(String pkg, @UserIdInt int userId,
            String channelId);

    /**
     * Registers the specified {@code processObserver} to be notified of future changes to
     * process state.
+40 −0
Original line number Diff line number Diff line
@@ -119,6 +119,7 @@ import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.function.Predicate;

@@ -433,6 +434,45 @@ public final class ActiveServices {
        return smap != null ? smap.mStartingBackground.size() >= mMaxStartingBackground : false;
    }

    boolean hasForegroundServiceNotificationLocked(String pkg, int userId, String channelId) {
        final ServiceMap smap = mServiceMap.get(userId);
        if (smap != null) {
            for (int i = 0; i < smap.mServicesByInstanceName.size(); i++) {
                final ServiceRecord sr = smap.mServicesByInstanceName.valueAt(i);
                if (sr.appInfo.packageName.equals(pkg) && sr.isForeground) {
                    if (Objects.equals(sr.foregroundNoti.getChannelId(), channelId)) {
                        if (DEBUG_FOREGROUND_SERVICE) {
                            Slog.d(TAG_SERVICE, "Channel u" + userId + "/pkg=" + pkg
                                    + "/channelId=" + channelId
                                    + " has fg service notification");
                        }
                        return true;
                    }
                }
            }
        }
        return false;
    }

    void stopForegroundServicesForChannelLocked(String pkg, int userId, String channelId) {
        final ServiceMap smap = mServiceMap.get(userId);
        if (smap != null) {
            for (int i = 0; i < smap.mServicesByInstanceName.size(); i++) {
                final ServiceRecord sr = smap.mServicesByInstanceName.valueAt(i);
                if (sr.appInfo.packageName.equals(pkg) && sr.isForeground) {
                    if (Objects.equals(sr.foregroundNoti.getChannelId(), channelId)) {
                        if (DEBUG_FOREGROUND_SERVICE) {
                            Slog.d(TAG_SERVICE, "Stopping FGS u" + userId + "/pkg=" + pkg
                                    + "/channelId=" + channelId
                                    + " for conversation channel clear");
                        }
                        stopServiceLocked(sr);
                    }
                }
            }
        }
    }

    private ServiceMap getServiceMapLocked(int callingUser) {
        ServiceMap smap = mServiceMap.get(callingUser);
        if (smap == null) {
+16 −0
Original line number Diff line number Diff line
@@ -19900,6 +19900,22 @@ public class ActivityManagerService extends IActivityManager.Stub
            return false;
        }
        @Override
        public boolean hasForegroundServiceNotification(String pkg, int userId,
                String channelId) {
            synchronized (ActivityManagerService.this) {
                return mServices.hasForegroundServiceNotificationLocked(pkg, userId, channelId);
            }
        }
        @Override
        public void stopForegroundServicesForChannel(String pkg, int userId,
                String channelId) {
            synchronized (ActivityManagerService.this) {
                mServices.stopForegroundServicesForChannelLocked(pkg, userId, channelId);
            }
        }
        @Override
        public void registerProcessObserver(IProcessObserver processObserver) {
            ActivityManagerService.this.registerProcessObserver(processObserver);
+38 −9
Original line number Diff line number Diff line
@@ -403,6 +403,7 @@ public class NotificationManagerService extends SystemService {
    private IActivityManager mAm;
    private ActivityTaskManagerInternal mAtm;
    private ActivityManager mActivityManager;
    private ActivityManagerInternal mAmi;
    private IPackageManager mPackageManager;
    private PackageManager mPackageManagerClient;
    AudioManager mAudioManager;
@@ -1876,7 +1877,7 @@ public class NotificationManagerService extends SystemService {
            DevicePolicyManagerInternal dpm, IUriGrantsManager ugm,
            UriGrantsManagerInternal ugmInternal, AppOpsManager appOps, UserManager userManager,
            NotificationHistoryManager historyManager, StatsManager statsManager,
            TelephonyManager telephonyManager) {
            TelephonyManager telephonyManager, ActivityManagerInternal ami) {
        mHandler = handler;
        Resources resources = getContext().getResources();
        mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
@@ -1897,6 +1898,7 @@ public class NotificationManagerService extends SystemService {
        mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
        mCompanionManager = companionManager;
        mActivityManager = activityManager;
        mAmi = ami;
        mDeviceIdleController = IDeviceIdleController.Stub.asInterface(
                ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
        mDpm = dpm;
@@ -2119,7 +2121,8 @@ public class NotificationManagerService extends SystemService {
                new NotificationHistoryManager(getContext(), handler),
                mStatsManager = (StatsManager) getContext().getSystemService(
                        Context.STATS_MANAGER),
                getContext().getSystemService(TelephonyManager.class));
                getContext().getSystemService(TelephonyManager.class),
                LocalServices.getService(ActivityManagerInternal.class));

        // register for various Intents
        IntentFilter filter = new IntentFilter();
@@ -3405,15 +3408,30 @@ public class NotificationManagerService extends SystemService {
                    pkg, uid, channelId, conversationId, true, includeDeleted);
        }

        // Returns 'true' if the given channel has a notification associated
        // with an active foreground service.
        private void enforceDeletingChannelHasNoFgService(String pkg, int userId,
                String channelId) {
            if (mAmi.hasForegroundServiceNotification(pkg, userId, channelId)) {
                Slog.w(TAG, "Package u" + userId + "/" + pkg
                        + " may not delete notification channel '"
                        + channelId + "' with fg service");
                throw new SecurityException("Not allowed to delete channel " + channelId
                        + " with a foreground service");
            }
        }

        @Override
        public void deleteNotificationChannel(String pkg, String channelId) {
            checkCallerIsSystemOrSameApp(pkg);
            final int callingUid = Binder.getCallingUid();
            final int callingUser = UserHandle.getUserId(callingUid);
            if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
                throw new IllegalArgumentException("Cannot delete default channel");
            }
            enforceDeletingChannelHasNoFgService(pkg, callingUser, channelId);
            cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true,
                    UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null);
                    callingUser, REASON_CHANNEL_BANNED, null);
            mPreferencesHelper.deleteNotificationChannel(pkg, callingUid, channelId);
            mListeners.notifyNotificationChannelChanged(pkg,
                    UserHandle.getUserHandleForUid(callingUid),
@@ -3426,19 +3444,23 @@ public class NotificationManagerService extends SystemService {
        public void deleteConversationNotificationChannels(String pkg, int uid,
                String conversationId) {
            checkCallerIsSystem();
            final int callingUid = Binder.getCallingUid();
            List<NotificationChannel> channels =
                    mPreferencesHelper.getNotificationChannelsByConversationId(
                            pkg, uid, conversationId);
            if (!channels.isEmpty()) {
                // Preflight for fg service notifications in these channels:  do nothing
                // unless they're all eligible
                final int appUserId = UserHandle.getUserId(uid);
                for (NotificationChannel nc : channels) {
                    final String channelId = nc.getId();
                    mAmi.stopForegroundServicesForChannel(pkg, appUserId, channelId);
                    cancelAllNotificationsInt(MY_UID, MY_PID, pkg, nc.getId(), 0, 0, true,
                            UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null);
                    mPreferencesHelper.deleteNotificationChannel(pkg, callingUid, nc.getId());
                            appUserId, REASON_CHANNEL_BANNED, null);
                    mPreferencesHelper.deleteNotificationChannel(pkg, uid, channelId);
                    mListeners.notifyNotificationChannelChanged(pkg,
                            UserHandle.getUserHandleForUid(callingUid),
                            UserHandle.getUserHandleForUid(uid),
                            mPreferencesHelper.getNotificationChannel(
                                    pkg, callingUid, nc.getId(), true),
                                    pkg, uid, channelId, true),
                            NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
                }
                handleSavePolicyFile();
@@ -3469,13 +3491,20 @@ public class NotificationManagerService extends SystemService {
            NotificationChannelGroup groupToDelete =
                    mPreferencesHelper.getNotificationChannelGroup(groupId, pkg, callingUid);
            if (groupToDelete != null) {
                // Preflight for allowability
                final int userId = UserHandle.getUserId(callingUid);
                List<NotificationChannel> groupChannels = groupToDelete.getChannels();
                for (int i = 0; i < groupChannels.size(); i++) {
                    enforceDeletingChannelHasNoFgService(pkg, userId,
                            groupChannels.get(i).getId());
                }
                List<NotificationChannel> deletedChannels =
                        mPreferencesHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId);
                for (int i = 0; i < deletedChannels.size(); i++) {
                    final NotificationChannel deletedChannel = deletedChannels.get(i);
                    cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0,
                            true,
                            UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
                            userId, REASON_CHANNEL_BANNED,
                            null);
                    mListeners.notifyNotificationChannelChanged(pkg,
                            UserHandle.getUserHandleForUid(callingUid),
+2 −1
Original line number Diff line number Diff line
@@ -505,7 +505,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
                mGroupHelper, mAm, mAtm, mAppUsageStats,
                mock(DevicePolicyManagerInternal.class), mUgm, mUgmInternal,
                mAppOpsManager, mUm, mHistoryManager, mStatsManager,
                mock(TelephonyManager.class));
                mock(TelephonyManager.class),
                mock(ActivityManagerInternal.class));
        mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);

        mService.setAudioManager(mAudioManager);
Loading