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

Commit 75256717 authored by Geoffrey Pitsch's avatar Geoffrey Pitsch Committed by android-build-merger
Browse files

Merge "Fix race condition in removeForegroundServiceFlag" into oc-dev

am: f4077aa3

Change-Id: I0ba4947f1cf1c67a39333c1aff5aacc3c5131083
parents a6f3d1b7 f4077aa3
Loading
Loading
Loading
Loading
+26 −19
Original line number Diff line number Diff line
@@ -1421,6 +1421,11 @@ public class NotificationManagerService extends SystemService {
        return INotificationManager.Stub.asInterface(mService);
    }

    @VisibleForTesting
    NotificationManagerInternal getInternalService() {
        return mInternalService;
    }

    private final IBinder mService = new INotificationManager.Stub() {
        // Toasts
        // ============================================================================
@@ -2984,25 +2989,27 @@ public class NotificationManagerService extends SystemService {
                int userId) {
            checkCallerIsSystem();
            synchronized (mNotificationLock) {
                NotificationRecord r = findNotificationByListLocked(mNotificationList, pkg, null,
                        notificationId, userId);
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        NotificationRecord r =
                                findNotificationLocked(pkg, null, notificationId, userId);
                        if (r == null) {
                    Log.d(TAG, "stripForegroundServiceFlag: Could not find notification with "
                            + "pkg=" + pkg + " / id=" + notificationId + " / userId=" + userId);
                            Log.d(TAG,
                                    "stripForegroundServiceFlag: Could not find notification with "
                                    + "pkg=" + pkg + " / id=" + notificationId
                                    + " / userId=" + userId);
                            return;
                        }
                        StatusBarNotification sbn = r.sbn;
                        // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
                // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove FLAG_FOREGROUND_SERVICE,
                // we have to revert to the flags we received initially *and* force remove
                // FLAG_FOREGROUND_SERVICE.
                        // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove
                        // FLAG_FOREGROUND_SERVICE, we have to revert to the flags we received
                        // initially *and* force remove FLAG_FOREGROUND_SERVICE.
                        sbn.getNotification().flags =
                                (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
                        mRankingHelper.sort(mNotificationList);
                        mListeners.notifyPostedLocked(sbn, sbn /* oldSbn */);
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        mGroupHelper.onNotificationPosted(sbn);
                    }
                });
@@ -4425,16 +4432,16 @@ public class NotificationManagerService extends SystemService {
        }
    }

    protected static boolean isUidSystem(int uid) {
    protected boolean isUidSystem(int uid) {
        final int appid = UserHandle.getAppId(uid);
        return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
    }

    private static boolean isCallerSystem() {
    private boolean isCallerSystem() {
        return isUidSystem(Binder.getCallingUid());
    }

    private static void checkCallerIsSystem() {
    protected void checkCallerIsSystem() {
        if (isCallerSystem()) {
            return;
        }
+2 −1
Original line number Diff line number Diff line
@@ -23,7 +23,8 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
    guava \
    android-support-test \
    mockito-target-minus-junit4 \
    platform-test-annotations
    platform-test-annotations \
    testables

LOCAL_JAVA_LIBRARIES := android.test.runner

+32 −22
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.support.test.annotation.UiThreadTest;
import android.support.test.InstrumentationRegistry;
import android.testing.TestableLooper;

import java.util.Arrays;
import java.util.concurrent.CountDownLatch;
@@ -64,20 +65,29 @@ public class NotificationManagerServiceTest {
    private final int uid = Binder.getCallingUid();
    private NotificationManagerService mNotificationManagerService;
    private INotificationManager mBinderService;
    private NotificationManagerInternal mInternalService;
    private IPackageManager mPackageManager = mock(IPackageManager.class);
    private final PackageManager mPackageManagerClient = mock(PackageManager.class);
    private Context mContext = InstrumentationRegistry.getTargetContext();
    private final String PKG = mContext.getPackageName();
    private HandlerThread mThread;
    private TestableLooper mTestableLooper;
    private final RankingHelper mRankingHelper = mock(RankingHelper.class);
    private NotificationChannel mTestNotificationChannel = new NotificationChannel(
            TEST_CHANNEL_ID, TEST_CHANNEL_ID, NotificationManager.IMPORTANCE_DEFAULT);

    // Use a Testable subclass so we can simulate calls from the system without failing.
    private static class TestableNotificationManagerService extends NotificationManagerService {
        public TestableNotificationManagerService(Context context) { super(context); }

        @Override
        protected void checkCallerIsSystem() {}
    }

    @Before
    @Test
    @UiThreadTest
    public void setUp() throws Exception {
        mNotificationManagerService = new NotificationManagerService(mContext);
        mNotificationManagerService = new TestableNotificationManagerService(mContext);

        // MockPackageManager - default returns ApplicationInfo with matching calling UID
        final ApplicationInfo applicationInfo = new ApplicationInfo();
@@ -88,9 +98,8 @@ public class NotificationManagerServiceTest {
                .thenReturn(applicationInfo);
        final LightsManager mockLightsManager = mock(LightsManager.class);
        when(mockLightsManager.getLight(anyInt())).thenReturn(mock(Light.class));
        // Use a separate thread for service looper.
        mThread = new HandlerThread("TestThread");
        mThread.start();
        // Use this testable looper.
        mTestableLooper = new TestableLooper(false);
        // Mock NotificationListeners to bypass security checks.
        final NotificationManagerService.NotificationListeners mockNotificationListeners =
                mock(NotificationManagerService.NotificationListeners.class);
@@ -98,32 +107,19 @@ public class NotificationManagerServiceTest {
                mockNotificationListeners.new ManagedServiceInfo(null,
                        new ComponentName(PKG, "test_class"), uid, true, null, 0));

        mNotificationManagerService.init(mThread.getLooper(), mPackageManager,
        mNotificationManagerService.init(mTestableLooper.getLooper(), mPackageManager,
                mPackageManagerClient, mockLightsManager, mockNotificationListeners);

        // Tests call directly into the Binder.
        mBinderService = mNotificationManagerService.getBinderService();
        mInternalService = mNotificationManagerService.getInternalService();

        mBinderService.createNotificationChannels(
                PKG, new ParceledListSlice(Arrays.asList(mTestNotificationChannel)));
    }

    public void waitForIdle() throws Exception {
        MessageQueue queue = mThread.getLooper().getQueue();
        if (queue.isIdle()) {
            return;
        }
        CountDownLatch latch = new CountDownLatch(1);
        queue.addIdleHandler(new MessageQueue.IdleHandler() {
                @Override public boolean queueIdle() {
                    latch.countDown();
                    return false;
                }
        });
        // Timeout is valid in the cases where the queue goes idle before the IdleHandler
        // is added.
        latch.await(WAIT_FOR_IDLE_TIMEOUT, TimeUnit.SECONDS);
        waitForIdle();
        mTestableLooper.processAllMessages();
    }

    private NotificationRecord generateNotificationRecord(NotificationChannel channel) {
@@ -260,7 +256,6 @@ public class NotificationManagerServiceTest {

    @Test
    @UiThreadTest
    @Ignore("Flaky")
    public void testEnqueueNotificationWithTag_PopulatesGetActiveNotifications() throws Exception {
        mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
                generateNotificationRecord(null).getNotification(), new int[1], 0);
@@ -378,6 +373,21 @@ public class NotificationManagerServiceTest {
        assertEquals(1, notifs.length);
    }

    @Test
    @UiThreadTest
    public void testRemoveForegroundServiceFlag_ImmediatelyAfterEnqueue() throws Exception {
        final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
        sbn.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
        mBinderService.enqueueNotificationWithTag(PKG, "opPkg", null,
                sbn.getId(), sbn.getNotification(), new int[1], sbn.getUserId());
        mInternalService.removeForegroundServiceFlagFromNotification(PKG, sbn.getId(),
                sbn.getUserId());
        waitForIdle();
        StatusBarNotification[] notifs =
                mBinderService.getActiveNotifications(sbn.getPackageName());
        assertEquals(0, notifs[0].getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE);
    }

    @Test
    @UiThreadTest
    public void testTvExtenderChannelOverride_onTv() throws Exception {