From 7a53408d196d6a288d9a6745d98db697cb2a411f Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Mon, 5 Nov 2018 15:03:04 -0800 Subject: [PATCH] Initial implementation of IntelligenceService.onContentCaptureEvents() It's only implementing the activity lifecycle events, but at least they're fed end-to-end in the pipeline (from app to service implementation). Test: mmm -j packages/experimental/FillService && \ adb install -r ${OUT}/data/app/FillService/FillService.apk && \ adb shell settings put secure intel_service foo.bar.fill/.AiaiService Bug: 111276913 Change-Id: I2f46be1e6a6a21ad909e5fffea01bedaa28fb300 --- core/java/android/app/Activity.java | 41 +++++++-- .../intelligence/IIntelligenceService.aidl | 8 ++ .../intelligence/IntelligenceService.java | 9 ++ .../intelligence/ContentCaptureEvent.aidl | 19 ++++ .../intelligence/ContentCaptureEvent.java | 66 ++++++++++++-- .../intelligence/IIntelligenceManager.aidl | 14 +++ .../intelligence/IntelligenceManager.java | 36 ++++++++ .../intelligence/ContentCaptureSession.java | 13 ++- .../IntelligenceManagerService.java | 14 +++ .../IntelligencePerUserService.java | 17 ++++ .../RemoteIntelligenceService.java | 86 +++++++++++++++---- .../android/server/AbstractRemoteService.java | 5 +- 12 files changed, 289 insertions(+), 39 deletions(-) create mode 100644 core/java/android/view/intelligence/ContentCaptureEvent.aidl diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 8d54e91b93e45..86ed267eafdbb 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -120,6 +120,7 @@ import android.view.autofill.AutofillManager; import android.view.autofill.AutofillManager.AutofillClient; import android.view.autofill.AutofillPopupWindow; import android.view.autofill.IAutofillWindowPresenter; +import android.view.intelligence.ContentCaptureEvent; import android.view.intelligence.IntelligenceManager; import android.widget.AdapterView; import android.widget.Toast; @@ -1023,6 +1024,31 @@ public class Activity extends ContextThemeWrapper return mIntelligenceManager; } + private void notifyIntelligenceManagerIfNeeded(@ContentCaptureEvent.EventType int event) { + final IntelligenceManager im = getIntelligenceManager(); + if (im == null || !im.isContentCaptureEnabled()) { + return; + } + switch (event) { + case ContentCaptureEvent.TYPE_ACTIVITY_CREATED: + //TODO(b/111276913): decide whether the InteractionSessionId should be + // saved / restored in the activity bundle. + im.onActivityCreated(mToken, getComponentName()); + break; + case ContentCaptureEvent.TYPE_ACTIVITY_DESTROYED: + im.onActivityDestroyed(); + break; + case ContentCaptureEvent.TYPE_ACTIVITY_STARTED: + case ContentCaptureEvent.TYPE_ACTIVITY_RESUMED: + case ContentCaptureEvent.TYPE_ACTIVITY_PAUSED: + case ContentCaptureEvent.TYPE_ACTIVITY_STOPPED: + im.onActivityLifecycleEvent(event); + break; + default: + Log.w(TAG, "notifyIntelligenceManagerIfNeeded(): invalid type " + event); + } + } + @Override protected void attachBaseContext(Context newBase) { super.attachBaseContext(newBase); @@ -1099,11 +1125,7 @@ public class Activity extends ContextThemeWrapper mRestoredFromBundle = savedInstanceState != null; mCalled = true; - if (getIntelligenceManager() != null) { - //TODO(b/111276913): decide whether the screen_obs session id should be saved / restored - // in the activity bundle. - mIntelligenceManager.onActivityCreated(mToken, getComponentName()); - } + notifyIntelligenceManagerIfNeeded(ContentCaptureEvent.TYPE_ACTIVITY_CREATED); } /** @@ -1337,6 +1359,7 @@ public class Activity extends ContextThemeWrapper if (mAutoFillResetNeeded) { getAutofillManager().onVisibleForAutofill(); } + notifyIntelligenceManagerIfNeeded(ContentCaptureEvent.TYPE_ACTIVITY_STARTED); } /** @@ -1419,6 +1442,7 @@ public class Activity extends ContextThemeWrapper } } } + notifyIntelligenceManagerIfNeeded(ContentCaptureEvent.TYPE_ACTIVITY_RESUMED); mCalled = true; } @@ -1812,6 +1836,7 @@ public class Activity extends ContextThemeWrapper mAutoFillIgnoreFirstResumePause = false; } } + notifyIntelligenceManagerIfNeeded(ContentCaptureEvent.TYPE_ACTIVITY_PAUSED); mCalled = true; } @@ -2000,6 +2025,7 @@ public class Activity extends ContextThemeWrapper getAutofillManager().onPendingSaveUi(AutofillManager.PENDING_UI_OPERATION_CANCEL, mIntent.getIBinderExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN)); } + notifyIntelligenceManagerIfNeeded(ContentCaptureEvent.TYPE_ACTIVITY_STOPPED); } } @@ -2071,9 +2097,8 @@ public class Activity extends ContextThemeWrapper getApplication().dispatchActivityDestroyed(this); - if (getIntelligenceManager() != null) { - mIntelligenceManager.onActivityDestroyed(); - } + notifyIntelligenceManagerIfNeeded(ContentCaptureEvent.TYPE_ACTIVITY_DESTROYED); + } /** diff --git a/core/java/android/service/intelligence/IIntelligenceService.aidl b/core/java/android/service/intelligence/IIntelligenceService.aidl index ee93326d2e3cf..bacad8b447831 100644 --- a/core/java/android/service/intelligence/IIntelligenceService.aidl +++ b/core/java/android/service/intelligence/IIntelligenceService.aidl @@ -19,6 +19,11 @@ package android.service.intelligence; import android.service.intelligence.InteractionSessionId; import android.service.intelligence.InteractionContext; +import android.view.intelligence.ContentCaptureEvent; + +import java.util.List; + + /** * Interface from the system to an intelligence service. * @@ -28,4 +33,7 @@ oneway interface IIntelligenceService { // Called when session is created (context not null) or destroyed (context null) void onSessionLifecycle(in InteractionContext context, in InteractionSessionId sessionId); + + void onContentCaptureEvents(in InteractionSessionId sessionId, + in List events); } diff --git a/core/java/android/service/intelligence/IntelligenceService.java b/core/java/android/service/intelligence/IntelligenceService.java index ce0a88a3faca6..a2b60f044657e 100644 --- a/core/java/android/service/intelligence/IntelligenceService.java +++ b/core/java/android/service/intelligence/IntelligenceService.java @@ -70,6 +70,14 @@ public abstract class IntelligenceService extends Service { IntelligenceService.this, sessionId)); } } + @Override + public void onContentCaptureEvents(InteractionSessionId sessionId, + List events) { + mHandler.sendMessage( + obtainMessage(IntelligenceService::onContentCaptureEvent, + IntelligenceService.this, sessionId, events)); + + } }; @CallSuper @@ -105,6 +113,7 @@ public abstract class IntelligenceService extends Service { * @param sessionId the session's Id * @param events the events */ + // TODO(b/111276913): rename to onContentCaptureEvents public abstract void onContentCaptureEvent(@NonNull InteractionSessionId sessionId, @NonNull List events); diff --git a/core/java/android/view/intelligence/ContentCaptureEvent.aidl b/core/java/android/view/intelligence/ContentCaptureEvent.aidl new file mode 100644 index 0000000000000..c66a6cb0d486b --- /dev/null +++ b/core/java/android/view/intelligence/ContentCaptureEvent.aidl @@ -0,0 +1,19 @@ +/* + * 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.intelligence; + +parcelable ContentCaptureEvent; diff --git a/core/java/android/view/intelligence/ContentCaptureEvent.java b/core/java/android/view/intelligence/ContentCaptureEvent.java index d6aec344171d0..2530ae3b31240 100644 --- a/core/java/android/view/intelligence/ContentCaptureEvent.java +++ b/core/java/android/view/intelligence/ContentCaptureEvent.java @@ -30,6 +30,11 @@ import java.lang.annotation.RetentionPolicy; @SystemApi public final class ContentCaptureEvent implements Parcelable { + /** @hide */ + public static final int TYPE_ACTIVITY_DESTROYED = -2; + /** @hide */ + public static final int TYPE_ACTIVITY_CREATED = -1; + /** * Called when the activity is started. */ @@ -85,10 +90,18 @@ public final class ContentCaptureEvent implements Parcelable { TYPE_VIEW_TEXT_CHANGED }) @Retention(RetentionPolicy.SOURCE) - @interface EventType{} + public @interface EventType{} + + private final int mType; + private final long mEventTime; + private final int mFlags; + /** @hide */ - ContentCaptureEvent() { + public ContentCaptureEvent(int type, long eventTime, int flags) { + mType = type; + mEventTime = eventTime; + mFlags = flags; } /** @@ -99,14 +112,14 @@ public final class ContentCaptureEvent implements Parcelable { * {@link #TYPE_VIEW_ADDED}, {@link #TYPE_VIEW_REMOVED}, or {@link #TYPE_VIEW_TEXT_CHANGED}. */ public @EventType int getType() { - return 42; + return mType; } /** * Gets when the event was generated, in ms. */ public long getEventTime() { - return 48151623; + return mEventTime; } /** @@ -116,7 +129,7 @@ public final class ContentCaptureEvent implements Parcelable { * {@link android.view.intelligence.IntelligenceManager#FLAG_USER_INPUT}. */ public int getFlags() { - return 0; + return mFlags; } /** @@ -149,6 +162,16 @@ public final class ContentCaptureEvent implements Parcelable { return null; } + @Override + public String toString() { + final StringBuilder string = new StringBuilder("ContentCaptureEvent[type=") + .append(getTypeAsString(mType)).append(", time=").append(mEventTime); + if (mFlags > 0) { + string.append(", flags=").append(mFlags); + } + return string.append(']').toString(); + } + @Override public int describeContents() { return 0; @@ -156,7 +179,9 @@ public final class ContentCaptureEvent implements Parcelable { @Override public void writeToParcel(Parcel parcel, int flags) { - // TODO(b/111276913): implement + parcel.writeInt(mType); + parcel.writeLong(mEventTime); + parcel.writeInt(mFlags); } public static final Parcelable.Creator CREATOR = @@ -164,8 +189,10 @@ public final class ContentCaptureEvent implements Parcelable { @Override public ContentCaptureEvent createFromParcel(Parcel parcel) { - // TODO(b/111276913): implement - return null; + final int type = parcel.readInt(); + final long eventTime = parcel.readLong(); + final int flags = parcel.readInt(); + return new ContentCaptureEvent(type, eventTime, flags); } @Override @@ -173,4 +200,27 @@ public final class ContentCaptureEvent implements Parcelable { return new ContentCaptureEvent[size]; } }; + + + /** @hide */ + public static String getTypeAsString(@EventType int type) { + switch (type) { + case TYPE_ACTIVITY_STARTED: + return "ACTIVITY_STARTED"; + case TYPE_ACTIVITY_RESUMED: + return "ACTIVITY_RESUMED"; + case TYPE_ACTIVITY_PAUSED: + return "ACTIVITY_PAUSED"; + case TYPE_ACTIVITY_STOPPED: + return "ACTIVITY_STOPPED"; + case TYPE_VIEW_ADDED: + return "VIEW_ADDED"; + case TYPE_VIEW_REMOVED: + return "VIEW_REMOVED"; + case TYPE_VIEW_TEXT_CHANGED: + return "VIEW_TEXT_CHANGED"; + default: + return "UKNOWN_TYPE: " + type; + } + } } diff --git a/core/java/android/view/intelligence/IIntelligenceManager.aidl b/core/java/android/view/intelligence/IIntelligenceManager.aidl index f4901c371614a..7bbe99a9ad480 100644 --- a/core/java/android/view/intelligence/IIntelligenceManager.aidl +++ b/core/java/android/view/intelligence/IIntelligenceManager.aidl @@ -17,9 +17,15 @@ package android.view.intelligence; import android.content.ComponentName; + import android.os.IBinder; + +import android.view.intelligence.ContentCaptureEvent; + import com.android.internal.os.IResultReceiver; +import java.util.List; + /** * {@hide} */ @@ -33,6 +39,14 @@ oneway interface IIntelligenceManager { /** * Finishes a session. */ + // TODO(b/111276913): pass just (global) session id void finishSession(int userId, IBinder activityToken, in ComponentName componentName, int localSessionId, int globalSessionId); + + /** + * Sends a batch of events + */ + // TODO(b/111276913): pass just (global) session id + void sendEvents(int userId, IBinder activityToken, in ComponentName componentName, + int localSessionId, int globalSessionId, in List events); } diff --git a/core/java/android/view/intelligence/IntelligenceManager.java b/core/java/android/view/intelligence/IntelligenceManager.java index b1d06f7fccfdf..a30d77e4d446c 100644 --- a/core/java/android/view/intelligence/IntelligenceManager.java +++ b/core/java/android/view/intelligence/IntelligenceManager.java @@ -24,13 +24,17 @@ import android.content.Context; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; +import android.os.SystemClock; import android.util.Log; +import android.view.intelligence.ContentCaptureEvent.EventType; import com.android.internal.annotations.GuardedBy; import com.android.internal.os.IResultReceiver; import com.android.internal.util.Preconditions; import java.io.PrintWriter; +import java.util.Arrays; +import java.util.List; import java.util.Set; /** @@ -161,6 +165,38 @@ public final class IntelligenceManager { } } + /** + * Used for intermediate events (i.e, other than created and destroyed). + * + * @hide + */ + public void onActivityLifecycleEvent(@EventType int type) { + if (!isContentCaptureEnabled()) return; + + //TODO(b/111276913): should buffer event (and call service on handler thread), instead of + // calling right away + final ContentCaptureEvent event = new ContentCaptureEvent(type, SystemClock.uptimeMillis(), + 0); + final List events = Arrays.asList(event); + + synchronized (mLock) { + //TODO(b/111276913): check session state; for example, how to handle if it's waiting for + // remote id + + if (VERBOSE) { + Log.v(TAG, "onActivityLifecycleEvent() for " + mComponentName.flattenToShortString() + + ": " + ContentCaptureEvent.getTypeAsString(type)); + } + + try { + mService.sendEvents(mContext.getUserId(), mApplicationToken, mComponentName, + mLocalSessionId, mRemoteSessionId, events); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + /** @hide */ public void onActivityDestroyed() { if (!isContentCaptureEnabled()) return; diff --git a/services/autofill/java/com/android/server/intelligence/ContentCaptureSession.java b/services/autofill/java/com/android/server/intelligence/ContentCaptureSession.java index a437a390a0e67..14b28d32d22ae 100644 --- a/services/autofill/java/com/android/server/intelligence/ContentCaptureSession.java +++ b/services/autofill/java/com/android/server/intelligence/ContentCaptureSession.java @@ -23,12 +23,14 @@ import android.service.intelligence.IntelligenceService; import android.service.intelligence.InteractionContext; import android.service.intelligence.InteractionSessionId; import android.util.Slog; +import android.view.intelligence.ContentCaptureEvent; import com.android.internal.annotations.GuardedBy; import com.android.server.AbstractRemoteService; import com.android.server.intelligence.RemoteIntelligenceService.RemoteIntelligenceServiceCallbacks; import java.io.PrintWriter; +import java.util.List; final class ContentCaptureSession implements RemoteIntelligenceServiceCallbacks { @@ -65,6 +67,13 @@ final class ContentCaptureSession implements RemoteIntelligenceServiceCallbacks mRemoteService.onSessionLifecycleRequest(mInterationContext, mId); } + /** + * Notifies the {@link IntelligenceService} of a batch of events. + */ + public void sendEventsLocked(List events) { + mRemoteService.onContentCaptureEventsRequest(mId, events); + } + /** * Cleans up the session and remove itself from the service. * @@ -95,10 +104,10 @@ final class ContentCaptureSession implements RemoteIntelligenceServiceCallbacks } @Override // from RemoteScreenObservationServiceCallbacks - public void onSessionLifecycleRequestFailureOrTimeout(boolean timedOut) { + public void onFailureOrTimeout(boolean timedOut) { // TODO(b/111276913): log metrics on whether timed out or not if (mService.isDebug()) { - Slog.d(TAG, "onSessionLifecycleRequestFailure(" + mId + "): timed out=" + timedOut); + Slog.d(TAG, "onFailureOrTimeout(" + mId + "): timed out=" + timedOut); } synchronized (mLock) { removeSelfLocked(/* notifyRemoteService= */ false); diff --git a/services/autofill/java/com/android/server/intelligence/IntelligenceManagerService.java b/services/autofill/java/com/android/server/intelligence/IntelligenceManagerService.java index 4ea90364f9364..d67c15b01f0c7 100644 --- a/services/autofill/java/com/android/server/intelligence/IntelligenceManagerService.java +++ b/services/autofill/java/com/android/server/intelligence/IntelligenceManagerService.java @@ -24,6 +24,7 @@ import android.content.ComponentName; import android.content.Context; import android.os.IBinder; import android.os.UserManager; +import android.view.intelligence.ContentCaptureEvent; import android.view.intelligence.IIntelligenceManager; import com.android.internal.annotations.GuardedBy; @@ -35,6 +36,7 @@ import com.android.server.LocalServices; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.List; /** * A service used to observe the contents of the screen. @@ -103,6 +105,18 @@ public final class IntelligenceManagerService } } + @Override + public void sendEvents(int userId, @NonNull IBinder activityToken, + @NonNull ComponentName componentName, int localSessionId, int globalSessionId, + List events) { + Preconditions.checkNotNull(events); + + synchronized (mLock) { + final IntelligencePerUserService service = getServiceForUserLocked(userId); + service.sendEventsLocked(componentName, events); + } + } + @Override public void finishSession(int userId, @NonNull IBinder activityToken, @NonNull ComponentName componentName, int localSessionId, int globalSessionId) { diff --git a/services/autofill/java/com/android/server/intelligence/IntelligencePerUserService.java b/services/autofill/java/com/android/server/intelligence/IntelligencePerUserService.java index b62b239ab83ef..1d988192125c6 100644 --- a/services/autofill/java/com/android/server/intelligence/IntelligencePerUserService.java +++ b/services/autofill/java/com/android/server/intelligence/IntelligencePerUserService.java @@ -27,12 +27,14 @@ import android.os.IBinder; import android.os.RemoteException; import android.util.ArrayMap; import android.util.Slog; +import android.view.intelligence.ContentCaptureEvent; import com.android.internal.annotations.GuardedBy; import com.android.internal.os.IResultReceiver; import com.android.server.AbstractPerUserSystemService; import java.io.PrintWriter; +import java.util.List; /** * Per-user instance of {@link IntelligenceManagerService}. @@ -141,6 +143,20 @@ final class IntelligencePerUserService session.removeSelfLocked(true); } + @GuardedBy("mLock") + public void sendEventsLocked(@NonNull ComponentName componentName, + @NonNull List events) { + final ContentCaptureSession session = mSessions.get(componentName); + if (session == null) { + Slog.w(TAG, "sendEventsLocked(): no session for " + componentName); + return; + } + if (mMaster.verbose) { + Slog.v(TAG, "sendEventsLocked(): comp=" + componentName + "; events =" + events.size()); + } + session.sendEventsLocked(events); + } + @GuardedBy("mLock") public void removeSessionLocked(@NonNull ComponentName key) { mSessions.remove(key); @@ -171,4 +187,5 @@ final class IntelligencePerUserService Slog.w(TAG, "Error async reporting result to client: " + e); } } + } diff --git a/services/autofill/java/com/android/server/intelligence/RemoteIntelligenceService.java b/services/autofill/java/com/android/server/intelligence/RemoteIntelligenceService.java index ee66b4e741299..9d241fbf820d0 100644 --- a/services/autofill/java/com/android/server/intelligence/RemoteIntelligenceService.java +++ b/services/autofill/java/com/android/server/intelligence/RemoteIntelligenceService.java @@ -27,9 +27,12 @@ import android.service.intelligence.InteractionContext; import android.service.intelligence.InteractionSessionId; import android.text.format.DateUtils; import android.util.Slog; +import android.view.intelligence.ContentCaptureEvent; import com.android.server.AbstractRemoteService; +import java.util.List; + final class RemoteIntelligenceService extends AbstractRemoteService { private static final String TAG = "RemoteIntelligenceService"; @@ -79,44 +82,89 @@ final class RemoteIntelligenceService extends AbstractRemoteService { scheduleRequest(new PendingSessionLifecycleRequest(this, context, sessionId)); } - private static final class PendingSessionLifecycleRequest + /** + * Called by {@link ContentCaptureSession} to send a batch of events to the service. + */ + public void onContentCaptureEventsRequest(@NonNull InteractionSessionId sessionId, + @NonNull List events) { + cancelScheduledUnbind(); + scheduleRequest(new PendingOnContentCaptureEventsRequest(this, sessionId, events)); + } + + + private abstract static class MyPendingRequest extends PendingRequest { + protected final InteractionSessionId mSessionId; - private final InteractionContext mContext; - private final InteractionSessionId mSessionId; - - protected PendingSessionLifecycleRequest(@NonNull RemoteIntelligenceService service, - @Nullable InteractionContext context, @NonNull InteractionSessionId sessionId) { + private MyPendingRequest(@NonNull RemoteIntelligenceService service, + @NonNull InteractionSessionId sessionId) { super(service); - mContext = context; mSessionId = sessionId; } @Override // from PendingRequest - public void run() { + protected final void onTimeout(RemoteIntelligenceService remoteService) { + Slog.w(TAG, "timed out handling " + getClass().getSimpleName() + " for " + + mSessionId); + remoteService.mCallbacks.onFailureOrTimeout(/* timedOut= */ true); + } + + @Override // from PendingRequest + public final void run() { final RemoteIntelligenceService remoteService = getService(); if (remoteService != null) { try { - remoteService.mService.onSessionLifecycle(mContext, mSessionId); + myRun(remoteService); + // We don't expect the service to call us back, so we finish right away. + finish(); } catch (RemoteException e) { - Slog.w(TAG, "exception handling PendingSessionLifecycleRequest for " + Slog.w(TAG, "exception handling " + getClass().getSimpleName() + " for " + mSessionId + ": " + e); - remoteService.mCallbacks - .onSessionLifecycleRequestFailureOrTimeout(/* timedOut= */ false); + remoteService.mCallbacks.onFailureOrTimeout(/* timedOut= */ false); } } } - @Override // from PendingRequest - protected void onTimeout(RemoteIntelligenceService remoteService) { - Slog.w(TAG, "timed out handling PendingSessionLifecycleRequest for " - + mSessionId); - remoteService.mCallbacks - .onSessionLifecycleRequestFailureOrTimeout(/* timedOut= */ true); + protected abstract void myRun(@NonNull RemoteIntelligenceService service) + throws RemoteException; + + } + + private static final class PendingSessionLifecycleRequest extends MyPendingRequest { + + private final InteractionContext mContext; + + protected PendingSessionLifecycleRequest(@NonNull RemoteIntelligenceService service, + @Nullable InteractionContext context, @NonNull InteractionSessionId sessionId) { + super(service, sessionId); + mContext = context; + } + + @Override // from MyPendingRequest + public void myRun(@NonNull RemoteIntelligenceService remoteService) throws RemoteException { + remoteService.mService.onSessionLifecycle(mContext, mSessionId); + } + } + + private static final class PendingOnContentCaptureEventsRequest extends MyPendingRequest { + + private final List mEvents; + + protected PendingOnContentCaptureEventsRequest(@NonNull RemoteIntelligenceService service, + @NonNull InteractionSessionId sessionId, + @NonNull List events) { + super(service, sessionId); + mEvents = events; + } + + @Override // from MyPendingRequest + public void myRun(@NonNull RemoteIntelligenceService remoteService) throws RemoteException { + remoteService.mService.onContentCaptureEvents(mSessionId, mEvents); } } public interface RemoteIntelligenceServiceCallbacks extends VultureCallback { - void onSessionLifecycleRequestFailureOrTimeout(boolean timedOut); + // To keep it simple, we use the same callback for all failures / timeouts. + void onFailureOrTimeout(boolean timedOut); } } diff --git a/services/core/java/com/android/server/AbstractRemoteService.java b/services/core/java/com/android/server/AbstractRemoteService.java index 1d3a34c5e8db1..181d7fde1fb8b 100644 --- a/services/core/java/com/android/server/AbstractRemoteService.java +++ b/services/core/java/com/android/server/AbstractRemoteService.java @@ -366,11 +366,12 @@ public abstract class AbstractRemoteService implements DeathRecipient { mCompleted = true; } - Slog.w(mTag, "timed out"); final S remoteService = mWeakService.get(); if (remoteService != null) { - Slog.w(mTag, " timed out after " + service.getRemoteRequestMillis() + " ms"); + Slog.w(mTag, "timed out after " + service.getRemoteRequestMillis() + " ms"); onTimeout(remoteService); + } else { + Slog.w(mTag, "timed out (no service)"); } }; mServiceHandler.postAtTime(mTimeoutTrigger,