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

Commit df30f270 authored by Felipe Leme's avatar Felipe Leme
Browse files

Trigger Augmented Autofill when the standard service is not set.

Test: atest AugmentedLoginActivityTest#testAugmentedAutoFill_mainServiceDisabled
Test: atest CtsAutoFillServiceTestCases # sanity check

Fixes: 123100813

Change-Id: I16bf7f583a4be13584f1fa20c76c2b1c32cf4409
parent 8a5b8f7c
Loading
Loading
Loading
Loading
+28 −9
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package android.view.autofill;

import static android.service.autofill.FillRequest.FLAG_AUGMENTED_AUTOFILL_REQUEST;
import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
import static android.view.autofill.Helper.sDebug;
import static android.view.autofill.Helper.sVerbose;
@@ -228,6 +227,7 @@ 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_ADD_CLIENT_ENABLED_FOR_AUGMENTED_AUTOFILL_ONLY = 0x8;

    /** @hide */ public static final int FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY = 0x1;

@@ -520,6 +520,13 @@ public final class AutofillManager {
    @GuardedBy("mLock")
    private boolean mForAugmentedAutofillOnly;

    /**
     * When set, standard autofill is enabled, but sessions can still be created for augmented
     * autofill only.
     */
    @GuardedBy("mLock")
    private boolean mEnabledForAugmentedAutofillOnly;

    /** @hide */
    public interface AutofillClient {
        /**
@@ -946,7 +953,7 @@ public final class AutofillManager {

        ensureServiceClientAddedIfNeededLocked();

        if (!mEnabled) {
        if (!mEnabled && !mEnabledForAugmentedAutofillOnly) {
            if (sVerbose) Log.v(TAG, "ignoring notifyViewEntered(" + id + "): disabled");

            if (mCallback != null) {
@@ -988,7 +995,7 @@ public final class AutofillManager {
    void notifyViewExitedLocked(@NonNull View view) {
        ensureServiceClientAddedIfNeededLocked();

        if (mEnabled && isActiveLocked()) {
        if ((mEnabled || mEnabledForAugmentedAutofillOnly) && isActiveLocked()) {
            // dont notify exited when Activity is already in background
            if (!isClientDisablingEnterExitEvent()) {
                final AutofillId id = view.getAutofillId();
@@ -1104,7 +1111,7 @@ public final class AutofillManager {

        ensureServiceClientAddedIfNeededLocked();

        if (!mEnabled) {
        if (!mEnabled && !mEnabledForAugmentedAutofillOnly) {
            if (sVerbose) {
                Log.v(TAG, "ignoring notifyViewEntered(" + id + "): disabled");
            }
@@ -1155,7 +1162,7 @@ public final class AutofillManager {
    private void notifyViewExitedLocked(@NonNull View view, int virtualId) {
        ensureServiceClientAddedIfNeededLocked();

        if (mEnabled && isActiveLocked()) {
        if ((mEnabled || mEnabledForAugmentedAutofillOnly) && isActiveLocked()) {
            // don't notify exited when Activity is already in background
            if (!isClientDisablingEnterExitEvent()) {
                final AutofillId id = getAutofillId(view, virtualId);
@@ -1674,14 +1681,17 @@ public final class AutofillManager {
    private void startSessionLocked(@NonNull AutofillId id, @NonNull Rect bounds,
            @NonNull AutofillValue value, int flags) {
        if (mEnteredForAugmentedAutofillIds != null
                && mEnteredForAugmentedAutofillIds.contains(id)) {
                && mEnteredForAugmentedAutofillIds.contains(id)
                || mEnabledForAugmentedAutofillOnly) {
            if (sVerbose) Log.v(TAG, "Starting session for augmented autofill on " + id);
            flags |= FLAG_AUGMENTED_AUTOFILL_REQUEST;
            flags |= FLAG_ADD_CLIENT_ENABLED_FOR_AUGMENTED_AUTOFILL_ONLY;
        }
        if (sVerbose) {
            Log.v(TAG, "startSessionLocked(): id=" + id + ", bounds=" + bounds + ", value=" + value
                    + ", flags=" + flags + ", state=" + getStateAsStringLocked()
                    + ", compatMode=" + isCompatibilityModeEnabledLocked()
                    + ", augmentedOnly=" + mForAugmentedAutofillOnly
                    + ", enabledAugmentedOnly=" + mEnabledForAugmentedAutofillOnly
                    + ", enteredIds=" + mEnteredIds);
        }
        if (mState != STATE_UNKNOWN && !isFinishedLocked() && (flags & FLAG_MANUAL_REQUEST) == 0) {
@@ -1776,7 +1786,8 @@ public final class AutofillManager {

    @GuardedBy("mLock")
    private void ensureServiceClientAddedIfNeededLocked() {
        if (getClient() == null) {
        final AutofillClient client = getClient();
        if (client == null) {
            return;
        }

@@ -1785,11 +1796,18 @@ public final class AutofillManager {
            try {
                final int userId = mContext.getUserId();
                final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
                mService.addClient(mServiceClient, userId, receiver);
                mService.addClient(mServiceClient, client.autofillClientGetComponentName(),
                        userId, receiver);
                final int flags = receiver.getIntResult();
                mEnabled = (flags & FLAG_ADD_CLIENT_ENABLED) != 0;
                sDebug = (flags & FLAG_ADD_CLIENT_DEBUG) != 0;
                sVerbose = (flags & FLAG_ADD_CLIENT_VERBOSE) != 0;
                mEnabledForAugmentedAutofillOnly = (flags
                        & FLAG_ADD_CLIENT_ENABLED_FOR_AUGMENTED_AUTOFILL_ONLY) != 0;
                if (sVerbose) {
                    Log.v(TAG, "receiver results: flags=" + flags + " enabled=" + mEnabled
                            + ", enabledForAugmentedOnly: " + mEnabledForAugmentedAutofillOnly);
                }
                final IAutoFillManager service = mService;
                final IAutoFillManagerClient serviceClient = mServiceClient;
                mServiceClientCleaner = Cleaner.create(this, () -> {
@@ -2406,6 +2424,7 @@ public final class AutofillManager {
            pw.print(" ("); pw.print(client.autofillClientGetActivityToken()); pw.println(')');
        }
        pw.print(pfx); pw.print("enabled: "); pw.println(mEnabled);
        pw.print(pfx); pw.print("enabledAugmentedOnly: "); pw.println(mForAugmentedAutofillOnly);
        pw.print(pfx); pw.print("hasService: "); pw.println(mService != null);
        pw.print(pfx); pw.print("hasCallback: "); pw.println(mCallback != null);
        pw.print(pfx); pw.print("onInvisibleCalled "); pw.println(mOnInvisibleCalled);
+2 −1
Original line number Diff line number Diff line
@@ -37,7 +37,8 @@ import com.android.internal.os.IResultReceiver;
 */
oneway interface IAutoFillManager {
    // Returns flags: FLAG_ADD_CLIENT_ENABLED | FLAG_ADD_CLIENT_DEBUG | FLAG_ADD_CLIENT_VERBOSE
    void addClient(in IAutoFillManagerClient client, int userId, in IResultReceiver result);
    void addClient(in IAutoFillManagerClient client, in ComponentName componentName, int userId,
        in IResultReceiver result);
    void removeClient(in IAutoFillManagerClient client, int userId);
    void startSession(IBinder activityToken, in IBinder appCallback, in AutofillId autoFillId,
        in Rect bounds, in AutofillValue value, int userId, boolean hasCallback, int flags,
+6 −4
Original line number Diff line number Diff line
@@ -942,12 +942,14 @@ public final class AutofillManagerService

    final class AutoFillManagerServiceStub extends IAutoFillManager.Stub {
        @Override
        public void addClient(IAutoFillManagerClient client, int userId,
                @NonNull IResultReceiver receiver) {
        public void addClient(IAutoFillManagerClient client, ComponentName componentName,
                int userId, IResultReceiver receiver) {
            int flags = 0;
            synchronized (mLock) {
                if (getServiceForUserLocked(userId).addClientLocked(client)) {
                    flags |= AutofillManager.FLAG_ADD_CLIENT_ENABLED;
                final int enabledFlags = getServiceForUserLocked(userId).addClientLocked(client,
                        componentName);
                if (enabledFlags != 0) {
                    flags |= enabledFlags;
                }
                if (sDebug) {
                    flags |= AutofillManager.FLAG_ADD_CLIENT_DEBUG;
+39 −17
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@ 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_ADD_CLIENT_ENABLED;
import static android.view.autofill.AutofillManager.FLAG_ADD_CLIENT_ENABLED_FOR_AUGMENTED_AUTOFILL_ONLY;
import static android.view.autofill.AutofillManager.FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY;
import static android.view.autofill.AutofillManager.NO_SESSION;

@@ -54,7 +56,6 @@ 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;
@@ -242,13 +243,28 @@ final class AutofillManagerServiceImpl
        return mAutofillCompatState.getUrlBarResourceIds(packageName, mUserId);
    }

    /**
     * Adds the client and return the proper flags
     *
     * @return {@code 0} if disabled, {@code FLAG_ADD_CLIENT_ENABLED} if enabled (it might be
     * OR'ed with {@code FLAG_AUGMENTED_AUTOFILL_REQUEST}).
     */
    @GuardedBy("mLock")
    boolean addClientLocked(IAutoFillManagerClient client) {
    int addClientLocked(IAutoFillManagerClient client, ComponentName componentName) {
        if (mClients == null) {
            mClients = new RemoteCallbackList<>();
        }
        mClients.register(client);
        return isEnabledLocked();

        if (isEnabledLocked()) return FLAG_ADD_CLIENT_ENABLED;

        // Check if it's enabled for augmented autofill
        if (isSetupCompletedLocked() && isWhitelistedForAugmentedAutofillLocked(componentName)) {
            return FLAG_ADD_CLIENT_ENABLED_FOR_AUGMENTED_AUTOFILL_ONLY;
        }

        // No flags / disabled
        return 0;
    }

    @GuardedBy("mLock")
@@ -286,7 +302,7 @@ final class AutofillManagerServiceImpl
     *
     * @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}).
     * {@link AutofillManager#FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY}).
     */
    @GuardedBy("mLock")
    long startSessionLocked(@NonNull IBinder activityToken, int taskId, int uid,
@@ -294,26 +310,27 @@ final class AutofillManagerServiceImpl
            @NonNull Rect virtualBounds, @Nullable AutofillValue value, boolean hasCallback,
            @NonNull ComponentName componentName, boolean compatMode,
            boolean bindInstantServiceAllowed, int flags) {
        if (!isEnabledLocked()) {
        // FLAG_AUGMENTED_AUTOFILL_REQUEST is set in the flags when standard autofill is disabled
        // but the package is whitelisted for augmented autofill
        boolean forAugmentedAutofillOnly = (flags
                & FLAG_ADD_CLIENT_ENABLED_FOR_AUGMENTED_AUTOFILL_ONLY) != 0;
        if (!isEnabledLocked() && !forAugmentedAutofillOnly) {
            return 0;
        }

        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 (!forAugmentedAutofillOnly && isAutofillDisabledLocked(componentName)) {
            // Standard autofill is enabled, but service disabled autofill for this activity; that
            // means no session, unless the activity is whitelisted for augmented autofill
            if (isWhitelistedForAugmentedAutofillLocked(componentName)) {
                if (sDebug) {
                    Slog.d(TAG, "startSession(" + shortComponentName + "): disabled by service but "
                    Slog.d(TAG, "startSession(" + componentName + "): disabled by service but "
                            + "whitelisted for augmented autofill");
                }
                forAugmentedAutofillOnly = true;

            } else {
                if (sDebug) {
                    Slog.d(TAG, "startSession(" + shortComponentName + "): ignored because "
                    Slog.d(TAG, "startSession(" + componentName + "): ignored because "
                            + "disabled by service and not whitelisted for augmented autofill");
                }
                final IAutoFillManagerClient client = IAutoFillManagerClient.Stub
@@ -323,7 +340,7 @@ final class AutofillManagerServiceImpl
                            /* autofillableIds= */ null);
                } catch (RemoteException e) {
                    Slog.w(TAG,
                            "Could not notify " + shortComponentName + " that it's disabled: " + e);
                            "Could not notify " + componentName + " that it's disabled: " + e);
                }

                return NO_SESSION;
@@ -345,9 +362,11 @@ final class AutofillManagerServiceImpl
            return NO_SESSION;
        }

        // Service can be null when it's only for augmented autofill
        String servicePackageName = mInfo == null ? null : mInfo.getServiceInfo().packageName;
        final String historyItem =
                "id=" + newSession.id + " uid=" + uid + " a=" + shortComponentName
                + " s=" + mInfo.getServiceInfo().packageName
                "id=" + newSession.id + " uid=" + uid + " a=" + componentName.toShortString()
                + " s=" + servicePackageName
                + " u=" + mUserId + " i=" + autofillId + " b=" + virtualBounds
                + " hc=" + hasCallback + " f=" + flags + " aa=" + forAugmentedAutofillOnly;
        mMaster.logRequestLocked(historyItem);
@@ -485,9 +504,12 @@ final class AutofillManagerServiceImpl

        assertCallerLocked(componentName, compatMode);

        // It's null when the session is just for augmented autofill
        final ComponentName serviceComponentName = mInfo == null ? null
                : mInfo.getServiceInfo().getComponentName();
        final Session newSession = new Session(this, mUi, getContext(), mHandler, mUserId, mLock,
                sessionId, taskId, uid, activityToken, appCallbackToken, hasCallback,
                mUiLatencyHistory, mWtfHistory, mInfo.getServiceInfo().getComponentName(),
                mUiLatencyHistory, mWtfHistory, serviceComponentName,
                componentName, compatMode, bindInstantServiceAllowed, forAugmentedAutofillOnly,
                flags);
        mSessions.put(newSession.id, newSession);
+28 −4
Original line number Diff line number Diff line
@@ -185,6 +185,12 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
    @GuardedBy("mLock")
    private DeathRecipient mClientVulture;

    /**
     * Reference to the remote service.
     *
     * <p>Only {@code null} when the session is for augmented autofill only.
     */
    @Nullable
    private final RemoteFillService mRemoteFillService;

    @GuardedBy("mLock")
@@ -293,6 +299,11 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
    private final IAssistDataReceiver mAssistReceiver = new IAssistDataReceiver.Stub() {
        @Override
        public void onHandleAssistData(Bundle resultData) throws RemoteException {
            if (mRemoteFillService == null) {
                wtf(null, "onHandleAssistData() called without a remote service. "
                        + "mForAugmentedAutofillOnly: %s", mForAugmentedAutofillOnly);
                return;
            }
            final AssistStructure structure = resultData.getParcelable(ASSIST_KEY_STRUCTURE);
            if (structure == null) {
                Slog.e(TAG, "No assist structure - app might have crashed providing it");
@@ -527,6 +538,11 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
     */
    @GuardedBy("mLock")
    private void cancelCurrentRequestLocked() {
        if (mRemoteFillService == null) {
            wtf(null, "cancelCurrentRequestLocked() called without a remote service. "
                    + "mForAugmentedAutofillOnly: %s", mForAugmentedAutofillOnly);
            return;
        }
        final int canceledRequest = mRemoteFillService.cancelCurrentRequest();

        // Remove the FillContext as there will never be a response for the service
@@ -608,7 +624,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
            @NonNull Context context, @NonNull Handler handler, int userId, @NonNull Object lock,
            int sessionId, int taskId, int uid, @NonNull IBinder activityToken,
            @NonNull IBinder client, boolean hasCallback, @NonNull LocalLog uiLatencyHistory,
            @NonNull LocalLog wtfHistory, @NonNull ComponentName serviceComponentName,
            @NonNull LocalLog wtfHistory, @Nullable ComponentName serviceComponentName,
            @NonNull ComponentName componentName, boolean compatMode,
            boolean bindInstantServiceAllowed, boolean forAugmentedAutofillOnly, int flags) {
        if (sessionId < 0) {
@@ -623,7 +639,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
        mLock = lock;
        mUi = ui;
        mHandler = handler;
        mRemoteFillService = new RemoteFillService(context, serviceComponentName, userId, this,
        mRemoteFillService = serviceComponentName == null ? null
                : new RemoteFillService(context, serviceComponentName, userId, this,
                        bindInstantServiceAllowed);
        mActivityToken = activityToken;
        mHasCallback = hasCallback;
@@ -2035,6 +2052,11 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
                    + id + " destroyed");
            return;
        }
        if (mRemoteFillService == null) {
            wtf(null, "callSaveLocked() called without a remote service. "
                    + "mForAugmentedAutofillOnly: %s", mForAugmentedAutofillOnly);
            return;
        }

        if (sVerbose) Slog.v(TAG, "callSaveLocked(): mViewStates=" + mViewStates);

@@ -3045,8 +3067,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
            pw.print(prefix); pw.print("mAugmentedAutofillableIds: ");
            pw.println(mAugmentedAutofillableIds);
        }
        if (mRemoteFillService != null) {
            mRemoteFillService.dump(prefix, pw);
        }
    }

    private static void dumpRequestLog(@NonNull PrintWriter pw, @NonNull LogMaker log) {
        pw.print("CAT="); pw.print(log.getCategory());