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

Commit 5e51aa6b authored by Nino Jagar's avatar Nino Jagar Committed by Android (Google) Code Review
Browse files

Merge "Add a reset mechanism into content protection processor" into udc-qpr-dev

parents 7ac68504 810ddb5e
Loading
Loading
Loading
Loading
+26 −0
Original line number Original line Diff line number Diff line
@@ -75,6 +75,8 @@ public class ContentProtectionEventProcessor {
                                    ContentCaptureEvent.TYPE_VIEW_DISAPPEARED,
                                    ContentCaptureEvent.TYPE_VIEW_DISAPPEARED,
                                    ContentCaptureEvent.TYPE_VIEW_TEXT_CHANGED)));
                                    ContentCaptureEvent.TYPE_VIEW_TEXT_CHANGED)));


    private static final int RESET_LOGIN_TOTAL_EVENTS_TO_PROCESS = 150;

    @NonNull private final RingBuffer<ContentCaptureEvent> mEventBuffer;
    @NonNull private final RingBuffer<ContentCaptureEvent> mEventBuffer;


    @NonNull private final Handler mHandler;
    @NonNull private final Handler mHandler;
@@ -93,6 +95,8 @@ public class ContentProtectionEventProcessor {
    @Nullable
    @Nullable
    public Instant mLastFlushTime;
    public Instant mLastFlushTime;


    private int mResetLoginRemainingEventsToProcess;

    public ContentProtectionEventProcessor(
    public ContentProtectionEventProcessor(
            @NonNull RingBuffer<ContentCaptureEvent> eventBuffer,
            @NonNull RingBuffer<ContentCaptureEvent> eventBuffer,
            @NonNull Handler handler,
            @NonNull Handler handler,
@@ -130,6 +134,8 @@ public class ContentProtectionEventProcessor {
        mSuspiciousTextDetected |= isSuspiciousText(event);
        mSuspiciousTextDetected |= isSuspiciousText(event);
        if (mPasswordFieldDetected && mSuspiciousTextDetected) {
        if (mPasswordFieldDetected && mSuspiciousTextDetected) {
            loginDetected();
            loginDetected();
        } else {
            maybeResetLoginFlags();
        }
        }
    }
    }


@@ -139,8 +145,28 @@ public class ContentProtectionEventProcessor {
                || Instant.now().isAfter(mLastFlushTime.plus(MIN_DURATION_BETWEEN_FLUSHING))) {
                || Instant.now().isAfter(mLastFlushTime.plus(MIN_DURATION_BETWEEN_FLUSHING))) {
            flush();
            flush();
        }
        }
        resetLoginFlags();
    }

    @UiThread
    private void resetLoginFlags() {
        mPasswordFieldDetected = false;
        mPasswordFieldDetected = false;
        mSuspiciousTextDetected = false;
        mSuspiciousTextDetected = false;
        mResetLoginRemainingEventsToProcess = 0;
    }

    @UiThread
    private void maybeResetLoginFlags() {
        if (mPasswordFieldDetected || mSuspiciousTextDetected) {
            if (mResetLoginRemainingEventsToProcess <= 0) {
                mResetLoginRemainingEventsToProcess = RESET_LOGIN_TOTAL_EVENTS_TO_PROCESS;
            } else {
                mResetLoginRemainingEventsToProcess--;
                if (mResetLoginRemainingEventsToProcess <= 0) {
                    resetLoginFlags();
                }
            }
        }
    }
    }


    @UiThread
    @UiThread
+52 −0
Original line number Original line Diff line number Diff line
@@ -91,6 +91,8 @@ public class ContentProtectionEventProcessorTest {
    private static final Set<Integer> EVENT_TYPES_TO_STORE =
    private static final Set<Integer> EVENT_TYPES_TO_STORE =
            ImmutableSet.of(TYPE_VIEW_APPEARED, TYPE_VIEW_DISAPPEARED, TYPE_VIEW_TEXT_CHANGED);
            ImmutableSet.of(TYPE_VIEW_APPEARED, TYPE_VIEW_DISAPPEARED, TYPE_VIEW_TEXT_CHANGED);


    private static final int RESET_LOGIN_TOTAL_EVENTS_TO_PROCESS = 150;

    @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
    @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();


    @Mock private RingBuffer<ContentCaptureEvent> mMockEventBuffer;
    @Mock private RingBuffer<ContentCaptureEvent> mMockEventBuffer;
@@ -231,6 +233,56 @@ public class ContentProtectionEventProcessorTest {
        verifyZeroInteractions(mMockContentCaptureManager);
        verifyZeroInteractions(mMockContentCaptureManager);
    }
    }


    @Test
    public void processEvent_loginDetected_belowResetLimit() throws Exception {
        when(mMockEventBuffer.toArray()).thenReturn(BUFFERED_EVENTS);
        mContentProtectionEventProcessor.mSuspiciousTextDetected = true;
        ContentCaptureEvent event =
                createAndroidPasswordFieldEvent(
                        ANDROID_CLASS_NAME, InputType.TYPE_TEXT_VARIATION_PASSWORD);

        for (int i = 0; i < RESET_LOGIN_TOTAL_EVENTS_TO_PROCESS; i++) {
            mContentProtectionEventProcessor.processEvent(PROCESS_EVENT);
        }

        assertThat(mContentProtectionEventProcessor.mPasswordFieldDetected).isFalse();
        assertThat(mContentProtectionEventProcessor.mSuspiciousTextDetected).isTrue();
        verify(mMockEventBuffer, never()).clear();
        verify(mMockEventBuffer, never()).toArray();

        mContentProtectionEventProcessor.processEvent(event);

        assertThat(mContentProtectionEventProcessor.mPasswordFieldDetected).isFalse();
        assertThat(mContentProtectionEventProcessor.mSuspiciousTextDetected).isFalse();
        verify(mMockEventBuffer).clear();
        verify(mMockEventBuffer).toArray();
        assertOnLoginDetected();
    }

    @Test
    public void processEvent_loginDetected_aboveResetLimit() throws Exception {
        mContentProtectionEventProcessor.mSuspiciousTextDetected = true;
        ContentCaptureEvent event =
                createAndroidPasswordFieldEvent(
                        ANDROID_CLASS_NAME, InputType.TYPE_TEXT_VARIATION_PASSWORD);

        for (int i = 0; i < RESET_LOGIN_TOTAL_EVENTS_TO_PROCESS + 1; i++) {
            mContentProtectionEventProcessor.processEvent(PROCESS_EVENT);
        }

        assertThat(mContentProtectionEventProcessor.mPasswordFieldDetected).isFalse();
        assertThat(mContentProtectionEventProcessor.mSuspiciousTextDetected).isFalse();
        verify(mMockEventBuffer, never()).clear();
        verify(mMockEventBuffer, never()).toArray();

        mContentProtectionEventProcessor.processEvent(event);

        assertThat(mContentProtectionEventProcessor.mPasswordFieldDetected).isTrue();
        assertThat(mContentProtectionEventProcessor.mSuspiciousTextDetected).isFalse();
        verify(mMockEventBuffer, never()).clear();
        verify(mMockEventBuffer, never()).toArray();
    }

    @Test
    @Test
    public void processEvent_multipleLoginsDetected_belowFlushThreshold() throws Exception {
    public void processEvent_multipleLoginsDetected_belowFlushThreshold() throws Exception {
        when(mMockEventBuffer.toArray()).thenReturn(BUFFERED_EVENTS);
        when(mMockEventBuffer.toArray()).thenReturn(BUFFERED_EVENTS);