Loading core/java/android/view/autofill/AutofillManager.java +38 −9 Original line number Diff line number Diff line Loading @@ -228,6 +228,9 @@ public final class AutofillManager { /** @hide */ public static final int FLAG_ADD_CLIENT_ENABLED = 0x1; /** @hide */ public static final int FLAG_ADD_CLIENT_DEBUG = 0x2; /** @hide */ public static final int FLAG_ADD_CLIENT_VERBOSE = 0x4; /** @hide */ public static final int FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY = 0x1; /** @hide */ public static final int DEFAULT_LOGGING_LEVEL = Build.IS_DEBUGGABLE ? AutofillManager.FLAG_ADD_CLIENT_DEBUG Loading Loading @@ -307,8 +310,8 @@ public final class AutofillManager { /** * Same as {@link #STATE_UNKNOWN}, but used on * {@link AutofillManagerClient#setSessionFinished(int)} when the session was finished because * the URL bar changed on client mode * {@link AutofillManagerClient#setSessionFinished(int, List)} when the session was finished * because the URL bar changed on client mode * * @hide */ Loading @@ -316,8 +319,8 @@ public final class AutofillManager { /** * Same as {@link #STATE_UNKNOWN}, but used on * {@link AutofillManagerClient#setSessionFinished(int)} when the session was finished because * the service failed to fullfil a request. * {@link AutofillManagerClient#setSessionFinished(int, List)} when the session was finished * because the service failed to fullfil a request. * * @hide */ Loading Loading @@ -436,7 +439,7 @@ public final class AutofillManager { * There is currently no session running. * {@hide} */ public static final int NO_SESSION = Integer.MIN_VALUE; public static final int NO_SESSION = Integer.MAX_VALUE; private final IAutoFillManager mService; Loading Loading @@ -513,6 +516,10 @@ public final class AutofillManager { @Nullable private final AutofillOptions mOptions; /** When set, session is only used for augmented autofill requests. */ @GuardedBy("mLock") private boolean mForAugmentedAutofillOnly; /** @hide */ public interface AutofillClient { /** Loading Loading @@ -940,9 +947,8 @@ public final class AutofillManager { ensureServiceClientAddedIfNeededLocked(); if (!mEnabled) { if (sVerbose) { Log.v(TAG, "ignoring notifyViewEntered(" + id + "): disabled"); } if (sVerbose) Log.v(TAG, "ignoring notifyViewEntered(" + id + "): disabled"); if (mCallback != null) { callback = mCallback; } Loading Loading @@ -1025,6 +1031,12 @@ public final class AutofillManager { private void notifyViewVisibilityChangedInternal(@NonNull View view, int virtualId, boolean isVisible, boolean virtual) { synchronized (mLock) { if (mForAugmentedAutofillOnly) { if (sVerbose) { Log.v(TAG, "notifyViewVisibilityChanged(): ignoring on augmented only mode"); } return; } if (mEnabled && isActiveLocked()) { final AutofillId id = virtual ? getAutofillId(view, virtualId) : view.getAutofillId(); Loading Loading @@ -1168,6 +1180,10 @@ public final class AutofillManager { AutofillValue value = null; synchronized (mLock) { if (mForAugmentedAutofillOnly) { if (sVerbose) Log.v(TAG, "notifyValueChanged(): ignoring on augmented only mode"); return; } // If the session is gone some fields might still be highlighted, hence we have to // remove the isAutofilled property even if no sessions are active. if (mLastAutofilledData == null) { Loading Loading @@ -1221,6 +1237,10 @@ public final class AutofillManager { return; } synchronized (mLock) { if (mForAugmentedAutofillOnly) { if (sVerbose) Log.v(TAG, "notifyValueChanged(): ignoring on augmented only mode"); return; } if (!mEnabled || !isActiveLocked()) { if (sVerbose) { Log.v(TAG, "notifyValueChanged(" + view.getAutofillId() + ":" + virtualId Loading Loading @@ -1676,14 +1696,20 @@ public final class AutofillManager { if (client == null) return; // NOTE: getClient() already logged it.. final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS); final ComponentName componentName = client.autofillClientGetComponentName(); mService.startSession(client.autofillClientGetActivityToken(), mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(), mCallback != null, flags, client.autofillClientGetComponentName(), mCallback != null, flags, componentName, isCompatibilityModeEnabledLocked(), receiver); mSessionId = receiver.getIntResult(); if (mSessionId != NO_SESSION) { mState = STATE_ACTIVE; } final int extraFlags = receiver.getOptionalExtraIntResult(0); if ((extraFlags & FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY) != 0) { if (sDebug) Log.d(TAG, "startSession(" + componentName + "): for augmented only"); mForAugmentedAutofillOnly = true; } client.autofillClientResetableStateAvailable(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); Loading Loading @@ -2400,6 +2426,9 @@ public final class AutofillManager { pw.print(pfx); pw.print("entered ids for augmented autofill: "); pw.println(mEnteredForAugmentedAutofillIds); } if (mForAugmentedAutofillOnly) { pw.print(pfx); pw.println("For Augmented Autofill Only"); } pw.print(pfx); pw.print("save trigger id: "); pw.println(mSaveTriggerId); pw.print(pfx); pw.print("save on finish(): "); pw.println(mSaveOnFinish); if (mOptions != null) { Loading core/java/com/android/internal/util/SyncResultReceiver.java +25 −0 Original line number Diff line number Diff line Loading @@ -96,6 +96,19 @@ public final class SyncResultReceiver extends IResultReceiver.Stub { return mBundle == null ? null : mBundle.getParcelable(EXTRA); } /** * Gets the optional result from an operation that returns an extra {@code int} (besides the * result code). * * @return value set in the bundle, or {@code defaultValue} when not set. */ public int getOptionalExtraIntResult(int defaultValue) throws TimeoutException { waitResult(); if (mBundle == null || !mBundle.containsKey(EXTRA)) return defaultValue; return mBundle.getInt(EXTRA); } @Override public void send(int resultCode, Bundle resultData) { mResult = resultCode; Loading Loading @@ -136,6 +149,18 @@ public final class SyncResultReceiver extends IResultReceiver.Stub { return bundle; } /** * Creates a bundle for an {@code int} value so it can be retrieved by * {@link #getParcelableResult()} - typically used to return an extra {@code int} (as the 1st * is returned as the result code). */ @NonNull public static Bundle bundleFor(int value) { final Bundle bundle = new Bundle(); bundle.putInt(EXTRA, value); return bundle; } /** @hide */ public static final class TimeoutException extends RemoteException { private TimeoutException(String msg) { Loading services/autofill/java/com/android/server/autofill/AutofillManagerService.java +17 −3 Original line number Diff line number Diff line Loading @@ -683,6 +683,14 @@ public final class AutofillManagerService send(receiver, value ? 1 : 0); } private void send(@NonNull IResultReceiver receiver, int value1, int value2) { try { receiver.send(value1, SyncResultReceiver.bundleFor(value2)); } catch (RemoteException e) { Slog.w(TAG, "Error async reporting result to client: " + e); } } @Nullable @VisibleForTesting static Map<String, String[]> getWhitelistedCompatModePackages(String setting) { Loading Loading @@ -1003,15 +1011,21 @@ public final class AutofillManagerService // TODO(b/113281366): add a callback method on AM to be notified when a task is finished // so we can clean up sessions kept alive final int taskId = mAm.getTaskIdForActivity(activityToken, false); final int sessionId; final long result; synchronized (mLock) { final AutofillManagerServiceImpl service = getServiceForUserLocked(userId); sessionId = service.startSessionLocked(activityToken, taskId, getCallingUid(), result = service.startSessionLocked(activityToken, taskId, getCallingUid(), appCallback, autofillId, bounds, value, hasCallback, componentName, compatMode, mAllowInstantService, flags); } final int sessionId = (int) result; final int resultFlags = (int) (result >> 32); if (resultFlags != 0) { send(receiver, sessionId, resultFlags); } else { send(receiver, sessionId); } } @Override public void getFillEventHistory(@NonNull IResultReceiver receiver) throws RemoteException { Loading services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java +58 −24 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.server.autofill; import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST; import static android.view.autofill.AutofillManager.ACTION_START_SESSION; import static android.view.autofill.AutofillManager.FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY; import static android.view.autofill.AutofillManager.NO_SESSION; import static com.android.server.autofill.Helper.sDebug; Loading Loading @@ -53,6 +54,7 @@ import android.service.autofill.FieldClassification; import android.service.autofill.FieldClassification.Match; import android.service.autofill.FillEventHistory; import android.service.autofill.FillEventHistory.Event; import android.service.autofill.FillRequest; import android.service.autofill.FillResponse; import android.service.autofill.IAutoFillService; import android.service.autofill.UserData; Loading Loading @@ -222,7 +224,7 @@ final class AutofillManagerServiceImpl session.removeSelfLocked(); } } sendStateToClients(false); sendStateToClients(/* resetClient= */ false); } updateRemoteAugmentedAutofillService(); return enabledChanged; Loading Loading @@ -279,8 +281,15 @@ final class AutofillManagerServiceImpl } } /** * Starts a new session. * * @return {@code long} whose right-most 32 bits represent the session id (which is always * non-negative), and the left-most contains extra flags (currently either {@code 0} or * {@link FillRequest#FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY}). */ @GuardedBy("mLock") int startSessionLocked(@NonNull IBinder activityToken, int taskId, int uid, long startSessionLocked(@NonNull IBinder activityToken, int taskId, int uid, @NonNull IBinder appCallbackToken, @NonNull AutofillId autofillId, @NonNull Rect virtualBounds, @Nullable AutofillValue value, boolean hasCallback, @NonNull ComponentName componentName, boolean compatMode, Loading @@ -290,33 +299,48 @@ final class AutofillManagerServiceImpl } final String shortComponentName = componentName.toShortString(); boolean forAugmentedAutofillOnly = false; if (isAutofillDisabledLocked(componentName)) { // Service disabled autofill; that means no session, unless the activity is whitelisted // for augmented autofill if (isWhitelistedForAugmentedAutofillLocked(componentName)) { if (sDebug) { Slog.d(TAG, "startSession(" + shortComponentName + "): ignored because disabled by service"); Slog.d(TAG, "startSession(" + shortComponentName + "): disabled by service but " + "whitelisted for augmented autofill"); } forAugmentedAutofillOnly = true; } else { if (sDebug) { Slog.d(TAG, "startSession(" + shortComponentName + "): ignored because " + "disabled by service and not whitelisted for augmented autofill"); } final IAutoFillManagerClient client = IAutoFillManagerClient.Stub .asInterface(appCallbackToken); try { client.setSessionFinished(AutofillManager.STATE_DISABLED_BY_SERVICE, /* autofillableIds= */ null); } catch (RemoteException e) { Slog.w(TAG, "Could not notify " + shortComponentName + " that it's disabled: " + e); Slog.w(TAG, "Could not notify " + shortComponentName + " that it's disabled: " + e); } return NO_SESSION; } } if (sVerbose) Slog.v(TAG, "startSession(): token=" + activityToken + ", flags=" + flags); if (sVerbose) { Slog.v(TAG, "startSession(): token=" + activityToken + ", flags=" + flags + ", forAugmentedAutofillOnly=" + forAugmentedAutofillOnly); } // Occasionally clean up abandoned sessions pruneAbandonedSessionsLocked(); final Session newSession = createSessionByTokenLocked(activityToken, taskId, uid, appCallbackToken, hasCallback, componentName, compatMode, bindInstantServiceAllowed, flags); bindInstantServiceAllowed, forAugmentedAutofillOnly, flags); if (newSession == null) { return NO_SESSION; } Loading @@ -325,13 +349,21 @@ final class AutofillManagerServiceImpl "id=" + newSession.id + " uid=" + uid + " a=" + shortComponentName + " s=" + mInfo.getServiceInfo().packageName + " u=" + mUserId + " i=" + autofillId + " b=" + virtualBounds + " hc=" + hasCallback + " f=" + flags; + " hc=" + hasCallback + " f=" + flags + " aa=" + forAugmentedAutofillOnly; mMaster.logRequestLocked(historyItem); newSession.updateLocked(autofillId, virtualBounds, value, ACTION_START_SESSION, flags); if (forAugmentedAutofillOnly) { // Must embed the flag in the response, at the high-end side of the long. // (session is always positive, so we don't have to worry about the signal bit) final long extraFlags = ((long) FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY) << 32; final long result = extraFlags | newSession.id; return result; } else { return newSession.id; } } /** * Remove abandoned sessions if needed. Loading Loading @@ -436,7 +468,7 @@ final class AutofillManagerServiceImpl private Session createSessionByTokenLocked(@NonNull IBinder activityToken, int taskId, int uid, @NonNull IBinder appCallbackToken, boolean hasCallback, @NonNull ComponentName componentName, boolean compatMode, boolean bindInstantServiceAllowed, int flags) { boolean bindInstantServiceAllowed, boolean forAugmentedAutofillOnly, int flags) { // use random ids so that one app cannot know that another app creates sessions int sessionId; int tries = 0; Loading @@ -447,15 +479,17 @@ final class AutofillManagerServiceImpl return null; } sessionId = sRandom.nextInt(); } while (sessionId == NO_SESSION || mSessions.indexOfKey(sessionId) >= 0); sessionId = Math.abs(sRandom.nextInt()); } while (sessionId == 0 || sessionId == NO_SESSION || mSessions.indexOfKey(sessionId) >= 0); assertCallerLocked(componentName, compatMode); final Session newSession = new Session(this, mUi, getContext(), mHandler, mUserId, mLock, sessionId, taskId, uid, activityToken, appCallbackToken, hasCallback, mUiLatencyHistory, mWtfHistory, mInfo.getServiceInfo().getComponentName(), componentName, compatMode, bindInstantServiceAllowed, flags); componentName, compatMode, bindInstantServiceAllowed, forAugmentedAutofillOnly, flags); mSessions.put(newSession.id, newSession); return newSession; Loading Loading @@ -635,7 +669,7 @@ final class AutofillManagerServiceImpl remoteFillServices.valueAt(i).destroy(); } sendStateToClients(true); sendStateToClients(/* resetclient=*/ true); if (mClients != null) { mClients.kill(); mClients = null; Loading services/autofill/java/com/android/server/autofill/Session.java +43 −15 Original line number Diff line number Diff line Loading @@ -138,7 +138,11 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState private static AtomicInteger sIdCounter = new AtomicInteger(); /** ID of the session */ /** * ID of the session. * * <p>It's always a positive number, to make it easier to embed it in a long. */ public final int id; /** uid the session is for */ Loading Loading @@ -276,6 +280,13 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState @GuardedBy("mLock") private ArraySet<AutofillId> mAugmentedAutofillableIds; /** * When {@code true}, the session was created only to handle Augmented Autofill requests (i.e., * the session would not have existed otherwsie). */ @GuardedBy("mLock") private boolean mForAugmentedAutofillOnly; /** * Receiver of assist data from the app's {@link Activity}. */ Loading Loading @@ -538,11 +549,12 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState */ @GuardedBy("mLock") private void requestNewFillResponseLocked(int flags) { if ((flags & FLAG_AUGMENTED_AUTOFILL_REQUEST) != 0) { if (mForAugmentedAutofillOnly || (flags & FLAG_AUGMENTED_AUTOFILL_REQUEST) != 0) { // TODO(b/122858578): log metrics if (sVerbose) { Slog.v(TAG, "requestNewFillResponse(): triggering augmented autofill instead"); Slog.v(TAG, "requestNewFillResponse(): triggering augmented autofill instead " + "(mForAugmentedAutofillOnly=" + mForAugmentedAutofillOnly + ", flags=" + flags + ")"); } triggerAugmentedAutofillLocked(); return; Loading @@ -564,8 +576,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState mRequestLogs.put(requestId, log); if (sVerbose) { Slog.v(TAG, "Requesting structure for request #" + ordinal + " ,requestId=" + requestId + ", flags=" + flags); Slog.v(TAG, "Requesting structure for request #" + ordinal + " ,requestId=" + requestId + ", flags=" + flags); } // If the focus changes very quickly before the first request is returned each focus change Loading Loading @@ -598,7 +610,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState @NonNull IBinder client, boolean hasCallback, @NonNull LocalLog uiLatencyHistory, @NonNull LocalLog wtfHistory, @NonNull ComponentName serviceComponentName, @NonNull ComponentName componentName, boolean compatMode, boolean bindInstantServiceAllowed, int flags) { boolean bindInstantServiceAllowed, boolean forAugmentedAutofillOnly, int flags) { if (sessionId < 0) { wtf(null, "Non-positive sessionId: %s", sessionId); } id = sessionId; mFlags = flags; this.taskId = taskId; Loading @@ -616,6 +631,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState mWtfHistory = wtfHistory; mComponentName = componentName; mCompatMode = compatMode; mForAugmentedAutofillOnly = forAugmentedAutofillOnly; setClientLocked(client); mMetricsLogger.write(newLogMaker(MetricsEvent.AUTOFILL_SESSION_STARTED) Loading Loading @@ -727,6 +743,22 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState final long disableDuration = response.getDisableDuration(); if (disableDuration > 0) { final int flags = response.getFlags(); if ((flags & FillResponse.FLAG_DISABLE_ACTIVITY_ONLY) != 0) { mService.disableAutofillForActivity(mComponentName, disableDuration, id, mCompatMode); } else { mService.disableAutofillForApp(mComponentName.getPackageName(), disableDuration, id, mCompatMode); } // Although "standard" autofill is disabled, it might still trigger augmented autofill if (triggerAugmentedAutofillLocked() != null) { mForAugmentedAutofillOnly = true; if (sDebug) { Slog.d(TAG, "Service disabled autofill for " + mComponentName + ", but session is kept for augmented autofill only"); } return; } if (sDebug) { final StringBuilder message = new StringBuilder("Service disabled autofill for ") .append(mComponentName) Loading @@ -735,13 +767,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState TimeUtils.formatDuration(disableDuration, message); Slog.d(TAG, message.toString()); } if ((flags & FillResponse.FLAG_DISABLE_ACTIVITY_ONLY) != 0) { mService.disableAutofillForActivity(mComponentName, disableDuration, id, mCompatMode); } else { mService.disableAutofillForApp(mComponentName.getPackageName(), disableDuration, id, mCompatMode); } sessionFinishedState = AutofillManager.STATE_DISABLED_BY_SERVICE; } Loading Loading @@ -3005,6 +3030,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState pw.print(prefix); pw.print("mSaveOnAllViewsInvisible: "); pw.println( mSaveOnAllViewsInvisible); pw.print(prefix); pw.print("mSelectedDatasetIds: "); pw.println(mSelectedDatasetIds); if (mForAugmentedAutofillOnly) { pw.print(prefix); pw.println("For Augmented Autofill Only"); } if (mAugmentedAutofillDestroyer != null) { pw.print(prefix); pw.println("has mAugmentedAutofillDestroyer"); } Loading Loading
core/java/android/view/autofill/AutofillManager.java +38 −9 Original line number Diff line number Diff line Loading @@ -228,6 +228,9 @@ public final class AutofillManager { /** @hide */ public static final int FLAG_ADD_CLIENT_ENABLED = 0x1; /** @hide */ public static final int FLAG_ADD_CLIENT_DEBUG = 0x2; /** @hide */ public static final int FLAG_ADD_CLIENT_VERBOSE = 0x4; /** @hide */ public static final int FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY = 0x1; /** @hide */ public static final int DEFAULT_LOGGING_LEVEL = Build.IS_DEBUGGABLE ? AutofillManager.FLAG_ADD_CLIENT_DEBUG Loading Loading @@ -307,8 +310,8 @@ public final class AutofillManager { /** * Same as {@link #STATE_UNKNOWN}, but used on * {@link AutofillManagerClient#setSessionFinished(int)} when the session was finished because * the URL bar changed on client mode * {@link AutofillManagerClient#setSessionFinished(int, List)} when the session was finished * because the URL bar changed on client mode * * @hide */ Loading @@ -316,8 +319,8 @@ public final class AutofillManager { /** * Same as {@link #STATE_UNKNOWN}, but used on * {@link AutofillManagerClient#setSessionFinished(int)} when the session was finished because * the service failed to fullfil a request. * {@link AutofillManagerClient#setSessionFinished(int, List)} when the session was finished * because the service failed to fullfil a request. * * @hide */ Loading Loading @@ -436,7 +439,7 @@ public final class AutofillManager { * There is currently no session running. * {@hide} */ public static final int NO_SESSION = Integer.MIN_VALUE; public static final int NO_SESSION = Integer.MAX_VALUE; private final IAutoFillManager mService; Loading Loading @@ -513,6 +516,10 @@ public final class AutofillManager { @Nullable private final AutofillOptions mOptions; /** When set, session is only used for augmented autofill requests. */ @GuardedBy("mLock") private boolean mForAugmentedAutofillOnly; /** @hide */ public interface AutofillClient { /** Loading Loading @@ -940,9 +947,8 @@ public final class AutofillManager { ensureServiceClientAddedIfNeededLocked(); if (!mEnabled) { if (sVerbose) { Log.v(TAG, "ignoring notifyViewEntered(" + id + "): disabled"); } if (sVerbose) Log.v(TAG, "ignoring notifyViewEntered(" + id + "): disabled"); if (mCallback != null) { callback = mCallback; } Loading Loading @@ -1025,6 +1031,12 @@ public final class AutofillManager { private void notifyViewVisibilityChangedInternal(@NonNull View view, int virtualId, boolean isVisible, boolean virtual) { synchronized (mLock) { if (mForAugmentedAutofillOnly) { if (sVerbose) { Log.v(TAG, "notifyViewVisibilityChanged(): ignoring on augmented only mode"); } return; } if (mEnabled && isActiveLocked()) { final AutofillId id = virtual ? getAutofillId(view, virtualId) : view.getAutofillId(); Loading Loading @@ -1168,6 +1180,10 @@ public final class AutofillManager { AutofillValue value = null; synchronized (mLock) { if (mForAugmentedAutofillOnly) { if (sVerbose) Log.v(TAG, "notifyValueChanged(): ignoring on augmented only mode"); return; } // If the session is gone some fields might still be highlighted, hence we have to // remove the isAutofilled property even if no sessions are active. if (mLastAutofilledData == null) { Loading Loading @@ -1221,6 +1237,10 @@ public final class AutofillManager { return; } synchronized (mLock) { if (mForAugmentedAutofillOnly) { if (sVerbose) Log.v(TAG, "notifyValueChanged(): ignoring on augmented only mode"); return; } if (!mEnabled || !isActiveLocked()) { if (sVerbose) { Log.v(TAG, "notifyValueChanged(" + view.getAutofillId() + ":" + virtualId Loading Loading @@ -1676,14 +1696,20 @@ public final class AutofillManager { if (client == null) return; // NOTE: getClient() already logged it.. final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS); final ComponentName componentName = client.autofillClientGetComponentName(); mService.startSession(client.autofillClientGetActivityToken(), mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(), mCallback != null, flags, client.autofillClientGetComponentName(), mCallback != null, flags, componentName, isCompatibilityModeEnabledLocked(), receiver); mSessionId = receiver.getIntResult(); if (mSessionId != NO_SESSION) { mState = STATE_ACTIVE; } final int extraFlags = receiver.getOptionalExtraIntResult(0); if ((extraFlags & FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY) != 0) { if (sDebug) Log.d(TAG, "startSession(" + componentName + "): for augmented only"); mForAugmentedAutofillOnly = true; } client.autofillClientResetableStateAvailable(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); Loading Loading @@ -2400,6 +2426,9 @@ public final class AutofillManager { pw.print(pfx); pw.print("entered ids for augmented autofill: "); pw.println(mEnteredForAugmentedAutofillIds); } if (mForAugmentedAutofillOnly) { pw.print(pfx); pw.println("For Augmented Autofill Only"); } pw.print(pfx); pw.print("save trigger id: "); pw.println(mSaveTriggerId); pw.print(pfx); pw.print("save on finish(): "); pw.println(mSaveOnFinish); if (mOptions != null) { Loading
core/java/com/android/internal/util/SyncResultReceiver.java +25 −0 Original line number Diff line number Diff line Loading @@ -96,6 +96,19 @@ public final class SyncResultReceiver extends IResultReceiver.Stub { return mBundle == null ? null : mBundle.getParcelable(EXTRA); } /** * Gets the optional result from an operation that returns an extra {@code int} (besides the * result code). * * @return value set in the bundle, or {@code defaultValue} when not set. */ public int getOptionalExtraIntResult(int defaultValue) throws TimeoutException { waitResult(); if (mBundle == null || !mBundle.containsKey(EXTRA)) return defaultValue; return mBundle.getInt(EXTRA); } @Override public void send(int resultCode, Bundle resultData) { mResult = resultCode; Loading Loading @@ -136,6 +149,18 @@ public final class SyncResultReceiver extends IResultReceiver.Stub { return bundle; } /** * Creates a bundle for an {@code int} value so it can be retrieved by * {@link #getParcelableResult()} - typically used to return an extra {@code int} (as the 1st * is returned as the result code). */ @NonNull public static Bundle bundleFor(int value) { final Bundle bundle = new Bundle(); bundle.putInt(EXTRA, value); return bundle; } /** @hide */ public static final class TimeoutException extends RemoteException { private TimeoutException(String msg) { Loading
services/autofill/java/com/android/server/autofill/AutofillManagerService.java +17 −3 Original line number Diff line number Diff line Loading @@ -683,6 +683,14 @@ public final class AutofillManagerService send(receiver, value ? 1 : 0); } private void send(@NonNull IResultReceiver receiver, int value1, int value2) { try { receiver.send(value1, SyncResultReceiver.bundleFor(value2)); } catch (RemoteException e) { Slog.w(TAG, "Error async reporting result to client: " + e); } } @Nullable @VisibleForTesting static Map<String, String[]> getWhitelistedCompatModePackages(String setting) { Loading Loading @@ -1003,15 +1011,21 @@ public final class AutofillManagerService // TODO(b/113281366): add a callback method on AM to be notified when a task is finished // so we can clean up sessions kept alive final int taskId = mAm.getTaskIdForActivity(activityToken, false); final int sessionId; final long result; synchronized (mLock) { final AutofillManagerServiceImpl service = getServiceForUserLocked(userId); sessionId = service.startSessionLocked(activityToken, taskId, getCallingUid(), result = service.startSessionLocked(activityToken, taskId, getCallingUid(), appCallback, autofillId, bounds, value, hasCallback, componentName, compatMode, mAllowInstantService, flags); } final int sessionId = (int) result; final int resultFlags = (int) (result >> 32); if (resultFlags != 0) { send(receiver, sessionId, resultFlags); } else { send(receiver, sessionId); } } @Override public void getFillEventHistory(@NonNull IResultReceiver receiver) throws RemoteException { Loading
services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java +58 −24 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.server.autofill; import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST; import static android.view.autofill.AutofillManager.ACTION_START_SESSION; import static android.view.autofill.AutofillManager.FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY; import static android.view.autofill.AutofillManager.NO_SESSION; import static com.android.server.autofill.Helper.sDebug; Loading Loading @@ -53,6 +54,7 @@ import android.service.autofill.FieldClassification; import android.service.autofill.FieldClassification.Match; import android.service.autofill.FillEventHistory; import android.service.autofill.FillEventHistory.Event; import android.service.autofill.FillRequest; import android.service.autofill.FillResponse; import android.service.autofill.IAutoFillService; import android.service.autofill.UserData; Loading Loading @@ -222,7 +224,7 @@ final class AutofillManagerServiceImpl session.removeSelfLocked(); } } sendStateToClients(false); sendStateToClients(/* resetClient= */ false); } updateRemoteAugmentedAutofillService(); return enabledChanged; Loading Loading @@ -279,8 +281,15 @@ final class AutofillManagerServiceImpl } } /** * Starts a new session. * * @return {@code long} whose right-most 32 bits represent the session id (which is always * non-negative), and the left-most contains extra flags (currently either {@code 0} or * {@link FillRequest#FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY}). */ @GuardedBy("mLock") int startSessionLocked(@NonNull IBinder activityToken, int taskId, int uid, long startSessionLocked(@NonNull IBinder activityToken, int taskId, int uid, @NonNull IBinder appCallbackToken, @NonNull AutofillId autofillId, @NonNull Rect virtualBounds, @Nullable AutofillValue value, boolean hasCallback, @NonNull ComponentName componentName, boolean compatMode, Loading @@ -290,33 +299,48 @@ final class AutofillManagerServiceImpl } final String shortComponentName = componentName.toShortString(); boolean forAugmentedAutofillOnly = false; if (isAutofillDisabledLocked(componentName)) { // Service disabled autofill; that means no session, unless the activity is whitelisted // for augmented autofill if (isWhitelistedForAugmentedAutofillLocked(componentName)) { if (sDebug) { Slog.d(TAG, "startSession(" + shortComponentName + "): ignored because disabled by service"); Slog.d(TAG, "startSession(" + shortComponentName + "): disabled by service but " + "whitelisted for augmented autofill"); } forAugmentedAutofillOnly = true; } else { if (sDebug) { Slog.d(TAG, "startSession(" + shortComponentName + "): ignored because " + "disabled by service and not whitelisted for augmented autofill"); } final IAutoFillManagerClient client = IAutoFillManagerClient.Stub .asInterface(appCallbackToken); try { client.setSessionFinished(AutofillManager.STATE_DISABLED_BY_SERVICE, /* autofillableIds= */ null); } catch (RemoteException e) { Slog.w(TAG, "Could not notify " + shortComponentName + " that it's disabled: " + e); Slog.w(TAG, "Could not notify " + shortComponentName + " that it's disabled: " + e); } return NO_SESSION; } } if (sVerbose) Slog.v(TAG, "startSession(): token=" + activityToken + ", flags=" + flags); if (sVerbose) { Slog.v(TAG, "startSession(): token=" + activityToken + ", flags=" + flags + ", forAugmentedAutofillOnly=" + forAugmentedAutofillOnly); } // Occasionally clean up abandoned sessions pruneAbandonedSessionsLocked(); final Session newSession = createSessionByTokenLocked(activityToken, taskId, uid, appCallbackToken, hasCallback, componentName, compatMode, bindInstantServiceAllowed, flags); bindInstantServiceAllowed, forAugmentedAutofillOnly, flags); if (newSession == null) { return NO_SESSION; } Loading @@ -325,13 +349,21 @@ final class AutofillManagerServiceImpl "id=" + newSession.id + " uid=" + uid + " a=" + shortComponentName + " s=" + mInfo.getServiceInfo().packageName + " u=" + mUserId + " i=" + autofillId + " b=" + virtualBounds + " hc=" + hasCallback + " f=" + flags; + " hc=" + hasCallback + " f=" + flags + " aa=" + forAugmentedAutofillOnly; mMaster.logRequestLocked(historyItem); newSession.updateLocked(autofillId, virtualBounds, value, ACTION_START_SESSION, flags); if (forAugmentedAutofillOnly) { // Must embed the flag in the response, at the high-end side of the long. // (session is always positive, so we don't have to worry about the signal bit) final long extraFlags = ((long) FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY) << 32; final long result = extraFlags | newSession.id; return result; } else { return newSession.id; } } /** * Remove abandoned sessions if needed. Loading Loading @@ -436,7 +468,7 @@ final class AutofillManagerServiceImpl private Session createSessionByTokenLocked(@NonNull IBinder activityToken, int taskId, int uid, @NonNull IBinder appCallbackToken, boolean hasCallback, @NonNull ComponentName componentName, boolean compatMode, boolean bindInstantServiceAllowed, int flags) { boolean bindInstantServiceAllowed, boolean forAugmentedAutofillOnly, int flags) { // use random ids so that one app cannot know that another app creates sessions int sessionId; int tries = 0; Loading @@ -447,15 +479,17 @@ final class AutofillManagerServiceImpl return null; } sessionId = sRandom.nextInt(); } while (sessionId == NO_SESSION || mSessions.indexOfKey(sessionId) >= 0); sessionId = Math.abs(sRandom.nextInt()); } while (sessionId == 0 || sessionId == NO_SESSION || mSessions.indexOfKey(sessionId) >= 0); assertCallerLocked(componentName, compatMode); final Session newSession = new Session(this, mUi, getContext(), mHandler, mUserId, mLock, sessionId, taskId, uid, activityToken, appCallbackToken, hasCallback, mUiLatencyHistory, mWtfHistory, mInfo.getServiceInfo().getComponentName(), componentName, compatMode, bindInstantServiceAllowed, flags); componentName, compatMode, bindInstantServiceAllowed, forAugmentedAutofillOnly, flags); mSessions.put(newSession.id, newSession); return newSession; Loading Loading @@ -635,7 +669,7 @@ final class AutofillManagerServiceImpl remoteFillServices.valueAt(i).destroy(); } sendStateToClients(true); sendStateToClients(/* resetclient=*/ true); if (mClients != null) { mClients.kill(); mClients = null; Loading
services/autofill/java/com/android/server/autofill/Session.java +43 −15 Original line number Diff line number Diff line Loading @@ -138,7 +138,11 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState private static AtomicInteger sIdCounter = new AtomicInteger(); /** ID of the session */ /** * ID of the session. * * <p>It's always a positive number, to make it easier to embed it in a long. */ public final int id; /** uid the session is for */ Loading Loading @@ -276,6 +280,13 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState @GuardedBy("mLock") private ArraySet<AutofillId> mAugmentedAutofillableIds; /** * When {@code true}, the session was created only to handle Augmented Autofill requests (i.e., * the session would not have existed otherwsie). */ @GuardedBy("mLock") private boolean mForAugmentedAutofillOnly; /** * Receiver of assist data from the app's {@link Activity}. */ Loading Loading @@ -538,11 +549,12 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState */ @GuardedBy("mLock") private void requestNewFillResponseLocked(int flags) { if ((flags & FLAG_AUGMENTED_AUTOFILL_REQUEST) != 0) { if (mForAugmentedAutofillOnly || (flags & FLAG_AUGMENTED_AUTOFILL_REQUEST) != 0) { // TODO(b/122858578): log metrics if (sVerbose) { Slog.v(TAG, "requestNewFillResponse(): triggering augmented autofill instead"); Slog.v(TAG, "requestNewFillResponse(): triggering augmented autofill instead " + "(mForAugmentedAutofillOnly=" + mForAugmentedAutofillOnly + ", flags=" + flags + ")"); } triggerAugmentedAutofillLocked(); return; Loading @@ -564,8 +576,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState mRequestLogs.put(requestId, log); if (sVerbose) { Slog.v(TAG, "Requesting structure for request #" + ordinal + " ,requestId=" + requestId + ", flags=" + flags); Slog.v(TAG, "Requesting structure for request #" + ordinal + " ,requestId=" + requestId + ", flags=" + flags); } // If the focus changes very quickly before the first request is returned each focus change Loading Loading @@ -598,7 +610,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState @NonNull IBinder client, boolean hasCallback, @NonNull LocalLog uiLatencyHistory, @NonNull LocalLog wtfHistory, @NonNull ComponentName serviceComponentName, @NonNull ComponentName componentName, boolean compatMode, boolean bindInstantServiceAllowed, int flags) { boolean bindInstantServiceAllowed, boolean forAugmentedAutofillOnly, int flags) { if (sessionId < 0) { wtf(null, "Non-positive sessionId: %s", sessionId); } id = sessionId; mFlags = flags; this.taskId = taskId; Loading @@ -616,6 +631,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState mWtfHistory = wtfHistory; mComponentName = componentName; mCompatMode = compatMode; mForAugmentedAutofillOnly = forAugmentedAutofillOnly; setClientLocked(client); mMetricsLogger.write(newLogMaker(MetricsEvent.AUTOFILL_SESSION_STARTED) Loading Loading @@ -727,6 +743,22 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState final long disableDuration = response.getDisableDuration(); if (disableDuration > 0) { final int flags = response.getFlags(); if ((flags & FillResponse.FLAG_DISABLE_ACTIVITY_ONLY) != 0) { mService.disableAutofillForActivity(mComponentName, disableDuration, id, mCompatMode); } else { mService.disableAutofillForApp(mComponentName.getPackageName(), disableDuration, id, mCompatMode); } // Although "standard" autofill is disabled, it might still trigger augmented autofill if (triggerAugmentedAutofillLocked() != null) { mForAugmentedAutofillOnly = true; if (sDebug) { Slog.d(TAG, "Service disabled autofill for " + mComponentName + ", but session is kept for augmented autofill only"); } return; } if (sDebug) { final StringBuilder message = new StringBuilder("Service disabled autofill for ") .append(mComponentName) Loading @@ -735,13 +767,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState TimeUtils.formatDuration(disableDuration, message); Slog.d(TAG, message.toString()); } if ((flags & FillResponse.FLAG_DISABLE_ACTIVITY_ONLY) != 0) { mService.disableAutofillForActivity(mComponentName, disableDuration, id, mCompatMode); } else { mService.disableAutofillForApp(mComponentName.getPackageName(), disableDuration, id, mCompatMode); } sessionFinishedState = AutofillManager.STATE_DISABLED_BY_SERVICE; } Loading Loading @@ -3005,6 +3030,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState pw.print(prefix); pw.print("mSaveOnAllViewsInvisible: "); pw.println( mSaveOnAllViewsInvisible); pw.print(prefix); pw.print("mSelectedDatasetIds: "); pw.println(mSelectedDatasetIds); if (mForAugmentedAutofillOnly) { pw.print(prefix); pw.println("For Augmented Autofill Only"); } if (mAugmentedAutofillDestroyer != null) { pw.print(prefix); pw.println("has mAugmentedAutofillDestroyer"); } Loading