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

Commit 37f47916 authored by Hui Yu's avatar Hui Yu
Browse files

Add a flag byForegroundService to enqueueNotification() call.

This flag is passed to NotificationManagerService, the CallStyle check
will treat byForegroundService flag same as isFgs flag.

Only the ServiceRecord.postNotification() call at startForeground() call has
byForegroundService flag set to true.

Add a test case NotificationManagerServiceTest.java#checkCallStyleNotification_allowedForByForegroundService

Bug: 280003654
Test: atest NotificationManagerServiceTest.java#checkCallStyleNotification_allowedForByForegroundService

Change-Id: Ibe30526ac0ff52e2e4fe9bc846576509cdf78236
parent e9557c25
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -2414,7 +2414,7 @@ public final class ActiveServices {
                    // Even if the service is already a FGS, we need to update the notification,
                    // so we need to call it again.
                    signalForegroundServiceObserversLocked(r);
                    r.postNotification();
                    r.postNotification(true);
                    if (r.app != null) {
                        updateServiceForegroundLocked(psr, true);
                    }
@@ -2472,7 +2472,7 @@ public final class ActiveServices {
                } else if (r.appInfo.targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {
                    // if it's been deferred, force to visibility
                    if (!r.mFgsNotificationShown) {
                        r.postNotification();
                        r.postNotification(false);
                    }
                    dropFgsNotificationStateLocked(r);
                    if ((flags & Service.STOP_FOREGROUND_DETACH) != 0) {
@@ -2916,7 +2916,7 @@ public final class ActiveServices {
                        // in the interval, so we lazy check whether we still need to show
                        // the notification.
                        if (r.isForeground && r.app != null) {
                            r.postNotification();
                            r.postNotification(true);
                            r.mFgsNotificationShown = true;
                        } else {
                            if (DEBUG_FOREGROUND_SERVICE) {
@@ -5338,7 +5338,7 @@ public final class ActiveServices {
            thread.scheduleCreateService(r, r.serviceInfo,
                    null /* compatInfo (unused but need to keep method signature) */,
                    app.mState.getReportedProcState());
            r.postNotification();
            r.postNotification(false);
            created = true;
        } catch (DeadObjectException e) {
            Slog.w(TAG, "Application dead when creating service " + r);
+2 −2
Original line number Diff line number Diff line
@@ -1324,7 +1324,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
        });
    }

    public void postNotification() {
    public void postNotification(boolean byForegroundService) {
        if (isForeground && foregroundNoti != null && app != null) {
            final int appUid = appInfo.uid;
            final int appPid = app.getPid();
@@ -1432,7 +1432,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
                        }
                        nm.enqueueNotification(localPackageName, localPackageName,
                                appUid, appPid, null, localForegroundId, localForegroundNoti,
                                userId);
                                userId, byForegroundService /* byForegroundService */);

                        foregroundNoti = localForegroundNoti; // save it for amending next time

+3 −0
Original line number Diff line number Diff line
@@ -27,6 +27,9 @@ public interface NotificationManagerInternal {
    NotificationChannelGroup getNotificationChannelGroup(String pkg, int uid, String channelId);
    void enqueueNotification(String pkg, String basePkg, int callingUid, int callingPid,
            String tag, int id, Notification notification, int userId);
    void enqueueNotification(String pkg, String basePkg, int callingUid, int callingPid,
            String tag, int id, Notification notification, int userId,
            boolean byForegroundService);
    void cancelNotification(String pkg, String basePkg, int callingUid, int callingPid,
            String tag, int id, int userId);

+24 −13
Original line number Diff line number Diff line
@@ -2531,7 +2531,8 @@ public class NotificationManagerService extends SystemService {
                }
                enqueueNotificationInternal(r.getSbn().getPackageName(), r.getSbn().getOpPkg(),
                        r.getSbn().getUid(), r.getSbn().getInitialPid(), r.getSbn().getTag(),
                        r.getSbn().getId(),  r.getSbn().getNotification(), userId, muteOnReturn);
                        r.getSbn().getId(),  r.getSbn().getNotification(), userId, muteOnReturn,
                        false /* byForegroundService */);
            } catch (Exception e) {
                Slog.e(TAG, "Cannot un-snooze notification", e);
            }
@@ -3521,7 +3522,8 @@ public class NotificationManagerService extends SystemService {
        public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
                Notification notification, int userId) throws RemoteException {
            enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
                    Binder.getCallingPid(), tag, id, notification, userId);
                    Binder.getCallingPid(), tag, id, notification, userId,
                    false /* byForegroundService */);
        }
        @Override
@@ -6089,7 +6091,7 @@ public class NotificationManagerService extends SystemService {
            }
            if (summaryRecord != null && checkDisqualifyingFeatures(userId, uid,
                    summaryRecord.getSbn().getId(), summaryRecord.getSbn().getTag(), summaryRecord,
                    true)) {
                    true, false)) {
                return summaryRecord;
            }
        }
@@ -6418,7 +6420,15 @@ public class NotificationManagerService extends SystemService {
        public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
                String tag, int id, Notification notification, int userId) {
            enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
                    userId);
                    userId, false /* byForegroundService */);
        }
        @Override
        public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
                String tag, int id, Notification notification, int userId,
                boolean byForegroundService) {
            enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
                    userId, byForegroundService);
        }
        @Override
@@ -6596,19 +6606,19 @@ public class NotificationManagerService extends SystemService {
    void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
            final int callingPid, final String tag, final int id, final Notification notification,
            int incomingUserId) {
            int incomingUserId, boolean byForegroundService) {
        enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
                incomingUserId, false);
                incomingUserId, false /* postSilently */, byForegroundService);
    }
    void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
            final int callingPid, final String tag, final int id, final Notification notification,
            int incomingUserId, boolean postSilently) {
            int incomingUserId, boolean postSilently, boolean byForegroundService) {
        PostNotificationTracker tracker = acquireWakeLockForPost(pkg, callingUid);
        boolean enqueued = false;
        try {
            enqueued = enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id,
                    notification, incomingUserId, postSilently, tracker);
                    notification, incomingUserId, postSilently, tracker, byForegroundService);
        } finally {
            if (!enqueued) {
                tracker.cancel();
@@ -6639,10 +6649,10 @@ public class NotificationManagerService extends SystemService {
     * @return True if we successfully processed the notification and handed off the task of
     * enqueueing it to a background thread; false otherwise.
     */
    private boolean enqueueNotificationInternal(final String pkg, final String opPkg,
    private boolean enqueueNotificationInternal(final String pkg, final String opPkg,  //HUI
            final int callingUid, final int callingPid, final String tag, final int id,
            final Notification notification, int incomingUserId, boolean postSilently,
            PostNotificationTracker tracker) {
            PostNotificationTracker tracker, boolean byForegroundService) {
        if (DBG) {
            Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
                    + " notification=" + notification);
@@ -6788,7 +6798,7 @@ public class NotificationManagerService extends SystemService {
                mPreferencesHelper.hasUserDemotedInvalidMsgApp(pkg, notificationUid));
        if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,
                r.getSbn().getOverrideGroupKey() != null)) {
                r.getSbn().getOverrideGroupKey() != null, byForegroundService)) {
            return false;
        }
@@ -7208,7 +7218,7 @@ public class NotificationManagerService extends SystemService {
     * Has side effects.
     */
    boolean checkDisqualifyingFeatures(int userId, int uid, int id, String tag,
            NotificationRecord r, boolean isAutogroup) {
            NotificationRecord r, boolean isAutogroup, boolean byForegroundService) {
        Notification n = r.getNotification();
        final String pkg = r.getSbn().getPackageName();
        final boolean isSystemNotification =
@@ -7299,7 +7309,8 @@ public class NotificationManagerService extends SystemService {
        if (n.isStyle(Notification.CallStyle.class)) {
            boolean hasFullScreenIntent = n.fullScreenIntent != null;
            boolean requestedFullScreenIntent = (n.flags & FLAG_FSI_REQUESTED_BUT_DENIED) != 0;
            if (!n.isFgsOrUij() && !hasFullScreenIntent && !requestedFullScreenIntent) {
            if (!n.isFgsOrUij() && !hasFullScreenIntent && !requestedFullScreenIntent
                    && !byForegroundService) {
                throw new IllegalArgumentException(r.getKey() + " Not posted."
                        + " CallStyle notifications must be for a foreground service or"
                        + " user initated job or use a fullScreenIntent.");
+37 −19
Original line number Diff line number Diff line
@@ -10239,7 +10239,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        try {
            mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), r.getSbn().getId(),
                    r.getSbn().getTag(), r,false);
                    r.getSbn().getTag(), r, false, false);
            fail("Allowed a contextual direct reply with an immutable intent to be posted");
        } catch (IllegalArgumentException e) {
            // good
@@ -10270,7 +10270,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        r.applyAdjustments();
        mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), r.getSbn().getId(),
                r.getSbn().getTag(), r,false);
                r.getSbn().getTag(), r, false, false);
    }
    @Test
@@ -10304,7 +10304,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        r.applyAdjustments();
        mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), r.getSbn().getId(),
                    r.getSbn().getTag(), r,false);
                    r.getSbn().getTag(), r, false, false);
    }
    @Test
@@ -10517,7 +10517,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        // normal blocked notifications - blocked
        assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
                r.getSbn().getId(), r.getSbn().getTag(), r, false)).isFalse();
                r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse();
        // just using the style - blocked
        nb.setStyle(new Notification.MediaStyle());
@@ -10526,7 +10526,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
        assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
                r.getSbn().getId(), r.getSbn().getTag(), r, false)).isFalse();
                r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse();
        // using the style, but incorrect type in session - blocked
        nb.setStyle(new Notification.MediaStyle());
@@ -10538,7 +10538,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
        assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
                r.getSbn().getId(), r.getSbn().getTag(), r, false)).isFalse();
                r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse();
        // style + media session - bypasses block
        nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class)));
@@ -10547,7 +10547,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
        assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
                r.getSbn().getId(), r.getSbn().getTag(), r, false)).isTrue();
                r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
    }
    @Test
@@ -10630,7 +10630,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        // normal blocked notifications - blocked
        assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
                r.getSbn().getId(), r.getSbn().getTag(), r, false)).isFalse();
                r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse();
        // just using the style - blocked
        Person person = new Person.Builder()
@@ -10644,36 +10644,36 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
        assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
                r.getSbn().getId(), r.getSbn().getTag(), r, false)).isFalse();
                r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse();
        // style + managed call - bypasses block
        when(mTelecomManager.isInManagedCall()).thenReturn(true);
        assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
                r.getSbn().getId(), r.getSbn().getTag(), r, false)).isTrue();
                r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
        // style + self managed call - bypasses block
        when(mTelecomManager.isInSelfManagedCall(
                r.getSbn().getPackageName(), r.getUser())).thenReturn(true);
        assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
                r.getSbn().getId(), r.getSbn().getTag(), r, false)).isTrue();
                r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
        // set telecom manager to null - blocked
        mService.setTelecomManager(null);
        assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
                           r.getSbn().getId(), r.getSbn().getTag(), r, false))
                           r.getSbn().getId(), r.getSbn().getTag(), r, false, false))
                .isFalse();
        // set telecom feature to false - blocked
        when(mPackageManagerClient.hasSystemFeature(FEATURE_TELECOM)).thenReturn(false);
        assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
                           r.getSbn().getId(), r.getSbn().getTag(), r, false))
                           r.getSbn().getId(), r.getSbn().getTag(), r, false, false))
                .isFalse();
        // telecom manager is not ready - blocked
        mService.setTelecomManager(mTelecomManager);
        when(mTelecomManager.isInCall()).thenThrow(new IllegalStateException("not ready"));
        assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
                r.getSbn().getId(), r.getSbn().getTag(), r, false))
                r.getSbn().getId(), r.getSbn().getTag(), r, false, false))
                .isFalse();
    }
@@ -11238,7 +11238,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        try {
            mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
                    r.getSbn().getId(), r.getSbn().getTag(), r, false);
                    r.getSbn().getId(), r.getSbn().getTag(), r, false, false);
            assertFalse("CallStyle should not be allowed without a valid use case", true);
        } catch (IllegalArgumentException error) {
            assertThat(error.getMessage()).contains("CallStyle");
@@ -11258,7 +11258,25 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
        assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
                r.getSbn().getId(), r.getSbn().getTag(), r, false)).isTrue();
                r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
    }
    @Test
    public void checkCallStyleNotification_allowedForByForegroundService() throws Exception {
        Person person = new Person.Builder().setName("caller").build();
        Notification n = new Notification.Builder(mContext, "test")
                // Without FLAG_FOREGROUND_SERVICE.
                //.setFlag(FLAG_FOREGROUND_SERVICE, true)
                .setStyle(Notification.CallStyle.forOngoingCall(
                        person, mock(PendingIntent.class)))
                .build();
        StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0,
                n, UserHandle.getUserHandleForUid(mUid), null, 0);
        NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
        assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
                r.getSbn().getId(), r.getSbn().getTag(), r, false,
                true /* byForegroundService */)).isTrue();
    }
    @Test
@@ -11274,7 +11292,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
        assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
                r.getSbn().getId(), r.getSbn().getTag(), r, false)).isTrue();
                r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
    }
    @Test
@@ -11290,7 +11308,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
        assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
                r.getSbn().getId(), r.getSbn().getTag(), r, false)).isTrue();
                r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
    }
    @Test
@@ -11306,7 +11324,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
        assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
                r.getSbn().getId(), r.getSbn().getTag(), r, false)).isTrue();
                r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
    }
    @Test