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

Commit 08609460 authored by Bryce Lee's avatar Bryce Lee
Browse files

Check condition presence before updating callbacks.

It is possible that a condition is removed on an execution loop with a
subsequent update callback for that condition queued. This changelist
checks the presence of the condition's callbacks before proceeding to
update them.

Fixes: 237362971
Test: atest ConditionMonitorTest#testUpdateRemovedCallback
Change-Id: If2e4fcc8ff82f51134d91434ad7f2043f531ae77
parent de145197
Loading
Loading
Loading
Loading
+9 −1
Original line number Diff line number Diff line
@@ -92,7 +92,15 @@ public class Monitor {
    }

    private void updateConditionMetState(Condition condition) {
        mConditions.get(condition).stream().forEach(token -> mSubscriptions.get(token).update());
        final ArraySet<Subscription.Token> subscriptions = mConditions.get(condition);

        // It's possible the condition was removed between the time the callback occurred and
        // update was executed on the main thread.
        if (subscriptions == null) {
            return;
        }

        subscriptions.stream().forEach(token -> mSubscriptions.get(token).update());
    }

    /**
+18 −0
Original line number Diff line number Diff line
@@ -159,6 +159,24 @@ public class ConditionMonitorTest extends SysuiTestCase {
        Mockito.clearInvocations(callback);
    }

    // Ensure that updating a callback that is removed doesn't result in an exception due to the
    // absence of the condition.
    @Test
    public void testUpdateRemovedCallback() {
        final Monitor.Callback callback1 =
                mock(Monitor.Callback.class);
        final Monitor.Subscription.Token subscription1 =
                mConditionMonitor.addSubscription(getDefaultBuilder(callback1).build());
        ArgumentCaptor<Condition.Callback> monitorCallback =
                ArgumentCaptor.forClass(Condition.Callback.class);
        mExecutor.runAllReady();
        verify(mCondition1).addCallback(monitorCallback.capture());
        // This will execute first before the handler for onConditionChanged.
        mConditionMonitor.removeSubscription(subscription1);
        monitorCallback.getValue().onConditionChanged(mCondition1);
        mExecutor.runAllReady();
    }

    @Test
    public void addCallback_addFirstCallback_addCallbackToAllConditions() {
        final Monitor.Callback callback1 =