Loading core/java/android/service/contentcapture/ContentCaptureService.java +48 −12 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.RemoteException; import android.util.Log; import android.util.Slog; Loading Loading @@ -140,10 +141,9 @@ public abstract class ContentCaptureService extends Service { private long mCallerMismatchTimeout = 1000; private long mLastCallerMismatchLog; /** * Binder that receives calls from the system server. */ private final IContentCaptureService mServerInterface = new IContentCaptureService.Stub() { /** Binder that receives calls from the system server in the content capture flow. */ private final IContentCaptureService mContentCaptureServerInterface = new IContentCaptureService.Stub() { @Override public void onConnected(IBinder callback, boolean verbose, boolean debug) { Loading Loading @@ -199,10 +199,24 @@ public abstract class ContentCaptureService extends Service { } }; /** * Binder that receives calls from the app. */ private final IContentCaptureDirectManager mClientInterface = /** Binder that receives calls from the system server in the content protection flow. */ private final IContentProtectionService mContentProtectionServerInterface = new IContentProtectionService.Stub() { @Override public void onLoginDetected( @SuppressWarnings("rawtypes") ParceledListSlice events) { mHandler.sendMessage( obtainMessage( ContentCaptureService::handleOnLoginDetected, ContentCaptureService.this, Binder.getCallingUid(), events)); } }; /** Binder that receives calls from the app in the content capture flow. */ private final IContentCaptureDirectManager mContentCaptureClientInterface = new IContentCaptureDirectManager.Stub() { @Override Loading Loading @@ -232,9 +246,19 @@ public abstract class ContentCaptureService extends Service { @Override public final IBinder onBind(Intent intent) { if (SERVICE_INTERFACE.equals(intent.getAction())) { return mServerInterface.asBinder(); } Log.w(TAG, "Tried to bind to wrong intent (should be " + SERVICE_INTERFACE + ": " + intent); return mContentCaptureServerInterface.asBinder(); } if (PROTECTION_SERVICE_INTERFACE.equals(intent.getAction())) { return mContentProtectionServerInterface.asBinder(); } Log.w( TAG, "Tried to bind to wrong intent (should be " + SERVICE_INTERFACE + " or " + PROTECTION_SERVICE_INTERFACE + "): " + intent); return null; } Loading Loading @@ -468,7 +492,7 @@ public abstract class ContentCaptureService extends Service { } else { stateFlags |= ContentCaptureSession.STATE_DISABLED; } setClientState(clientReceiver, stateFlags, mClientInterface.asBinder()); setClientState(clientReceiver, stateFlags, mContentCaptureClientInterface.asBinder()); } private void handleSendEvents(int uid, Loading Loading @@ -536,6 +560,18 @@ public abstract class ContentCaptureService extends Service { writeFlushMetrics(lastSessionId, activityComponent, metrics, options, reason); } private void handleOnLoginDetected( int uid, @NonNull ParceledListSlice<ContentCaptureEvent> parceledEvents) { if (uid != Process.SYSTEM_UID) { Log.e(TAG, "handleOnLoginDetected() not allowed for uid: " + uid); return; } List<ContentCaptureEvent> events = parceledEvents.getList(); int sessionIdInt = events.isEmpty() ? NO_SESSION_ID : events.get(0).getSessionId(); ContentCaptureSessionId sessionId = new ContentCaptureSessionId(sessionIdInt); events.forEach(event -> onContentCaptureEvent(sessionId, event)); } private void handleOnActivitySnapshot(int sessionId, @NonNull SnapshotData snapshotData) { onActivitySnapshot(new ContentCaptureSessionId(sessionId), snapshotData); } Loading core/java/android/service/contentcapture/IContentProtectionService.aidl 0 → 100644 +30 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.service.contentcapture; import android.content.pm.ParceledListSlice; import android.view.contentcapture.ContentCaptureEvent; /** * Interface from the system server to the content protection service. * * @hide */ oneway interface IContentProtectionService { void onLoginDetected(in ParceledListSlice events); } core/java/android/view/contentcapture/ContentCaptureSession.java +1 −6 Original line number Diff line number Diff line Loading @@ -181,8 +181,6 @@ public abstract class ContentCaptureSession implements AutoCloseable { public static final int FLUSH_REASON_VIEW_TREE_APPEARING = 9; /** @hide */ public static final int FLUSH_REASON_VIEW_TREE_APPEARED = 10; /** @hide */ public static final int FLUSH_REASON_LOGIN_DETECTED = 11; /** * After {@link UPSIDE_DOWN_CAKE}, {@link #notifyViewsDisappeared(AutofillId, long[])} wraps Loading @@ -205,8 +203,7 @@ public abstract class ContentCaptureSession implements AutoCloseable { FLUSH_REASON_SESSION_CONNECTED, FLUSH_REASON_FORCE_FLUSH, FLUSH_REASON_VIEW_TREE_APPEARING, FLUSH_REASON_VIEW_TREE_APPEARED, FLUSH_REASON_LOGIN_DETECTED FLUSH_REASON_VIEW_TREE_APPEARED }) @Retention(RetentionPolicy.SOURCE) public @interface FlushReason {} Loading Loading @@ -690,8 +687,6 @@ public abstract class ContentCaptureSession implements AutoCloseable { return "VIEW_TREE_APPEARING"; case FLUSH_REASON_VIEW_TREE_APPEARED: return "VIEW_TREE_APPEARED"; case FLUSH_REASON_LOGIN_DETECTED: return "LOGIN_DETECTED"; default: return "UNKNOWN-" + reason; } Loading core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java +5 −3 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ import com.google.common.collect.ImmutableMap; import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges; import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges; import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TestRule; Loading Loading @@ -130,6 +131,7 @@ public class ContentCaptureSessionTest { () -> mSession1.notifyViewsDisappeared(new AutofillId(42, 108), new long[] {666})); } @Ignore("b/286134492") @Test public void testNotifyViewsDisappeared_noSendTreeEventBeforeU() { MyContentCaptureSession session = new MyContentCaptureSession(121); Loading @@ -139,6 +141,7 @@ public class ContentCaptureSessionTest { assertThat(session.mInternalNotifyViewTreeEventFinishedCount).isEqualTo(0); } @Ignore("b/286134492") @EnableCompatChanges({ContentCaptureSession.NOTIFY_NODES_DISAPPEAR_NOW_SENDS_TREE_EVENTS}) @Test public void testNotifyViewsDisappeared_sendTreeEventSinceU() { Loading @@ -151,7 +154,7 @@ public class ContentCaptureSessionTest { @Test public void testGetFlushReasonAsString() { int invalidFlushReason = ContentCaptureSession.FLUSH_REASON_LOGIN_DETECTED + 1; int invalidFlushReason = ContentCaptureSession.FLUSH_REASON_VIEW_TREE_APPEARED + 1; Map<Integer, String> expectedMap = new ImmutableMap.Builder<Integer, String>() .put(ContentCaptureSession.FLUSH_REASON_FULL, "FULL") Loading @@ -168,8 +171,7 @@ public class ContentCaptureSessionTest { .put( ContentCaptureSession.FLUSH_REASON_VIEW_TREE_APPEARED, "VIEW_TREE_APPEARED") .put(ContentCaptureSession.FLUSH_REASON_LOGIN_DETECTED, "LOGIN_DETECTED") .put(invalidFlushReason, "UNKOWN-" + invalidFlushReason) .put(invalidFlushReason, "UNKNOWN-" + invalidFlushReason) .build(); expectedMap.forEach( Loading services/contentcapture/java/com/android/server/contentprotection/RemoteContentProtectionService.java +5 −10 Original line number Diff line number Diff line Loading @@ -16,17 +16,15 @@ package com.android.server.contentprotection; import static android.view.contentcapture.ContentCaptureSession.FLUSH_REASON_LOGIN_DETECTED; import android.annotation.NonNull; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ParceledListSlice; import android.service.contentcapture.ContentCaptureService; import android.service.contentcapture.IContentProtectionService; import android.util.Slog; import android.view.contentcapture.ContentCaptureEvent; import android.view.contentcapture.IContentCaptureDirectManager; import com.android.internal.infra.ServiceConnector; Loading @@ -38,7 +36,7 @@ import java.time.Duration; * @hide */ public class RemoteContentProtectionService extends ServiceConnector.Impl<IContentCaptureDirectManager> { extends ServiceConnector.Impl<IContentProtectionService> { private static final String TAG = RemoteContentProtectionService.class.getSimpleName(); Loading @@ -57,7 +55,7 @@ public class RemoteContentProtectionService .setComponent(componentName), bindAllowInstant ? Context.BIND_ALLOW_INSTANT : 0, userId, IContentCaptureDirectManager.Stub::asInterface); IContentProtectionService.Stub::asInterface); mComponentName = componentName; } Loading @@ -68,7 +66,7 @@ public class RemoteContentProtectionService @Override // from ServiceConnector.Impl protected void onServiceConnectionStatusChanged( @NonNull IContentCaptureDirectManager service, boolean isConnected) { @NonNull IContentProtectionService service, boolean isConnected) { Slog.i( TAG, "Connection status for: " Loading @@ -78,9 +76,6 @@ public class RemoteContentProtectionService } public void onLoginDetected(@NonNull ParceledListSlice<ContentCaptureEvent> events) { run( service -> service.sendEvents( events, FLUSH_REASON_LOGIN_DETECTED, /* options= */ null)); run(service -> service.onLoginDetected(events)); } } Loading
core/java/android/service/contentcapture/ContentCaptureService.java +48 −12 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.RemoteException; import android.util.Log; import android.util.Slog; Loading Loading @@ -140,10 +141,9 @@ public abstract class ContentCaptureService extends Service { private long mCallerMismatchTimeout = 1000; private long mLastCallerMismatchLog; /** * Binder that receives calls from the system server. */ private final IContentCaptureService mServerInterface = new IContentCaptureService.Stub() { /** Binder that receives calls from the system server in the content capture flow. */ private final IContentCaptureService mContentCaptureServerInterface = new IContentCaptureService.Stub() { @Override public void onConnected(IBinder callback, boolean verbose, boolean debug) { Loading Loading @@ -199,10 +199,24 @@ public abstract class ContentCaptureService extends Service { } }; /** * Binder that receives calls from the app. */ private final IContentCaptureDirectManager mClientInterface = /** Binder that receives calls from the system server in the content protection flow. */ private final IContentProtectionService mContentProtectionServerInterface = new IContentProtectionService.Stub() { @Override public void onLoginDetected( @SuppressWarnings("rawtypes") ParceledListSlice events) { mHandler.sendMessage( obtainMessage( ContentCaptureService::handleOnLoginDetected, ContentCaptureService.this, Binder.getCallingUid(), events)); } }; /** Binder that receives calls from the app in the content capture flow. */ private final IContentCaptureDirectManager mContentCaptureClientInterface = new IContentCaptureDirectManager.Stub() { @Override Loading Loading @@ -232,9 +246,19 @@ public abstract class ContentCaptureService extends Service { @Override public final IBinder onBind(Intent intent) { if (SERVICE_INTERFACE.equals(intent.getAction())) { return mServerInterface.asBinder(); } Log.w(TAG, "Tried to bind to wrong intent (should be " + SERVICE_INTERFACE + ": " + intent); return mContentCaptureServerInterface.asBinder(); } if (PROTECTION_SERVICE_INTERFACE.equals(intent.getAction())) { return mContentProtectionServerInterface.asBinder(); } Log.w( TAG, "Tried to bind to wrong intent (should be " + SERVICE_INTERFACE + " or " + PROTECTION_SERVICE_INTERFACE + "): " + intent); return null; } Loading Loading @@ -468,7 +492,7 @@ public abstract class ContentCaptureService extends Service { } else { stateFlags |= ContentCaptureSession.STATE_DISABLED; } setClientState(clientReceiver, stateFlags, mClientInterface.asBinder()); setClientState(clientReceiver, stateFlags, mContentCaptureClientInterface.asBinder()); } private void handleSendEvents(int uid, Loading Loading @@ -536,6 +560,18 @@ public abstract class ContentCaptureService extends Service { writeFlushMetrics(lastSessionId, activityComponent, metrics, options, reason); } private void handleOnLoginDetected( int uid, @NonNull ParceledListSlice<ContentCaptureEvent> parceledEvents) { if (uid != Process.SYSTEM_UID) { Log.e(TAG, "handleOnLoginDetected() not allowed for uid: " + uid); return; } List<ContentCaptureEvent> events = parceledEvents.getList(); int sessionIdInt = events.isEmpty() ? NO_SESSION_ID : events.get(0).getSessionId(); ContentCaptureSessionId sessionId = new ContentCaptureSessionId(sessionIdInt); events.forEach(event -> onContentCaptureEvent(sessionId, event)); } private void handleOnActivitySnapshot(int sessionId, @NonNull SnapshotData snapshotData) { onActivitySnapshot(new ContentCaptureSessionId(sessionId), snapshotData); } Loading
core/java/android/service/contentcapture/IContentProtectionService.aidl 0 → 100644 +30 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.service.contentcapture; import android.content.pm.ParceledListSlice; import android.view.contentcapture.ContentCaptureEvent; /** * Interface from the system server to the content protection service. * * @hide */ oneway interface IContentProtectionService { void onLoginDetected(in ParceledListSlice events); }
core/java/android/view/contentcapture/ContentCaptureSession.java +1 −6 Original line number Diff line number Diff line Loading @@ -181,8 +181,6 @@ public abstract class ContentCaptureSession implements AutoCloseable { public static final int FLUSH_REASON_VIEW_TREE_APPEARING = 9; /** @hide */ public static final int FLUSH_REASON_VIEW_TREE_APPEARED = 10; /** @hide */ public static final int FLUSH_REASON_LOGIN_DETECTED = 11; /** * After {@link UPSIDE_DOWN_CAKE}, {@link #notifyViewsDisappeared(AutofillId, long[])} wraps Loading @@ -205,8 +203,7 @@ public abstract class ContentCaptureSession implements AutoCloseable { FLUSH_REASON_SESSION_CONNECTED, FLUSH_REASON_FORCE_FLUSH, FLUSH_REASON_VIEW_TREE_APPEARING, FLUSH_REASON_VIEW_TREE_APPEARED, FLUSH_REASON_LOGIN_DETECTED FLUSH_REASON_VIEW_TREE_APPEARED }) @Retention(RetentionPolicy.SOURCE) public @interface FlushReason {} Loading Loading @@ -690,8 +687,6 @@ public abstract class ContentCaptureSession implements AutoCloseable { return "VIEW_TREE_APPEARING"; case FLUSH_REASON_VIEW_TREE_APPEARED: return "VIEW_TREE_APPEARED"; case FLUSH_REASON_LOGIN_DETECTED: return "LOGIN_DETECTED"; default: return "UNKNOWN-" + reason; } Loading
core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java +5 −3 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ import com.google.common.collect.ImmutableMap; import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges; import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges; import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TestRule; Loading Loading @@ -130,6 +131,7 @@ public class ContentCaptureSessionTest { () -> mSession1.notifyViewsDisappeared(new AutofillId(42, 108), new long[] {666})); } @Ignore("b/286134492") @Test public void testNotifyViewsDisappeared_noSendTreeEventBeforeU() { MyContentCaptureSession session = new MyContentCaptureSession(121); Loading @@ -139,6 +141,7 @@ public class ContentCaptureSessionTest { assertThat(session.mInternalNotifyViewTreeEventFinishedCount).isEqualTo(0); } @Ignore("b/286134492") @EnableCompatChanges({ContentCaptureSession.NOTIFY_NODES_DISAPPEAR_NOW_SENDS_TREE_EVENTS}) @Test public void testNotifyViewsDisappeared_sendTreeEventSinceU() { Loading @@ -151,7 +154,7 @@ public class ContentCaptureSessionTest { @Test public void testGetFlushReasonAsString() { int invalidFlushReason = ContentCaptureSession.FLUSH_REASON_LOGIN_DETECTED + 1; int invalidFlushReason = ContentCaptureSession.FLUSH_REASON_VIEW_TREE_APPEARED + 1; Map<Integer, String> expectedMap = new ImmutableMap.Builder<Integer, String>() .put(ContentCaptureSession.FLUSH_REASON_FULL, "FULL") Loading @@ -168,8 +171,7 @@ public class ContentCaptureSessionTest { .put( ContentCaptureSession.FLUSH_REASON_VIEW_TREE_APPEARED, "VIEW_TREE_APPEARED") .put(ContentCaptureSession.FLUSH_REASON_LOGIN_DETECTED, "LOGIN_DETECTED") .put(invalidFlushReason, "UNKOWN-" + invalidFlushReason) .put(invalidFlushReason, "UNKNOWN-" + invalidFlushReason) .build(); expectedMap.forEach( Loading
services/contentcapture/java/com/android/server/contentprotection/RemoteContentProtectionService.java +5 −10 Original line number Diff line number Diff line Loading @@ -16,17 +16,15 @@ package com.android.server.contentprotection; import static android.view.contentcapture.ContentCaptureSession.FLUSH_REASON_LOGIN_DETECTED; import android.annotation.NonNull; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ParceledListSlice; import android.service.contentcapture.ContentCaptureService; import android.service.contentcapture.IContentProtectionService; import android.util.Slog; import android.view.contentcapture.ContentCaptureEvent; import android.view.contentcapture.IContentCaptureDirectManager; import com.android.internal.infra.ServiceConnector; Loading @@ -38,7 +36,7 @@ import java.time.Duration; * @hide */ public class RemoteContentProtectionService extends ServiceConnector.Impl<IContentCaptureDirectManager> { extends ServiceConnector.Impl<IContentProtectionService> { private static final String TAG = RemoteContentProtectionService.class.getSimpleName(); Loading @@ -57,7 +55,7 @@ public class RemoteContentProtectionService .setComponent(componentName), bindAllowInstant ? Context.BIND_ALLOW_INSTANT : 0, userId, IContentCaptureDirectManager.Stub::asInterface); IContentProtectionService.Stub::asInterface); mComponentName = componentName; } Loading @@ -68,7 +66,7 @@ public class RemoteContentProtectionService @Override // from ServiceConnector.Impl protected void onServiceConnectionStatusChanged( @NonNull IContentCaptureDirectManager service, boolean isConnected) { @NonNull IContentProtectionService service, boolean isConnected) { Slog.i( TAG, "Connection status for: " Loading @@ -78,9 +76,6 @@ public class RemoteContentProtectionService } public void onLoginDetected(@NonNull ParceledListSlice<ContentCaptureEvent> events) { run( service -> service.sendEvents( events, FLUSH_REASON_LOGIN_DETECTED, /* options= */ null)); run(service -> service.onLoginDetected(events)); } }