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

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

Merge "Call the update API for content protection allowlist" into main

parents 998a9627 95a7d157
Loading
Loading
Loading
Loading
+33 −4
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Handler;
import android.os.UserHandle;
import android.service.contentcapture.IContentProtectionAllowlistCallback;
import android.util.Slog;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -52,6 +54,10 @@ public class ContentProtectionAllowlistManager {
    @NonNull
    final PackageMonitor mPackageMonitor;

    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
    @NonNull
    final IContentProtectionAllowlistCallback mAllowlistCallback;

    private final Object mHandlerToken = new Object();

    private final Object mLock = new Object();
@@ -74,6 +80,7 @@ public class ContentProtectionAllowlistManager {
        mHandler = handler;
        mTimeoutMs = timeoutMs;
        mPackageMonitor = createPackageMonitor();
        mAllowlistCallback = createAllowlistCallback();
    }

    /** Starts the manager. */
@@ -107,7 +114,7 @@ public class ContentProtectionAllowlistManager {
        return allowedPackages.contains(packageName);
    }

    private void setAllowlist(@NonNull List<String> packages) {
    private void handleUpdateAllowlistResponse(@NonNull List<String> packages) {
        synchronized (mLock) {
            mAllowedPackages = packages.stream().collect(Collectors.toUnmodifiableSet());
        }
@@ -115,14 +122,14 @@ public class ContentProtectionAllowlistManager {
    }

    private void handleInitialUpdate() {
        handleUpdate();
        handlePackagesChanged();

        // Initial update done, start listening to package updates now
        mPackageMonitor.register(
                mContentCaptureManagerService.getContext(), UserHandle.ALL, mHandler);
    }

    private void handleUpdate() {
    private void handlePackagesChanged() {
        if (!blocklistUpdateEnabled()) {
            return;
        }
@@ -145,6 +152,12 @@ public class ContentProtectionAllowlistManager {
        // If there are any pending updates queued already, they can be removed immediately
        mHandler.removeCallbacksAndMessages(mHandlerToken);
        mUpdatePendingUntil = Instant.now().plusMillis(mTimeoutMs);

        try {
            remoteContentProtectionService.onUpdateAllowlistRequest(mAllowlistCallback);
        } catch (Exception ex) {
            Slog.e(TAG, "Failed to call remote service", ex);
        }
    }

    /** @hide */
@@ -154,12 +167,28 @@ public class ContentProtectionAllowlistManager {
        return new ContentProtectionPackageMonitor();
    }

    /** @hide */
    @NonNull
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
    protected IContentProtectionAllowlistCallback createAllowlistCallback() {
        return new ContentProtectionAllowlistCallback();
    }

    private final class ContentProtectionPackageMonitor extends PackageMonitor {

        // This callback might be invoked multiple times, for more info refer to the comment above
        @Override
        public void onSomePackagesChanged() {
            handleUpdate();
            handlePackagesChanged();
        }
    }

    private final class ContentProtectionAllowlistCallback
            extends IContentProtectionAllowlistCallback.Stub {

        @Override
        public void setAllowlist(List<String> packages) {
            mHandler.post(() -> handleUpdateAllowlistResponse(packages));
        }
    }
}
+169 −24
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import android.os.Handler;
import android.os.UserHandle;
import android.os.test.TestLooper;
import android.platform.test.flag.junit.SetFlagsRule;
import android.service.contentcapture.IContentProtectionAllowlistCallback;

import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -48,6 +49,8 @@ import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;

import java.util.List;

/**
 * Test for {@link ContentProtectionAllowlistManager}.
 *
@@ -58,7 +61,9 @@ import org.mockito.junit.MockitoRule;
@SmallTest
public class ContentProtectionAllowlistManagerTest {

    private static final String PACKAGE_NAME = "com.test.package.name";
    private static final String FIRST_PACKAGE_NAME = "com.test.first.package.name";

    private static final String SECOND_PACKAGE_NAME = "com.test.second.package.name";

    private static final long TIMEOUT_MS = 111_111_111L;

@@ -74,12 +79,18 @@ public class ContentProtectionAllowlistManagerTest {

    @Mock private RemoteContentProtectionService mMockRemoteContentProtectionService;

    @Mock private IContentProtectionAllowlistCallback mMockAllowlistCallback;

    private final TestLooper mTestLooper = new TestLooper();

    private Handler mHandler;

    private ContentProtectionAllowlistManager mContentProtectionAllowlistManager;

    private boolean mUseMockPackageMonitor = true;

    private boolean mUseMockAllowlistCallback = true;

    @Before
    public void setup() {
        mHandler = new Handler(mTestLooper.getLooper());
@@ -91,6 +102,8 @@ public class ContentProtectionAllowlistManagerTest {
        assertThat(mHandler.hasMessagesOrCallbacks()).isFalse();
        verifyZeroInteractions(mMockContentCaptureManagerService);
        verifyZeroInteractions(mMockPackageMonitor);
        verifyZeroInteractions(mMockRemoteContentProtectionService);
        verifyZeroInteractions(mMockAllowlistCallback);
    }

    @Test
@@ -103,6 +116,8 @@ public class ContentProtectionAllowlistManagerTest {
        assertThat(mHandler.hasMessagesOrCallbacks()).isTrue();
        verifyZeroInteractions(mMockContentCaptureManagerService);
        verifyZeroInteractions(mMockPackageMonitor);
        verifyZeroInteractions(mMockRemoteContentProtectionService);
        verifyZeroInteractions(mMockAllowlistCallback);
    }

    @Test
@@ -117,6 +132,8 @@ public class ContentProtectionAllowlistManagerTest {
        verify(mMockContentCaptureManagerService).createRemoteContentProtectionService();
        verify(mMockPackageMonitor).register(any(), eq(UserHandle.ALL), eq(mHandler));
        verify(mMockPackageMonitor, never()).unregister();
        verifyZeroInteractions(mMockRemoteContentProtectionService);
        verifyZeroInteractions(mMockAllowlistCallback);
    }

    @Test
@@ -132,6 +149,8 @@ public class ContentProtectionAllowlistManagerTest {
        verify(mMockContentCaptureManagerService).createRemoteContentProtectionService();
        verify(mMockPackageMonitor).register(any(), eq(UserHandle.ALL), eq(mHandler));
        verify(mMockPackageMonitor, never()).unregister();
        verifyZeroInteractions(mMockRemoteContentProtectionService);
        verifyZeroInteractions(mMockAllowlistCallback);
    }

    @Test
@@ -144,6 +163,8 @@ public class ContentProtectionAllowlistManagerTest {
        assertThat(mHandler.hasMessagesOrCallbacks()).isTrue();
        verifyZeroInteractions(mMockContentCaptureManagerService);
        verifyZeroInteractions(mMockPackageMonitor);
        verifyZeroInteractions(mMockRemoteContentProtectionService);
        verifyZeroInteractions(mMockAllowlistCallback);
    }

    @Test
@@ -158,6 +179,8 @@ public class ContentProtectionAllowlistManagerTest {
        verifyZeroInteractions(mMockContentCaptureManagerService);
        verify(mMockPackageMonitor).register(any(), eq(UserHandle.ALL), eq(mHandler));
        verify(mMockPackageMonitor, never()).unregister();
        verifyZeroInteractions(mMockRemoteContentProtectionService);
        verifyZeroInteractions(mMockAllowlistCallback);
    }

    @Test
@@ -173,6 +196,8 @@ public class ContentProtectionAllowlistManagerTest {
        verifyZeroInteractions(mMockContentCaptureManagerService);
        verify(mMockPackageMonitor).register(any(), eq(UserHandle.ALL), eq(mHandler));
        verify(mMockPackageMonitor, never()).unregister();
        verifyZeroInteractions(mMockRemoteContentProtectionService);
        verifyZeroInteractions(mMockAllowlistCallback);
    }

    @Test
@@ -186,6 +211,8 @@ public class ContentProtectionAllowlistManagerTest {
        verifyZeroInteractions(mMockContentCaptureManagerService);
        verify(mMockPackageMonitor, never()).register(any(), any(), any());
        verify(mMockPackageMonitor).unregister();
        verifyZeroInteractions(mMockRemoteContentProtectionService);
        verifyZeroInteractions(mMockAllowlistCallback);
    }

    @Test
@@ -201,6 +228,8 @@ public class ContentProtectionAllowlistManagerTest {
        verifyZeroInteractions(mMockContentCaptureManagerService);
        verify(mMockPackageMonitor, never()).register(any(), any(), any());
        verify(mMockPackageMonitor).unregister();
        verifyZeroInteractions(mMockRemoteContentProtectionService);
        verifyZeroInteractions(mMockAllowlistCallback);
    }

    @Test
@@ -216,6 +245,8 @@ public class ContentProtectionAllowlistManagerTest {
        verify(mMockContentCaptureManagerService).createRemoteContentProtectionService();
        verify(mMockPackageMonitor).register(any(), eq(UserHandle.ALL), eq(mHandler));
        verify(mMockPackageMonitor).unregister();
        verifyZeroInteractions(mMockRemoteContentProtectionService);
        verifyZeroInteractions(mMockAllowlistCallback);
    }

    @Test
@@ -229,6 +260,8 @@ public class ContentProtectionAllowlistManagerTest {
        verifyZeroInteractions(mMockContentCaptureManagerService);
        verify(mMockPackageMonitor, never()).register(any(), any(), any());
        verify(mMockPackageMonitor).unregister();
        verifyZeroInteractions(mMockRemoteContentProtectionService);
        verifyZeroInteractions(mMockAllowlistCallback);
    }

    @Test
@@ -244,6 +277,8 @@ public class ContentProtectionAllowlistManagerTest {
        verifyZeroInteractions(mMockContentCaptureManagerService);
        verify(mMockPackageMonitor, never()).register(any(), any(), any());
        verify(mMockPackageMonitor).unregister();
        verifyZeroInteractions(mMockRemoteContentProtectionService);
        verifyZeroInteractions(mMockAllowlistCallback);
    }

    @Test
@@ -259,6 +294,8 @@ public class ContentProtectionAllowlistManagerTest {
        verifyZeroInteractions(mMockContentCaptureManagerService);
        verify(mMockPackageMonitor).register(any(), eq(UserHandle.ALL), eq(mHandler));
        verify(mMockPackageMonitor).unregister();
        verifyZeroInteractions(mMockRemoteContentProtectionService);
        verifyZeroInteractions(mMockAllowlistCallback);
    }

    @Test
@@ -274,6 +311,8 @@ public class ContentProtectionAllowlistManagerTest {
        assertThat(mHandler.hasMessagesOrCallbacks()).isFalse();
        verify(mMockPackageMonitor).register(any(), eq(UserHandle.ALL), eq(mHandler));
        verify(mMockPackageMonitor).unregister();
        verifyZeroInteractions(mMockRemoteContentProtectionService);
        verifyZeroInteractions(mMockAllowlistCallback);
    }

    @Test
@@ -290,60 +329,130 @@ public class ContentProtectionAllowlistManagerTest {
        assertThat(mHandler.hasMessagesOrCallbacks()).isFalse();
        verify(mMockPackageMonitor, times(2)).register(any(), eq(UserHandle.ALL), eq(mHandler));
        verify(mMockPackageMonitor).unregister();
        verifyZeroInteractions(mMockRemoteContentProtectionService);
        verifyZeroInteractions(mMockAllowlistCallback);
    }

    @Test
    public void isAllowed_default() {
        boolean actual = mContentProtectionAllowlistManager.isAllowed(FIRST_PACKAGE_NAME);

        assertThat(actual).isFalse();
        verifyZeroInteractions(mMockContentCaptureManagerService);
        verifyZeroInteractions(mMockPackageMonitor);
        verifyZeroInteractions(mMockRemoteContentProtectionService);
        verifyZeroInteractions(mMockAllowlistCallback);
    }

    @Test
    public void isAllowed() {
        boolean actual = mContentProtectionAllowlistManager.isAllowed(PACKAGE_NAME);
    public void isAllowed_false() throws Exception {
        mUseMockAllowlistCallback = false;
        ContentProtectionAllowlistManager manager = new TestContentProtectionAllowlistManager();
        manager.mAllowlistCallback.setAllowlist(List.of(FIRST_PACKAGE_NAME));
        mTestLooper.dispatchNext();

        boolean actual = manager.isAllowed(SECOND_PACKAGE_NAME);

        assertThat(actual).isFalse();
        verifyZeroInteractions(mMockContentCaptureManagerService);
        verifyZeroInteractions(mMockPackageMonitor);
        verifyZeroInteractions(mMockRemoteContentProtectionService);
    }

    @Test
    public void handleUpdate_updateDisabled() {
    public void isAllowed_true() throws Exception {
        mUseMockAllowlistCallback = false;
        ContentProtectionAllowlistManager manager = new TestContentProtectionAllowlistManager();
        manager.mAllowlistCallback.setAllowlist(List.of(FIRST_PACKAGE_NAME));
        mTestLooper.dispatchNext();

        boolean actual = manager.isAllowed(FIRST_PACKAGE_NAME);

        assertThat(actual).isTrue();
        verifyZeroInteractions(mMockContentCaptureManagerService);
        verifyZeroInteractions(mMockPackageMonitor);
        verifyZeroInteractions(mMockRemoteContentProtectionService);
    }

    @Test
    public void handlePackagesChanged_updateDisabled() {
        mSetFlagsRule.disableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
        ContentProtectionAllowlistManager manager =
                new ContentProtectionAllowlistManager(
                        mMockContentCaptureManagerService, mHandler, TIMEOUT_MS);
        mUseMockPackageMonitor = false;
        ContentProtectionAllowlistManager manager = new TestContentProtectionAllowlistManager();

        manager.mPackageMonitor.onSomePackagesChanged();

        verifyZeroInteractions(mMockContentCaptureManagerService);
        verifyZeroInteractions(mMockRemoteContentProtectionService);
        verifyZeroInteractions(mMockAllowlistCallback);
    }

    @Test
    public void handleUpdate_updateEnabled() {
    public void handlePackagesChanged_updateEnabled_noService() {
        mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
        ContentProtectionAllowlistManager manager =
                new ContentProtectionAllowlistManager(
                        mMockContentCaptureManagerService, mHandler, TIMEOUT_MS);
        mUseMockPackageMonitor = false;
        ContentProtectionAllowlistManager manager = new TestContentProtectionAllowlistManager();

        manager.mPackageMonitor.onSomePackagesChanged();

        verify(mMockContentCaptureManagerService).createRemoteContentProtectionService();
        verifyZeroInteractions(mMockRemoteContentProtectionService);
        verifyZeroInteractions(mMockAllowlistCallback);
    }

    @Test
    public void handleUpdate_rateLimit_noService() {
    public void handlePackagesChanged_updateEnabled_withService() {
        mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
        ContentProtectionAllowlistManager manager =
                new ContentProtectionAllowlistManager(
                        mMockContentCaptureManagerService, mHandler, TIMEOUT_MS);
        mUseMockPackageMonitor = false;
        ContentProtectionAllowlistManager manager = new TestContentProtectionAllowlistManager();
        when(mMockContentCaptureManagerService.createRemoteContentProtectionService())
                .thenReturn(mMockRemoteContentProtectionService);

        manager.mPackageMonitor.onSomePackagesChanged();

        verify(mMockRemoteContentProtectionService)
                .onUpdateAllowlistRequest(mMockAllowlistCallback);
        verifyZeroInteractions(mMockAllowlistCallback);
    }

    @Test
    public void handlePackagesChanged_updateEnabled_withServiceException() {
        mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
        mUseMockPackageMonitor = false;
        ContentProtectionAllowlistManager manager = new TestContentProtectionAllowlistManager();
        when(mMockContentCaptureManagerService.createRemoteContentProtectionService())
                .thenReturn(mMockRemoteContentProtectionService);
        doThrow(new RuntimeException("TEST EXCEPTION"))
                .when(mMockRemoteContentProtectionService)
                .onUpdateAllowlistRequest(mMockAllowlistCallback);

        manager.mPackageMonitor.onSomePackagesChanged();

        // Does not rethrow
        verify(mMockRemoteContentProtectionService)
                .onUpdateAllowlistRequest(mMockAllowlistCallback);
        verifyZeroInteractions(mMockAllowlistCallback);
    }

    @Test
    public void handlePackagesChanged_rateLimit_noService() {
        mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
        mUseMockPackageMonitor = false;
        ContentProtectionAllowlistManager manager = new TestContentProtectionAllowlistManager();

        manager.mPackageMonitor.onSomePackagesChanged();
        manager.mPackageMonitor.onSomePackagesChanged();

        verify(mMockContentCaptureManagerService, times(2)).createRemoteContentProtectionService();
        verifyZeroInteractions(mMockRemoteContentProtectionService);
        verifyZeroInteractions(mMockAllowlistCallback);
    }

    @Test
    public void handleUpdate_rateLimit_beforeTimeout() {
    public void handlePackagesChanged_rateLimit_beforeTimeout() {
        mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
        ContentProtectionAllowlistManager manager =
                new ContentProtectionAllowlistManager(
                        mMockContentCaptureManagerService, mHandler, TIMEOUT_MS);
        mUseMockPackageMonitor = false;
        ContentProtectionAllowlistManager manager = new TestContentProtectionAllowlistManager();
        when(mMockContentCaptureManagerService.createRemoteContentProtectionService())
                .thenReturn(mMockRemoteContentProtectionService);

@@ -351,32 +460,68 @@ public class ContentProtectionAllowlistManagerTest {
        manager.mPackageMonitor.onSomePackagesChanged();

        verify(mMockContentCaptureManagerService).createRemoteContentProtectionService();
        verify(mMockRemoteContentProtectionService)
                .onUpdateAllowlistRequest(mMockAllowlistCallback);
        verifyZeroInteractions(mMockAllowlistCallback);
    }

    @Test
    public void handleUpdate_rateLimit_afterTimeout() {
    public void handlePackagesChanged_rateLimit_afterTimeout() {
        mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
        mUseMockPackageMonitor = false;
        ContentProtectionAllowlistManager manager =
                new ContentProtectionAllowlistManager(
                        mMockContentCaptureManagerService, mHandler, /* timeoutMs= */ 0L);
                new TestContentProtectionAllowlistManager(/* timeoutMs= */ 0L);
        when(mMockContentCaptureManagerService.createRemoteContentProtectionService())
                .thenReturn(mMockRemoteContentProtectionService);

        manager.mPackageMonitor.onSomePackagesChanged();
        manager.mPackageMonitor.onSomePackagesChanged();

        verify(mMockContentCaptureManagerService, times(2)).createRemoteContentProtectionService();
        verify(mMockRemoteContentProtectionService, times(2))
                .onUpdateAllowlistRequest(mMockAllowlistCallback);
        verifyZeroInteractions(mMockAllowlistCallback);
    }

    @Test
    public void handlePackagesChanged_rateLimit_afterUpdate() throws Exception {
        mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
        mUseMockPackageMonitor = false;
        mUseMockAllowlistCallback = false;
        ContentProtectionAllowlistManager manager = new TestContentProtectionAllowlistManager();
        when(mMockContentCaptureManagerService.createRemoteContentProtectionService())
                .thenReturn(mMockRemoteContentProtectionService);

        manager.mPackageMonitor.onSomePackagesChanged();
        manager.mAllowlistCallback.setAllowlist(List.of());
        mTestLooper.dispatchNext();
        manager.mPackageMonitor.onSomePackagesChanged();

        verify(mMockContentCaptureManagerService, times(2)).createRemoteContentProtectionService();
        verify(mMockRemoteContentProtectionService, times(2))
                .onUpdateAllowlistRequest(manager.mAllowlistCallback);
    }

    private class TestContentProtectionAllowlistManager extends ContentProtectionAllowlistManager {

        TestContentProtectionAllowlistManager() {
            super(mMockContentCaptureManagerService, mHandler, TIMEOUT_MS);
            this(TIMEOUT_MS);
        }

        TestContentProtectionAllowlistManager(long timeoutMs) {
            super(mMockContentCaptureManagerService, mHandler, timeoutMs);
        }

        @Override
        protected IContentProtectionAllowlistCallback createAllowlistCallback() {
            return mUseMockAllowlistCallback
                    ? mMockAllowlistCallback
                    : super.createAllowlistCallback();
        }

        @Override
        protected PackageMonitor createPackageMonitor() {
            return mMockPackageMonitor;
            return mUseMockPackageMonitor ? mMockPackageMonitor : super.createPackageMonitor();
        }
    }
}