Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b9b1befb authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Trigger Augmented Autofill when the standard service used FillResponse.disableAutofill()"

parents 8c6eee11 adb34f58
Loading
Loading
Loading
Loading
+38 −9
Original line number Diff line number Diff line
@@ -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
@@ -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
     */
@@ -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
     */
@@ -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;

@@ -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 {
        /**
@@ -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;
            }
@@ -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();
@@ -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) {
@@ -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
@@ -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();
@@ -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) {
+25 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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) {
+17 −3
Original line number Diff line number Diff line
@@ -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) {
@@ -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 {
+58 −24
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -222,7 +224,7 @@ final class AutofillManagerServiceImpl
                    session.removeSelfLocked();
                }
            }
            sendStateToClients(false);
            sendStateToClients(/* resetClient= */ false);
        }
        updateRemoteAugmentedAutofillService();
        return enabledChanged;
@@ -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,
@@ -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;
        }
@@ -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.
@@ -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;
@@ -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;
@@ -635,7 +669,7 @@ final class AutofillManagerServiceImpl
            remoteFillServices.valueAt(i).destroy();
        }

        sendStateToClients(true);
        sendStateToClients(/* resetclient=*/ true);
        if (mClients != null) {
            mClients.kill();
            mClients = null;
+43 −15
Original line number Diff line number Diff line
@@ -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 */
@@ -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}.
     */
@@ -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;
@@ -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
@@ -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;
@@ -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)
@@ -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)
@@ -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;
        }

@@ -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");
        }