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

Commit 5bc6a51a authored by MingWei's avatar MingWei
Browse files

Set upper limit of process queue in MainContentCaptureSessionV2

To prevent view events starting accumulated in the process queue, an
upper limit must be provided. This should address a potential memory
usage issue when no FORCE_FLUSH signal is presented for a while.

Test: MainContentCaptureSessionV2, CtsContentCaptureServiceTestCases
Bug: 309411951

Change-Id: I9054cdfb50212550a87b5e52b7706462a53e97fe
parent 6538db51
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -149,9 +149,12 @@ public final class MainContentCaptureSessionV2 extends ContentCaptureSession {
     *
     * Because it is not guaranteed that the events will be enqueued from a single thread, the
     * implementation must be thread-safe to prevent unexpected behaviour.
     *
     * @hide
     */
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
    @NonNull
    private final ConcurrentLinkedQueue<ContentCaptureEvent> mEventProcessQueue;
    public final ConcurrentLinkedQueue<ContentCaptureEvent> mEventProcessQueue;

    /**
     * List of events held to be sent to the {@link ContentCaptureService} as a batch.
@@ -908,7 +911,7 @@ public final class MainContentCaptureSessionV2 extends ContentCaptureSession {
     * clear the buffer events then starting sending out current event.
     */
    private void enqueueEvent(@NonNull final ContentCaptureEvent event, boolean forceFlush) {
        if (forceFlush) {
        if (forceFlush || mEventProcessQueue.size() >= mManager.mOptions.maxBufferSize - 1) {
            // The buffer events are cleared in the same thread first to prevent new events
            // being added during the time of context switch. This would disrupt the sequence
            // of events.
+66 −0
Original line number Diff line number Diff line
@@ -433,6 +433,72 @@ public class MainContentCaptureSessionV2Test {
        assertThat(session.mEvents).isEmpty();
    }

    @Test
    public void notifyViewAppearedBelowMaximumBufferSize() throws RemoteException {
        ContentCaptureOptions options =
                createOptions(
                        /* enableContentCaptureReceiver= */ true,
                        /* enableContentProtectionReceiver= */ true);
        MainContentCaptureSessionV2 session = createSession(options);
        session.mDirectServiceInterface = mMockContentCaptureDirectManager;

        session.onSessionStarted(0x2, null);
        for (int i = 0; i < BUFFER_SIZE - 1; i++) {
            View view = prepareView(session);
            session.notifyViewAppeared(session.newViewStructure(view));
        }
        mTestableLooper.processAllMessages();

        verify(mMockContentCaptureDirectManager, times(0))
                .sendEvents(any(), anyInt(), any());
        assertThat(session.mEvents).isNull();
        assertThat(session.mEventProcessQueue).hasSize(BUFFER_SIZE - 1);
    }

    @Test
    public void notifyViewAppearedExactAsMaximumBufferSize() throws RemoteException {
        ContentCaptureOptions options =
                createOptions(
                        /* enableContentCaptureReceiver= */ true,
                        /* enableContentProtectionReceiver= */ true);
        MainContentCaptureSessionV2 session = createSession(options);
        session.mDirectServiceInterface = mMockContentCaptureDirectManager;

        session.onSessionStarted(0x2, null);
        for (int i = 0; i < BUFFER_SIZE; i++) {
            View view = prepareView(session);
            session.notifyViewAppeared(session.newViewStructure(view));
        }
        mTestableLooper.processAllMessages();

        verify(mMockContentCaptureDirectManager, times(1))
                .sendEvents(any(), anyInt(), any());
        assertThat(session.mEvents).isEmpty();
        assertThat(session.mEventProcessQueue).isEmpty();
    }

    @Test
    public void notifyViewAppearedAboveMaximumBufferSize() throws RemoteException {
        ContentCaptureOptions options =
                createOptions(
                        /* enableContentCaptureReceiver= */ true,
                        /* enableContentProtectionReceiver= */ true);
        MainContentCaptureSessionV2 session = createSession(options);
        session.mDirectServiceInterface = mMockContentCaptureDirectManager;

        session.onSessionStarted(0x2, null);
        for (int i = 0; i < BUFFER_SIZE * 2 + 1; i++) {
            View view = prepareView(session);
            session.notifyViewAppeared(session.newViewStructure(view));
        }
        mTestableLooper.processAllMessages();

        verify(mMockContentCaptureDirectManager, times(2))
                .sendEvents(any(), anyInt(), any());
        assertThat(session.mEvents).isEmpty();
        assertThat(session.mEventProcessQueue).hasSize(1);
    }

    /** Simulates the regular content capture events sequence. */
    private void notifyContentCaptureEvents(final MainContentCaptureSessionV2 session) {
        final ArrayList<Object> events = new ArrayList<>(