summaryrefslogtreecommitdiff
path: root/core/java/android
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/service/contentcapture/ContentCaptureEventsRequest.java12
-rw-r--r--core/java/android/service/contentcapture/ContentCaptureService.java154
-rw-r--r--core/java/android/service/contentcapture/IContentCaptureService.aidl12
-rw-r--r--core/java/android/view/contentcapture/ContentCaptureSession.java169
-rw-r--r--core/java/android/view/contentcapture/IContentCaptureDirectManager.aidl30
-rw-r--r--core/java/android/view/contentcapture/IContentCaptureManager.aidl10
6 files changed, 306 insertions, 81 deletions
diff --git a/core/java/android/service/contentcapture/ContentCaptureEventsRequest.java b/core/java/android/service/contentcapture/ContentCaptureEventsRequest.java
index df58f52dc59c..028180dd3bf0 100644
--- a/core/java/android/service/contentcapture/ContentCaptureEventsRequest.java
+++ b/core/java/android/service/contentcapture/ContentCaptureEventsRequest.java
@@ -17,6 +17,7 @@ package android.service.contentcapture;
import android.annotation.NonNull;
import android.annotation.SystemApi;
+import android.content.pm.ParceledListSlice;
import android.os.Parcel;
import android.os.Parcelable;
import android.view.contentcapture.ContentCaptureEvent;
@@ -31,10 +32,10 @@ import java.util.List;
@SystemApi
public final class ContentCaptureEventsRequest implements Parcelable {
- private final List<ContentCaptureEvent> mEvents;
+ private final ParceledListSlice<ContentCaptureEvent> mEvents;
/** @hide */
- public ContentCaptureEventsRequest(@NonNull List<ContentCaptureEvent> events) {
+ public ContentCaptureEventsRequest(@NonNull ParceledListSlice<ContentCaptureEvent> events) {
mEvents = events;
}
@@ -43,7 +44,7 @@ public final class ContentCaptureEventsRequest implements Parcelable {
*/
@NonNull
public List<ContentCaptureEvent> getEvents() {
- return mEvents;
+ return mEvents.getList();
}
@Override
@@ -53,7 +54,7 @@ public final class ContentCaptureEventsRequest implements Parcelable {
@Override
public void writeToParcel(Parcel parcel, int flags) {
- parcel.writeTypedList(mEvents, flags);
+ parcel.writeParcelable(mEvents, flags);
}
public static final Parcelable.Creator<ContentCaptureEventsRequest> CREATOR =
@@ -61,8 +62,7 @@ public final class ContentCaptureEventsRequest implements Parcelable {
@Override
public ContentCaptureEventsRequest createFromParcel(Parcel parcel) {
- return new ContentCaptureEventsRequest(parcel
- .createTypedArrayList(ContentCaptureEvent.CREATOR));
+ return new ContentCaptureEventsRequest(parcel.readParcelable(null));
}
@Override
diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java
index 58848fce43d6..953ccf1e4575 100644
--- a/core/java/android/service/contentcapture/ContentCaptureService.java
+++ b/core/java/android/service/contentcapture/ContentCaptureService.java
@@ -24,15 +24,27 @@ import android.annotation.SystemApi;
import android.app.Service;
import android.content.ComponentName;
import android.content.Intent;
+import android.content.pm.ParceledListSlice;
+import android.os.Binder;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
+import android.util.ArrayMap;
import android.util.Log;
+import android.util.Slog;
import android.view.contentcapture.ContentCaptureContext;
import android.view.contentcapture.ContentCaptureEvent;
+import android.view.contentcapture.ContentCaptureManager;
+import android.view.contentcapture.ContentCaptureSession;
import android.view.contentcapture.ContentCaptureSessionId;
+import android.view.contentcapture.IContentCaptureDirectManager;
+import com.android.internal.os.IResultReceiver;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.List;
import java.util.Set;
@@ -63,39 +75,54 @@ public abstract class ContentCaptureService extends Service {
private Handler mHandler;
- private final IContentCaptureService mInterface = new IContentCaptureService.Stub() {
+ /**
+ * Binder that receives calls from the system server.
+ */
+ private final IContentCaptureService mServerInterface = new IContentCaptureService.Stub() {
@Override
- public void onSessionLifecycle(ContentCaptureContext context, String sessionId)
- throws RemoteException {
- if (context != null) {
- mHandler.sendMessage(
- obtainMessage(ContentCaptureService::handleOnCreateSession,
- ContentCaptureService.this, context, sessionId));
- } else {
- mHandler.sendMessage(
- obtainMessage(ContentCaptureService::handleOnDestroySession,
- ContentCaptureService.this, sessionId));
- }
+ public void onSessionStarted(ContentCaptureContext context, String sessionId, int uid,
+ IResultReceiver clientReceiver) {
+ mHandler.sendMessage(obtainMessage(ContentCaptureService::handleOnCreateSession,
+ ContentCaptureService.this, context, sessionId, uid, clientReceiver));
}
@Override
- public void onContentCaptureEventsRequest(String sessionId,
- ContentCaptureEventsRequest request) {
+ public void onActivitySnapshot(String sessionId, SnapshotData snapshotData) {
mHandler.sendMessage(
- obtainMessage(ContentCaptureService::handleOnContentCaptureEventsRequest,
- ContentCaptureService.this, sessionId, request));
+ obtainMessage(ContentCaptureService::handleOnActivitySnapshot,
+ ContentCaptureService.this, sessionId, snapshotData));
+ }
+ @Override
+ public void onSessionFinished(String sessionId) {
+ mHandler.sendMessage(obtainMessage(ContentCaptureService::handleFinishSession,
+ ContentCaptureService.this, sessionId));
}
+ };
+
+ /**
+ * Binder that receives calls from the app.
+ */
+ private final IContentCaptureDirectManager mClientInterface =
+ new IContentCaptureDirectManager.Stub() {
@Override
- public void onActivitySnapshot(String sessionId, SnapshotData snapshotData) {
- mHandler.sendMessage(
- obtainMessage(ContentCaptureService::handleOnActivitySnapshot,
- ContentCaptureService.this, sessionId, snapshotData));
+ public void sendEvents(String sessionId,
+ @SuppressWarnings("rawtypes") ParceledListSlice events) {
+ mHandler.sendMessage(obtainMessage(ContentCaptureService::handleSendEvents,
+ ContentCaptureService.this, sessionId, Binder.getCallingUid(), events));
}
};
+ /**
+ * List of sessions per UID.
+ *
+ * <p>This map is populated when an session is started, which is called by the system server
+ * and can be trusted. Then subsequent calls made by the app are verified against this map.
+ */
+ private final ArrayMap<String, Integer> mSessionsByUid = new ArrayMap<>();
+
@CallSuper
@Override
public void onCreate() {
@@ -107,7 +134,7 @@ public abstract class ContentCaptureService extends Service {
@Override
public final IBinder onBind(Intent intent) {
if (SERVICE_INTERFACE.equals(intent.getAction())) {
- return mInterface.asBinder();
+ return mServerInterface.asBinder();
}
Log.w(TAG, "Tried to bind to wrong intent (should be " + SERVICE_INTERFACE + ": " + intent);
return null;
@@ -196,8 +223,10 @@ public abstract class ContentCaptureService extends Service {
* @param sessionId the session's Id
* @param request the events
*/
- public abstract void onContentCaptureEventsRequest(@NonNull ContentCaptureSessionId sessionId,
- @NonNull ContentCaptureEventsRequest request);
+ public void onContentCaptureEventsRequest(@NonNull ContentCaptureSessionId sessionId,
+ @NonNull ContentCaptureEventsRequest request) {
+ if (VERBOSE) Log.v(TAG, "onContentCaptureEventsRequest(id=" + sessionId + ")");
+ }
/**
* Notifies the service of {@link SnapshotData snapshot data} associated with a session.
@@ -212,10 +241,22 @@ public abstract class ContentCaptureService extends Service {
* Destroys the content capture session.
*
* @param sessionId the id of the session to destroy
- */
+ * */
public void onDestroyContentCaptureSession(@NonNull ContentCaptureSessionId sessionId) {
- if (VERBOSE) {
- Log.v(TAG, "onDestroyContentCaptureSession(id=" + sessionId + ")");
+ if (VERBOSE) Log.v(TAG, "onDestroyContentCaptureSession(id=" + sessionId + ")");
+ }
+
+ @Override
+ @CallSuper
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ final int size = mSessionsByUid.size();
+ pw.print("Number sessions: "); pw.println(size);
+ if (size > 0) {
+ final String prefix = " ";
+ for (int i = 0; i < size; i++) {
+ pw.print(prefix); pw.print(mSessionsByUid.keyAt(i));
+ pw.print(": uid="); pw.println(mSessionsByUid.valueAt(i));
+ }
}
}
@@ -223,13 +264,19 @@ public abstract class ContentCaptureService extends Service {
// so we don't need to create a temporary InteractionSessionId for each event.
private void handleOnCreateSession(@NonNull ContentCaptureContext context,
- @NonNull String sessionId) {
+ @NonNull String sessionId, int uid, IResultReceiver clientReceiver) {
+ mSessionsByUid.put(sessionId, uid);
onCreateContentCaptureSession(context, new ContentCaptureSessionId(sessionId));
+ setClientState(clientReceiver, ContentCaptureSession.STATE_ACTIVE,
+ mClientInterface.asBinder());
}
- private void handleOnContentCaptureEventsRequest(@NonNull String sessionId,
- @NonNull ContentCaptureEventsRequest request) {
- onContentCaptureEventsRequest(new ContentCaptureSessionId(sessionId), request);
+ private void handleSendEvents(@NonNull String sessionId, int uid,
+ @NonNull ParceledListSlice<ContentCaptureEvent> events) {
+ if (handleIsRightCallerFor(sessionId, uid)) {
+ onContentCaptureEventsRequest(new ContentCaptureSessionId(sessionId),
+ new ContentCaptureEventsRequest(events));
+ }
}
private void handleOnActivitySnapshot(@NonNull String sessionId,
@@ -237,7 +284,52 @@ public abstract class ContentCaptureService extends Service {
onActivitySnapshot(new ContentCaptureSessionId(sessionId), snapshotData);
}
- private void handleOnDestroySession(@NonNull String sessionId) {
+ private void handleFinishSession(@NonNull String sessionId) {
+ mSessionsByUid.remove(sessionId);
onDestroyContentCaptureSession(new ContentCaptureSessionId(sessionId));
}
+
+ /**
+ * Checks if the given {@code uid} owns the session.
+ */
+ private boolean handleIsRightCallerFor(@NonNull String sessionId, int uid) {
+ final Integer rightUid = mSessionsByUid.get(sessionId);
+ if (rightUid == null) {
+ if (VERBOSE) Log.v(TAG, "No session for " + sessionId);
+ // Just ignore, as the session could have finished
+ return false;
+ }
+ if (rightUid != uid) {
+ Log.e(TAG, "invalid call from UID " + uid + ": session " + sessionId + " belongs to "
+ + rightUid);
+ //TODO(b/111276913): log metrics as this could be a malicious app forging a sessionId
+ return false;
+ }
+ return true;
+
+ }
+
+ /**
+ * Sends the state of the {@link ContentCaptureManager} in the cleint app.
+ *
+ * @param clientReceiver receiver in the client app.
+ * @param binder handle to the {@code IContentCaptureDirectManager} object that resides in the
+ * service.
+ * @hide
+ */
+ public static void setClientState(@NonNull IResultReceiver clientReceiver,
+ int sessionStatus, @Nullable IBinder binder) {
+ try {
+ final Bundle extras;
+ if (binder != null) {
+ extras = new Bundle();
+ extras.putBinder(ContentCaptureSession.EXTRA_BINDER, binder);
+ } else {
+ extras = null;
+ }
+ clientReceiver.send(sessionStatus, extras);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Error async reporting result to client: " + e);
+ }
+ }
}
diff --git a/core/java/android/service/contentcapture/IContentCaptureService.aidl b/core/java/android/service/contentcapture/IContentCaptureService.aidl
index 8167be9e6838..20e8e99d4ce1 100644
--- a/core/java/android/service/contentcapture/IContentCaptureService.aidl
+++ b/core/java/android/service/contentcapture/IContentCaptureService.aidl
@@ -16,10 +16,11 @@
package android.service.contentcapture;
-import android.service.contentcapture.ContentCaptureEventsRequest;
import android.service.contentcapture.SnapshotData;
import android.view.contentcapture.ContentCaptureContext;
+import com.android.internal.os.IResultReceiver;
+
import java.util.List;
/**
@@ -28,11 +29,8 @@ import java.util.List;
* @hide
*/
oneway interface IContentCaptureService {
-
- // Called when session is created (context not null) or destroyed (context null)
- void onSessionLifecycle(in ContentCaptureContext context, String sessionId);
-
- void onContentCaptureEventsRequest(String sessionId, in ContentCaptureEventsRequest request);
-
+ void onSessionStarted(in ContentCaptureContext context, String sessionId, int uid,
+ in IResultReceiver clientReceiver);
+ void onSessionFinished(String sessionId);
void onActivitySnapshot(String sessionId, in SnapshotData snapshotData);
}
diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java
index 632955d335cf..f411cf751b47 100644
--- a/core/java/android/view/contentcapture/ContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ContentCaptureSession.java
@@ -27,9 +27,11 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
+import android.content.pm.ParceledListSlice;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
+import android.os.IBinder.DeathRecipient;
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.Log;
@@ -45,6 +47,8 @@ import dalvik.system.CloseGuard;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -100,6 +104,13 @@ public final class ContentCaptureSession implements AutoCloseable {
public static final int STATE_DISABLED = 3;
/**
+ * Session is disabled because its id already existed on server.
+ *
+ * @hide
+ */
+ public static final int STATE_DISABLED_DUPLICATED_ID = 4;
+
+ /**
* Handler message used to flush the buffer.
*/
private static final int MSG_FLUSH = 1;
@@ -116,6 +127,13 @@ public final class ContentCaptureSession implements AutoCloseable {
// TODO(b/121044064): use settings
private static final int FLUSHING_FREQUENCY_MS = 5_000;
+
+ /**
+ * Name of the {@link IResultReceiver} extra used to pass the binder interface to the service.
+ * @hide
+ */
+ public static final String EXTRA_BINDER = "binder";
+
private final CloseGuard mCloseGuard = CloseGuard.get();
@NonNull
@@ -127,8 +145,21 @@ public final class ContentCaptureSession implements AutoCloseable {
@NonNull
private final Handler mHandler;
+ /**
+ * Interface to the system_server binder object - it's only used to start the session (and
+ * notify when the session is finished).
+ */
@Nullable
- private final IContentCaptureManager mService;
+ private final IContentCaptureManager mSystemServerInterface;
+
+ /**
+ * Direct interface to the service binder object - it's used to send the events, including the
+ * last ones (when the session is finished)
+ */
+ @Nullable
+ private IContentCaptureDirectManager mDirectServiceInterface;
+ @Nullable
+ private DeathRecipient mDirectServiceVulture;
@Nullable
private final String mId = UUID.randomUUID().toString();
@@ -165,11 +196,11 @@ public final class ContentCaptureSession implements AutoCloseable {
/** @hide */
protected ContentCaptureSession(@NonNull Context context, @NonNull Handler handler,
- @Nullable IContentCaptureManager service, @NonNull AtomicBoolean disabled,
+ @Nullable IContentCaptureManager systemServerInterface, @NonNull AtomicBoolean disabled,
@Nullable ContentCaptureContext clientContext) {
mContext = context;
mHandler = handler;
- mService = service;
+ mSystemServerInterface = systemServerInterface;
mDisabled = disabled;
mClientContext = clientContext;
mCloseGuard.open("destroy");
@@ -227,6 +258,8 @@ public final class ContentCaptureSession implements AutoCloseable {
Log.v(TAG, "destroy(): state=" + getStateAsString(mState) + ", mId=" + mId);
}
+ flush();
+
mHandler.sendMessage(obtainMessage(ContentCaptureSession::handleDestroySession, this));
mCloseGuard.close();
}
@@ -267,11 +300,20 @@ public final class ContentCaptureSession implements AutoCloseable {
final int flags = 0; // TODO(b/111276913): get proper flags
try {
- mService.startSession(mContext.getUserId(), mApplicationToken, componentName,
- mId, mClientContext, flags, new IResultReceiver.Stub() {
+ mSystemServerInterface.startSession(mContext.getUserId(), mApplicationToken,
+ componentName, mId, mClientContext, flags, new IResultReceiver.Stub() {
@Override
public void send(int resultCode, Bundle resultData) {
- handleSessionStarted(resultCode);
+ IBinder binder = null;
+ if (resultData != null) {
+ binder = resultData.getBinder(EXTRA_BINDER);
+ if (binder == null) {
+ Log.wtf(TAG, "No " + EXTRA_BINDER + " extra result");
+ handleResetState();
+ return;
+ }
+ }
+ handleSessionStarted(resultCode, binder);
}
});
} catch (RemoteException e) {
@@ -280,12 +322,38 @@ public final class ContentCaptureSession implements AutoCloseable {
}
}
- private void handleSessionStarted(int resultCode) {
+ /**
+ * Callback from {@code system_server} after call to
+ * {@link IContentCaptureManager#startSession(int, IBinder, ComponentName, String,
+ * ContentCaptureContext, int, IResultReceiver)}.
+ *
+ * @param resultCode session state
+ * @param binder handle to {@link IContentCaptureDirectManager}
+ */
+ private void handleSessionStarted(int resultCode, @Nullable IBinder binder) {
mState = resultCode;
- mDisabled.set(mState == STATE_DISABLED);
+ if (binder != null) {
+ mDirectServiceInterface = IContentCaptureDirectManager.Stub.asInterface(binder);
+ mDirectServiceVulture = () -> {
+ Log.w(TAG, "Destroying session " + mId + " because service died");
+ destroy();
+ };
+ try {
+ binder.linkToDeath(mDirectServiceVulture, 0);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to link to death on " + binder + ": " + e);
+ }
+ }
+ if (resultCode == STATE_DISABLED || resultCode == STATE_DISABLED_DUPLICATED_ID) {
+ mDisabled.set(true);
+ handleResetSession(/* resetState= */ false);
+ } else {
+ mDisabled.set(false);
+ }
if (VERBOSE) {
Log.v(TAG, "handleSessionStarted() result: code=" + resultCode + ", id=" + mId
- + ", state=" + getStateAsString(mState) + ", disabled=" + mDisabled.get());
+ + ", state=" + getStateAsString(mState) + ", disabled=" + mDisabled.get()
+ + ", binder=" + binder);
}
}
@@ -307,7 +375,7 @@ public final class ContentCaptureSession implements AutoCloseable {
final boolean bufferEvent = numberEvents < MAX_BUFFER_SIZE;
if (bufferEvent && !forceFlush) {
- handleScheduleFlush();
+ handleScheduleFlush(/* checkExisting= */ true);
return;
}
@@ -331,8 +399,8 @@ public final class ContentCaptureSession implements AutoCloseable {
handleForceFlush();
}
- private void handleScheduleFlush() {
- if (mHandler.hasMessages(MSG_FLUSH)) {
+ private void handleScheduleFlush(boolean checkExisting) {
+ if (checkExisting && mHandler.hasMessages(MSG_FLUSH)) {
// "Renew" the flush message by removing the previous one
mHandler.removeMessages(MSG_FLUSH);
}
@@ -356,52 +424,80 @@ public final class ContentCaptureSession implements AutoCloseable {
private void handleForceFlush() {
if (mEvents == null) return;
+ if (mDirectServiceInterface == null) {
+ Log.w(TAG, "handleForceFlush(): client not available yet");
+ if (!mHandler.hasMessages(MSG_FLUSH)) {
+ handleScheduleFlush(/* checkExisting= */ false);
+ }
+ return;
+ }
+
final int numberEvents = mEvents.size();
try {
if (DEBUG) {
Log.d(TAG, "Flushing " + numberEvents + " event(s) for " + getActivityDebugName());
}
mHandler.removeMessages(MSG_FLUSH);
- mService.sendEvents(mContext.getUserId(), mId, mEvents);
- // TODO(b/111276913): decide whether we should clear or set it to null, as each has
- // its own advantages: clearing will save extra allocations while the session is
- // active, while setting to null would save memory if there's no more event coming.
- mEvents.clear();
+
+ final ParceledListSlice<ContentCaptureEvent> events = handleClearEvents();
+ mDirectServiceInterface.sendEvents(mId, events);
} catch (RemoteException e) {
Log.w(TAG, "Error sending " + numberEvents + " for " + getActivityDebugName()
+ ": " + e);
}
}
+ /**
+ * Resets the buffer and return a {@link ParceledListSlice} with the previous events.
+ */
+ @NonNull
+ private ParceledListSlice<ContentCaptureEvent> handleClearEvents() {
+ // NOTE: we must save a reference to the current mEvents and then set it to to null,
+ // otherwise clearing it would clear it in the receiving side if the service is also local.
+ final List<ContentCaptureEvent> events = mEvents == null
+ ? Collections.emptyList()
+ : mEvents;
+ mEvents = null;
+ return new ParceledListSlice<>(events);
+ }
+
private void handleDestroySession() {
//TODO(b/111276913): right now both the ContentEvents and lifecycle sessions are sent
// to system_server, so it's ok to call both in sequence here. But once we split
// them so the events are sent directly to the service, we need to make sure they're
// sent in order.
- try {
- if (DEBUG) {
- Log.d(TAG, "Destroying session (ctx=" + mContext + ", id=" + mId + ") with "
- + (mEvents == null ? 0 : mEvents.size()) + " event(s) for "
- + getActivityDebugName());
- }
+ if (DEBUG) {
+ Log.d(TAG, "Destroying session (ctx=" + mContext + ", id=" + mId + ") with "
+ + (mEvents == null ? 0 : mEvents.size()) + " event(s) for "
+ + getActivityDebugName());
+ }
- mService.finishSession(mContext.getUserId(), mId, mEvents);
+ try {
+ mSystemServerInterface.finishSession(mContext.getUserId(), mId);
} catch (RemoteException e) {
- Log.e(TAG, "Error destroying session " + mId + " for " + getActivityDebugName()
- + ": " + e);
- } finally {
- handleResetState();
+ Log.e(TAG, "Error destroying system-service session " + mId + " for "
+ + getActivityDebugName() + ": " + e);
}
}
+ private void handleResetState() {
+ handleResetSession(/* resetState= */ true);
+ }
+
// TODO(b/111276913): once we support multiple sessions, we might need to move some of these
// clearings out.
- private void handleResetState() {
- mState = STATE_UNKNOWN;
+ private void handleResetSession(boolean resetState) {
+ if (resetState) {
+ mState = STATE_UNKNOWN;
+ }
mContentCaptureSessionId = null;
mApplicationToken = null;
mComponentName = null;
mEvents = null;
+ if (mDirectServiceInterface != null) {
+ mDirectServiceInterface.asBinder().unlinkToDeath(mDirectServiceVulture, 0);
+ }
+ mDirectServiceInterface = null;
mHandler.removeMessages(MSG_FLUSH);
}
@@ -492,15 +588,20 @@ public final class ContentCaptureSession implements AutoCloseable {
}
private boolean isContentCaptureEnabled() {
- return mService != null && !mDisabled.get();
+ return mSystemServerInterface != null && !mDisabled.get();
}
void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
pw.print(prefix); pw.print("id: "); pw.println(mId);
pw.print(prefix); pw.print("mContext: "); pw.println(mContext);
pw.print(prefix); pw.print("user: "); pw.println(mContext.getUserId());
- if (mService != null) {
- pw.print(prefix); pw.print("mService: "); pw.println(mService);
+ if (mSystemServerInterface != null) {
+ pw.print(prefix); pw.print("mSystemServerInterface: ");
+ pw.println(mSystemServerInterface);
+ }
+ if (mDirectServiceInterface != null) {
+ pw.print(prefix); pw.print("mDirectServiceInterface: ");
+ pw.println(mDirectServiceInterface);
}
if (mClientContext != null) {
// NOTE: we don't dump clientContent because it could have PII
@@ -563,6 +664,8 @@ public final class ContentCaptureSession implements AutoCloseable {
return "ACTIVE";
case STATE_DISABLED:
return "DISABLED";
+ case STATE_DISABLED_DUPLICATED_ID:
+ return "DISABLED_DUPLICATED_ID";
default:
return "INVALID:" + state;
}
diff --git a/core/java/android/view/contentcapture/IContentCaptureDirectManager.aidl b/core/java/android/view/contentcapture/IContentCaptureDirectManager.aidl
new file mode 100644
index 000000000000..145fc16707a1
--- /dev/null
+++ b/core/java/android/view/contentcapture/IContentCaptureDirectManager.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 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.view.contentcapture;
+
+import android.content.pm.ParceledListSlice;
+import android.view.contentcapture.ContentCaptureEvent;
+
+/**
+ * Interface between an app (ContentCaptureManager / ContentCaptureSession) and the app providing
+ * the ContentCaptureService implementation.
+ *
+ * @hide
+ */
+oneway interface IContentCaptureDirectManager {
+ void sendEvents(in String sessionId, in ParceledListSlice events);
+}
diff --git a/core/java/android/view/contentcapture/IContentCaptureManager.aidl b/core/java/android/view/contentcapture/IContentCaptureManager.aidl
index 2002c5c1fc9a..cbd37017038e 100644
--- a/core/java/android/view/contentcapture/IContentCaptureManager.aidl
+++ b/core/java/android/view/contentcapture/IContentCaptureManager.aidl
@@ -26,12 +26,14 @@ import com.android.internal.os.IResultReceiver;
import java.util.List;
/**
- * {@hide}
- */
+ * Interface between an app (ContentCaptureManager / ContentCaptureSession) and the system-server
+ * implementation service (ContentCaptureManagerService).
+ *
+ * @hide
+ */
oneway interface IContentCaptureManager {
void startSession(int userId, IBinder activityToken, in ComponentName componentName,
String sessionId, in ContentCaptureContext clientContext, int flags,
in IResultReceiver result);
- void finishSession(int userId, String sessionId, in List<ContentCaptureEvent> events);
- void sendEvents(int userId, in String sessionId, in List<ContentCaptureEvent> events);
+ void finishSession(int userId, String sessionId);
}