Connect protection event processor with remote service
BYPASS_INCLUSIVE_LANGUAGE_REASON=Existing code in production Bug: 275732576 Test: Added tests Change-Id: I910460bb6fece38f38ffefa7eed4e8cad3f43277
This commit is contained in:
@@ -48,7 +48,7 @@ import java.io.PrintWriter;
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final class ContentCaptureServiceInfo {
|
||||
public class ContentCaptureServiceInfo {
|
||||
|
||||
private static final String TAG = ContentCaptureServiceInfo.class.getSimpleName();
|
||||
private static final String XML_TAG_SERVICE = "content-capture-service";
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package android.view.contentcapture;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.pm.ParceledListSlice;
|
||||
import android.view.contentcapture.ContentCaptureContext;
|
||||
import android.view.contentcapture.ContentCaptureEvent;
|
||||
import android.view.contentcapture.DataRemovalRequest;
|
||||
@@ -108,4 +109,9 @@ oneway interface IContentCaptureManager {
|
||||
*/
|
||||
void registerContentCaptureOptionsCallback(String packageName,
|
||||
in IContentCaptureOptionsCallback callback);
|
||||
|
||||
/**
|
||||
* Notifies the system server that a login was detected.
|
||||
*/
|
||||
void onLoginDetected(in ParceledListSlice<ContentCaptureEvent> events);
|
||||
}
|
||||
|
||||
@@ -162,7 +162,7 @@ public class ContentProtectionEventProcessor {
|
||||
|
||||
private void handlerOnLoginDetected(@NonNull ParceledListSlice<ContentCaptureEvent> events) {
|
||||
try {
|
||||
// TODO(b/275732576): Call mContentCaptureManager
|
||||
mContentCaptureManager.onLoginDetected(events);
|
||||
} catch (Exception ex) {
|
||||
Log.e(TAG, "Failed to flush events for: " + mPackageName, ex);
|
||||
}
|
||||
|
||||
@@ -26,10 +26,12 @@ import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.verifyZeroInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ParceledListSlice;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.text.InputType;
|
||||
@@ -51,6 +53,7 @@ import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnit;
|
||||
import org.mockito.junit.MockitoRule;
|
||||
@@ -82,6 +85,9 @@ public class ContentProtectionEventProcessorTest {
|
||||
|
||||
private static final ContentCaptureEvent PROCESS_EVENT = createProcessEvent();
|
||||
|
||||
private static final ContentCaptureEvent[] BUFFERED_EVENTS =
|
||||
new ContentCaptureEvent[] {PROCESS_EVENT};
|
||||
|
||||
private static final Set<Integer> EVENT_TYPES_TO_STORE =
|
||||
ImmutableSet.of(TYPE_VIEW_APPEARED, TYPE_VIEW_DISAPPEARED, TYPE_VIEW_TEXT_CHANGED);
|
||||
|
||||
@@ -165,11 +171,12 @@ public class ContentProtectionEventProcessorTest {
|
||||
|
||||
verify(mMockEventBuffer, never()).clear();
|
||||
verify(mMockEventBuffer, never()).toArray();
|
||||
verifyZeroInteractions(mMockContentCaptureManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void processEvent_loginDetected() {
|
||||
when(mMockEventBuffer.toArray()).thenReturn(new ContentCaptureEvent[0]);
|
||||
public void processEvent_loginDetected() throws Exception {
|
||||
when(mMockEventBuffer.toArray()).thenReturn(BUFFERED_EVENTS);
|
||||
mContentProtectionEventProcessor.mPasswordFieldDetected = true;
|
||||
mContentProtectionEventProcessor.mSuspiciousTextDetected = true;
|
||||
|
||||
@@ -179,6 +186,7 @@ public class ContentProtectionEventProcessorTest {
|
||||
assertThat(mContentProtectionEventProcessor.mSuspiciousTextDetected).isFalse();
|
||||
verify(mMockEventBuffer).clear();
|
||||
verify(mMockEventBuffer).toArray();
|
||||
assertOnLoginDetected();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -192,6 +200,7 @@ public class ContentProtectionEventProcessorTest {
|
||||
assertThat(mContentProtectionEventProcessor.mSuspiciousTextDetected).isTrue();
|
||||
verify(mMockEventBuffer, never()).clear();
|
||||
verify(mMockEventBuffer, never()).toArray();
|
||||
verifyZeroInteractions(mMockContentCaptureManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -205,6 +214,7 @@ public class ContentProtectionEventProcessorTest {
|
||||
assertThat(mContentProtectionEventProcessor.mSuspiciousTextDetected).isFalse();
|
||||
verify(mMockEventBuffer, never()).clear();
|
||||
verify(mMockEventBuffer, never()).toArray();
|
||||
verifyZeroInteractions(mMockContentCaptureManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -218,11 +228,12 @@ public class ContentProtectionEventProcessorTest {
|
||||
assertThat(mContentProtectionEventProcessor.mSuspiciousTextDetected).isFalse();
|
||||
verify(mMockEventBuffer, never()).clear();
|
||||
verify(mMockEventBuffer, never()).toArray();
|
||||
verifyZeroInteractions(mMockContentCaptureManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void processEvent_multipleLoginsDetected_belowFlushThreshold() {
|
||||
when(mMockEventBuffer.toArray()).thenReturn(new ContentCaptureEvent[0]);
|
||||
public void processEvent_multipleLoginsDetected_belowFlushThreshold() throws Exception {
|
||||
when(mMockEventBuffer.toArray()).thenReturn(BUFFERED_EVENTS);
|
||||
|
||||
mContentProtectionEventProcessor.mPasswordFieldDetected = true;
|
||||
mContentProtectionEventProcessor.mSuspiciousTextDetected = true;
|
||||
@@ -236,11 +247,12 @@ public class ContentProtectionEventProcessorTest {
|
||||
assertThat(mContentProtectionEventProcessor.mSuspiciousTextDetected).isFalse();
|
||||
verify(mMockEventBuffer).clear();
|
||||
verify(mMockEventBuffer).toArray();
|
||||
assertOnLoginDetected();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void processEvent_multipleLoginsDetected_aboveFlushThreshold() {
|
||||
when(mMockEventBuffer.toArray()).thenReturn(new ContentCaptureEvent[0]);
|
||||
public void processEvent_multipleLoginsDetected_aboveFlushThreshold() throws Exception {
|
||||
when(mMockEventBuffer.toArray()).thenReturn(BUFFERED_EVENTS);
|
||||
|
||||
mContentProtectionEventProcessor.mPasswordFieldDetected = true;
|
||||
mContentProtectionEventProcessor.mSuspiciousTextDetected = true;
|
||||
@@ -256,6 +268,7 @@ public class ContentProtectionEventProcessorTest {
|
||||
assertThat(mContentProtectionEventProcessor.mSuspiciousTextDetected).isFalse();
|
||||
verify(mMockEventBuffer, times(2)).clear();
|
||||
verify(mMockEventBuffer, times(2)).toArray();
|
||||
assertOnLoginDetected(PROCESS_EVENT, /* times= */ 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -269,6 +282,7 @@ public class ContentProtectionEventProcessorTest {
|
||||
assertThat(mContentProtectionEventProcessor.mPasswordFieldDetected).isTrue();
|
||||
verify(mMockEventBuffer, never()).clear();
|
||||
verify(mMockEventBuffer, never()).toArray();
|
||||
verifyZeroInteractions(mMockContentCaptureManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -282,6 +296,7 @@ public class ContentProtectionEventProcessorTest {
|
||||
assertThat(mContentProtectionEventProcessor.mPasswordFieldDetected).isFalse();
|
||||
verify(mMockEventBuffer, never()).clear();
|
||||
verify(mMockEventBuffer, never()).toArray();
|
||||
verifyZeroInteractions(mMockContentCaptureManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -296,6 +311,7 @@ public class ContentProtectionEventProcessorTest {
|
||||
assertThat(mContentProtectionEventProcessor.mPasswordFieldDetected).isFalse();
|
||||
verify(mMockEventBuffer, never()).clear();
|
||||
verify(mMockEventBuffer, never()).toArray();
|
||||
verifyZeroInteractions(mMockContentCaptureManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -309,21 +325,22 @@ public class ContentProtectionEventProcessorTest {
|
||||
assertThat(mContentProtectionEventProcessor.mPasswordFieldDetected).isFalse();
|
||||
verify(mMockEventBuffer, never()).clear();
|
||||
verify(mMockEventBuffer, never()).toArray();
|
||||
verifyZeroInteractions(mMockContentCaptureManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isPasswordField_webView() {
|
||||
when(mMockEventBuffer.toArray()).thenReturn(new ContentCaptureEvent[0]);
|
||||
|
||||
public void isPasswordField_webView() throws Exception {
|
||||
ContentCaptureEvent event =
|
||||
createWebViewPasswordFieldEvent(
|
||||
/* className= */ null, /* eventText= */ null, PASSWORD_TEXT);
|
||||
when(mMockEventBuffer.toArray()).thenReturn(new ContentCaptureEvent[] {event});
|
||||
|
||||
mContentProtectionEventProcessor.processEvent(event);
|
||||
|
||||
assertThat(mContentProtectionEventProcessor.mPasswordFieldDetected).isFalse();
|
||||
verify(mMockEventBuffer).clear();
|
||||
verify(mMockEventBuffer).toArray();
|
||||
assertOnLoginDetected(event, /* times= */ 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -337,6 +354,7 @@ public class ContentProtectionEventProcessorTest {
|
||||
assertThat(mContentProtectionEventProcessor.mPasswordFieldDetected).isFalse();
|
||||
verify(mMockEventBuffer, never()).clear();
|
||||
verify(mMockEventBuffer, never()).toArray();
|
||||
verifyZeroInteractions(mMockContentCaptureManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -350,6 +368,7 @@ public class ContentProtectionEventProcessorTest {
|
||||
assertThat(mContentProtectionEventProcessor.mPasswordFieldDetected).isFalse();
|
||||
verify(mMockEventBuffer, never()).clear();
|
||||
verify(mMockEventBuffer, never()).toArray();
|
||||
verifyZeroInteractions(mMockContentCaptureManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -362,6 +381,7 @@ public class ContentProtectionEventProcessorTest {
|
||||
assertThat(mContentProtectionEventProcessor.mPasswordFieldDetected).isFalse();
|
||||
verify(mMockEventBuffer, never()).clear();
|
||||
verify(mMockEventBuffer, never()).toArray();
|
||||
verifyZeroInteractions(mMockContentCaptureManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -373,6 +393,7 @@ public class ContentProtectionEventProcessorTest {
|
||||
assertThat(mContentProtectionEventProcessor.mSuspiciousTextDetected).isFalse();
|
||||
verify(mMockEventBuffer, never()).clear();
|
||||
verify(mMockEventBuffer, never()).toArray();
|
||||
verifyZeroInteractions(mMockContentCaptureManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -384,6 +405,7 @@ public class ContentProtectionEventProcessorTest {
|
||||
assertThat(mContentProtectionEventProcessor.mSuspiciousTextDetected).isTrue();
|
||||
verify(mMockEventBuffer, never()).clear();
|
||||
verify(mMockEventBuffer, never()).toArray();
|
||||
verifyZeroInteractions(mMockContentCaptureManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -395,6 +417,7 @@ public class ContentProtectionEventProcessorTest {
|
||||
assertThat(mContentProtectionEventProcessor.mSuspiciousTextDetected).isTrue();
|
||||
verify(mMockEventBuffer, never()).clear();
|
||||
verify(mMockEventBuffer, never()).toArray();
|
||||
verifyZeroInteractions(mMockContentCaptureManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -406,6 +429,7 @@ public class ContentProtectionEventProcessorTest {
|
||||
assertThat(mContentProtectionEventProcessor.mSuspiciousTextDetected).isTrue();
|
||||
verify(mMockEventBuffer, never()).clear();
|
||||
verify(mMockEventBuffer, never()).toArray();
|
||||
verifyZeroInteractions(mMockContentCaptureManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -420,6 +444,7 @@ public class ContentProtectionEventProcessorTest {
|
||||
assertThat(mContentProtectionEventProcessor.mSuspiciousTextDetected).isTrue();
|
||||
verify(mMockEventBuffer, never()).clear();
|
||||
verify(mMockEventBuffer, never()).toArray();
|
||||
verifyZeroInteractions(mMockContentCaptureManager);
|
||||
}
|
||||
|
||||
private static ContentCaptureEvent createEvent(int type) {
|
||||
@@ -474,4 +499,18 @@ public class ContentProtectionEventProcessorTest {
|
||||
return createProcessEvent(
|
||||
/* className= */ null, /* inputType= */ 0, eventText, viewNodeText);
|
||||
}
|
||||
|
||||
private void assertOnLoginDetected() throws Exception {
|
||||
assertOnLoginDetected(PROCESS_EVENT, /* times= */ 1);
|
||||
}
|
||||
|
||||
private void assertOnLoginDetected(ContentCaptureEvent event, int times) throws Exception {
|
||||
ArgumentCaptor<ParceledListSlice> captor = ArgumentCaptor.forClass(ParceledListSlice.class);
|
||||
verify(mMockContentCaptureManager, times(times)).onLoginDetected(captor.capture());
|
||||
|
||||
assertThat(captor.getValue()).isNotNull();
|
||||
List<ContentCaptureEvent> actual = captor.getValue().getList();
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).containsExactly(event);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ import android.content.Context;
|
||||
import android.content.pm.ActivityPresentationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.ParceledListSlice;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.database.ContentObserver;
|
||||
import android.os.Binder;
|
||||
@@ -69,6 +70,7 @@ import android.provider.DeviceConfig;
|
||||
import android.provider.DeviceConfig.Properties;
|
||||
import android.provider.Settings;
|
||||
import android.service.contentcapture.ActivityEvent.ActivityEventType;
|
||||
import android.service.contentcapture.ContentCaptureServiceInfo;
|
||||
import android.service.contentcapture.IDataShareCallback;
|
||||
import android.service.contentcapture.IDataShareReadAdapter;
|
||||
import android.service.voice.VoiceInteractionManagerInternal;
|
||||
@@ -79,6 +81,7 @@ import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseBooleanArray;
|
||||
import android.view.contentcapture.ContentCaptureCondition;
|
||||
import android.view.contentcapture.ContentCaptureEvent;
|
||||
import android.view.contentcapture.ContentCaptureHelper;
|
||||
import android.view.contentcapture.ContentCaptureManager;
|
||||
import android.view.contentcapture.DataRemovalRequest;
|
||||
@@ -96,6 +99,7 @@ import com.android.internal.util.DumpUtils;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.contentprotection.ContentProtectionBlocklistManager;
|
||||
import com.android.server.contentprotection.ContentProtectionPackageManager;
|
||||
import com.android.server.contentprotection.RemoteContentProtectionService;
|
||||
import com.android.server.infra.AbstractMasterSystemService;
|
||||
import com.android.server.infra.FrameworkResourcesServiceNameResolver;
|
||||
|
||||
@@ -208,6 +212,8 @@ public class ContentCaptureManagerService extends
|
||||
final GlobalContentCaptureOptions mGlobalContentCaptureOptions =
|
||||
new GlobalContentCaptureOptions();
|
||||
|
||||
@Nullable private final ComponentName mContentProtectionServiceComponentName;
|
||||
|
||||
@Nullable private final ContentProtectionBlocklistManager mContentProtectionBlocklistManager;
|
||||
|
||||
public ContentCaptureManagerService(@NonNull Context context) {
|
||||
@@ -249,10 +255,16 @@ public class ContentCaptureManagerService extends
|
||||
}
|
||||
|
||||
if (getEnableContentProtectionReceiverLocked()) {
|
||||
mContentProtectionBlocklistManager = createContentProtectionBlocklistManager(context);
|
||||
mContentProtectionBlocklistManager.updateBlocklist(
|
||||
mDevCfgContentProtectionAppsBlocklistSize);
|
||||
mContentProtectionServiceComponentName = getContentProtectionServiceComponentName();
|
||||
if (mContentProtectionServiceComponentName != null) {
|
||||
mContentProtectionBlocklistManager = createContentProtectionBlocklistManager();
|
||||
mContentProtectionBlocklistManager.updateBlocklist(
|
||||
mDevCfgContentProtectionAppsBlocklistSize);
|
||||
} else {
|
||||
mContentProtectionBlocklistManager = null;
|
||||
}
|
||||
} else {
|
||||
mContentProtectionServiceComponentName = null;
|
||||
mContentProtectionBlocklistManager = null;
|
||||
}
|
||||
}
|
||||
@@ -785,9 +797,82 @@ public class ContentCaptureManagerService extends
|
||||
/** @hide */
|
||||
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
|
||||
@NonNull
|
||||
protected ContentProtectionBlocklistManager createContentProtectionBlocklistManager(
|
||||
@NonNull Context context) {
|
||||
return new ContentProtectionBlocklistManager(new ContentProtectionPackageManager(context));
|
||||
protected ContentProtectionBlocklistManager createContentProtectionBlocklistManager() {
|
||||
return new ContentProtectionBlocklistManager(
|
||||
new ContentProtectionPackageManager(getContext()));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ComponentName getContentProtectionServiceComponentName() {
|
||||
String flatComponentName = getContentProtectionServiceFlatComponentName();
|
||||
ComponentName componentName = ComponentName.unflattenFromString(flatComponentName);
|
||||
if (componentName == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check permissions by trying to construct {@link ContentCaptureServiceInfo}
|
||||
try {
|
||||
createContentProtectionServiceInfo(componentName);
|
||||
} catch (Exception ex) {
|
||||
// Swallow, exception was already logged
|
||||
return null;
|
||||
}
|
||||
|
||||
return componentName;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
|
||||
@Nullable
|
||||
protected String getContentProtectionServiceFlatComponentName() {
|
||||
return getContext()
|
||||
.getString(com.android.internal.R.string.config_defaultContentProtectionService);
|
||||
}
|
||||
|
||||
/**
|
||||
* Can also throw runtime exceptions such as {@link SecurityException}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
|
||||
@NonNull
|
||||
protected ContentCaptureServiceInfo createContentProtectionServiceInfo(
|
||||
@NonNull ComponentName componentName) throws PackageManager.NameNotFoundException {
|
||||
return new ContentCaptureServiceInfo(
|
||||
getContext(), componentName, /* isTemp= */ false, UserHandle.getCallingUserId());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private RemoteContentProtectionService createRemoteContentProtectionService() {
|
||||
if (mContentProtectionServiceComponentName == null) {
|
||||
// This case should not be possible but make sure
|
||||
return null;
|
||||
}
|
||||
synchronized (mLock) {
|
||||
if (!mDevCfgEnableContentProtectionReceiver) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return createRemoteContentProtectionService(mContentProtectionServiceComponentName);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
|
||||
@NonNull
|
||||
protected RemoteContentProtectionService createRemoteContentProtectionService(
|
||||
@NonNull ComponentName componentName) {
|
||||
return new RemoteContentProtectionService(
|
||||
getContext(),
|
||||
componentName,
|
||||
UserHandle.getCallingUserId(),
|
||||
isBindInstantServiceAllowed());
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
|
||||
@NonNull
|
||||
protected ContentCaptureManagerServiceStub getContentCaptureManagerServiceStub() {
|
||||
return mContentCaptureManagerServiceStub;
|
||||
}
|
||||
|
||||
final class ContentCaptureManagerServiceStub extends IContentCaptureManager.Stub {
|
||||
@@ -1023,6 +1108,19 @@ public class ContentCaptureManagerService extends
|
||||
public void setDefaultServiceEnabled(@UserIdInt int userId, boolean enabled) {
|
||||
ContentCaptureManagerService.this.setDefaultServiceEnabled(userId, enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoginDetected(@NonNull ParceledListSlice<ContentCaptureEvent> events) {
|
||||
RemoteContentProtectionService service = createRemoteContentProtectionService();
|
||||
if (service == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
service.onLoginDetected(events);
|
||||
} catch (Exception ex) {
|
||||
Slog.e(TAG, "Failed to call remote service", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class LocalService extends ContentCaptureManagerInternal {
|
||||
@@ -1205,7 +1303,8 @@ public class ContentCaptureManagerService extends
|
||||
}
|
||||
|
||||
private boolean isContentProtectionReceiverEnabled(@NonNull String packageName) {
|
||||
if (mContentProtectionBlocklistManager == null) {
|
||||
if (mContentProtectionServiceComponentName == null
|
||||
|| mContentProtectionBlocklistManager == null) {
|
||||
return false;
|
||||
}
|
||||
synchronized (mLock) {
|
||||
|
||||
@@ -37,7 +37,8 @@ import java.time.Duration;
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
class RemoteContentProtectionService extends ServiceConnector.Impl<IContentCaptureDirectManager> {
|
||||
public class RemoteContentProtectionService
|
||||
extends ServiceConnector.Impl<IContentCaptureDirectManager> {
|
||||
|
||||
private static final String TAG = RemoteContentProtectionService.class.getSimpleName();
|
||||
|
||||
@@ -45,7 +46,7 @@ class RemoteContentProtectionService extends ServiceConnector.Impl<IContentCaptu
|
||||
|
||||
@NonNull private final ComponentName mComponentName;
|
||||
|
||||
protected RemoteContentProtectionService(
|
||||
public RemoteContentProtectionService(
|
||||
@NonNull Context context,
|
||||
@NonNull ComponentName componentName,
|
||||
int userId,
|
||||
|
||||
@@ -30,7 +30,11 @@ import android.annotation.NonNull;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentCaptureOptions;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ParceledListSlice;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.service.contentcapture.ContentCaptureServiceInfo;
|
||||
import android.view.contentcapture.ContentCaptureEvent;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
@@ -38,6 +42,7 @@ import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.contentprotection.ContentProtectionBlocklistManager;
|
||||
import com.android.server.contentprotection.RemoteContentProtectionService;
|
||||
import com.android.server.pm.UserManagerInternal;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
@@ -68,6 +73,12 @@ public class ContentCaptureManagerServiceTest {
|
||||
private static final ComponentName COMPONENT_NAME =
|
||||
new ComponentName(PACKAGE_NAME, "TestClass");
|
||||
|
||||
private static final ContentCaptureEvent EVENT =
|
||||
new ContentCaptureEvent(/* sessionId= */ 100, /* type= */ 200);
|
||||
|
||||
private static final ParceledListSlice<ContentCaptureEvent> PARCELED_EVENTS =
|
||||
new ParceledListSlice<>(ImmutableList.of(EVENT));
|
||||
|
||||
private static final Context sContext = ApplicationProvider.getApplicationContext();
|
||||
|
||||
@Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
|
||||
@@ -76,10 +87,22 @@ public class ContentCaptureManagerServiceTest {
|
||||
|
||||
@Mock private ContentProtectionBlocklistManager mMockContentProtectionBlocklistManager;
|
||||
|
||||
@Mock private ContentCaptureServiceInfo mMockContentCaptureServiceInfo;
|
||||
|
||||
@Mock private RemoteContentProtectionService mMockRemoteContentProtectionService;
|
||||
|
||||
private boolean mDevCfgEnableContentProtectionReceiver;
|
||||
|
||||
private int mContentProtectionBlocklistManagersCreated;
|
||||
|
||||
private int mContentProtectionServiceInfosCreated;
|
||||
|
||||
private int mRemoteContentProtectionServicesCreated;
|
||||
|
||||
private String mConfigDefaultContentProtectionService = COMPONENT_NAME.flattenToString();
|
||||
|
||||
private boolean mContentProtectionServiceInfoConstructorShouldThrow;
|
||||
|
||||
private ContentCaptureManagerService mContentCaptureManagerService;
|
||||
|
||||
@Before
|
||||
@@ -91,24 +114,54 @@ public class ContentCaptureManagerServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructor_default_doesNotCreateContentProtectionBlocklistManager() {
|
||||
public void constructor_contentProtection_flagDisabled_noBlocklistManager() {
|
||||
assertThat(mContentProtectionBlocklistManagersCreated).isEqualTo(0);
|
||||
assertThat(mContentProtectionServiceInfosCreated).isEqualTo(0);
|
||||
verifyZeroInteractions(mMockContentProtectionBlocklistManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructor_flagDisabled_doesNotContentProtectionBlocklistManager() {
|
||||
public void constructor_contentProtection_componentNameNull_noBlocklistManager() {
|
||||
mConfigDefaultContentProtectionService = null;
|
||||
|
||||
mContentCaptureManagerService = new TestContentCaptureManagerService();
|
||||
|
||||
assertThat(mContentProtectionBlocklistManagersCreated).isEqualTo(0);
|
||||
assertThat(mContentProtectionServiceInfosCreated).isEqualTo(0);
|
||||
verifyZeroInteractions(mMockContentProtectionBlocklistManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructor_flagEnabled_createsContentProtectionBlocklistManager() {
|
||||
public void constructor_contentProtection_componentNameBlank_noBlocklistManager() {
|
||||
mConfigDefaultContentProtectionService = " ";
|
||||
|
||||
mContentCaptureManagerService = new TestContentCaptureManagerService();
|
||||
|
||||
assertThat(mContentProtectionBlocklistManagersCreated).isEqualTo(0);
|
||||
assertThat(mContentProtectionServiceInfosCreated).isEqualTo(0);
|
||||
verifyZeroInteractions(mMockContentProtectionBlocklistManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructor_contentProtection_serviceInfoThrows_noBlocklistManager() {
|
||||
mDevCfgEnableContentProtectionReceiver = true;
|
||||
mContentProtectionServiceInfoConstructorShouldThrow = true;
|
||||
|
||||
mContentCaptureManagerService = new TestContentCaptureManagerService();
|
||||
|
||||
assertThat(mContentProtectionBlocklistManagersCreated).isEqualTo(0);
|
||||
assertThat(mContentProtectionServiceInfosCreated).isEqualTo(1);
|
||||
verifyZeroInteractions(mMockContentProtectionBlocklistManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructor_contentProtection_enabled_createsBlocklistManager() {
|
||||
mDevCfgEnableContentProtectionReceiver = true;
|
||||
|
||||
mContentCaptureManagerService = new TestContentCaptureManagerService();
|
||||
|
||||
assertThat(mContentProtectionBlocklistManagersCreated).isEqualTo(1);
|
||||
assertThat(mContentProtectionServiceInfosCreated).isEqualTo(1);
|
||||
verify(mMockContentProtectionBlocklistManager).updateBlocklist(anyInt());
|
||||
}
|
||||
|
||||
@@ -298,6 +351,35 @@ public class ContentCaptureManagerServiceTest {
|
||||
verify(mMockContentProtectionBlocklistManager, never()).isAllowed(anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onLoginDetected_disabledAfterConstructor() {
|
||||
mDevCfgEnableContentProtectionReceiver = true;
|
||||
mContentCaptureManagerService = new TestContentCaptureManagerService();
|
||||
mContentCaptureManagerService.mDevCfgEnableContentProtectionReceiver = false;
|
||||
|
||||
mContentCaptureManagerService
|
||||
.getContentCaptureManagerServiceStub()
|
||||
.onLoginDetected(PARCELED_EVENTS);
|
||||
|
||||
assertThat(mContentProtectionServiceInfosCreated).isEqualTo(1);
|
||||
assertThat(mRemoteContentProtectionServicesCreated).isEqualTo(0);
|
||||
verifyZeroInteractions(mMockRemoteContentProtectionService);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onLoginDetected_enabled() {
|
||||
mDevCfgEnableContentProtectionReceiver = true;
|
||||
mContentCaptureManagerService = new TestContentCaptureManagerService();
|
||||
|
||||
mContentCaptureManagerService
|
||||
.getContentCaptureManagerServiceStub()
|
||||
.onLoginDetected(PARCELED_EVENTS);
|
||||
|
||||
assertThat(mContentProtectionServiceInfosCreated).isEqualTo(1);
|
||||
assertThat(mRemoteContentProtectionServicesCreated).isEqualTo(1);
|
||||
verify(mMockRemoteContentProtectionService).onLoginDetected(PARCELED_EVENTS);
|
||||
}
|
||||
|
||||
private class TestContentCaptureManagerService extends ContentCaptureManagerService {
|
||||
|
||||
TestContentCaptureManagerService() {
|
||||
@@ -312,10 +394,31 @@ public class ContentCaptureManagerServiceTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ContentProtectionBlocklistManager createContentProtectionBlocklistManager(
|
||||
@NonNull Context context) {
|
||||
protected ContentProtectionBlocklistManager createContentProtectionBlocklistManager() {
|
||||
mContentProtectionBlocklistManagersCreated++;
|
||||
return mMockContentProtectionBlocklistManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getContentProtectionServiceFlatComponentName() {
|
||||
return mConfigDefaultContentProtectionService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ContentCaptureServiceInfo createContentProtectionServiceInfo(
|
||||
@NonNull ComponentName componentName) throws PackageManager.NameNotFoundException {
|
||||
mContentProtectionServiceInfosCreated++;
|
||||
if (mContentProtectionServiceInfoConstructorShouldThrow) {
|
||||
throw new RuntimeException("TEST RUNTIME EXCEPTION");
|
||||
}
|
||||
return mMockContentCaptureServiceInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RemoteContentProtectionService createRemoteContentProtectionService(
|
||||
@NonNull ComponentName componentName) {
|
||||
mRemoteContentProtectionServicesCreated++;
|
||||
return mMockRemoteContentProtectionService;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user