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

Commit 00b0f1d3 authored by Felipe Leme's avatar Felipe Leme Committed by Android (Google) Code Review
Browse files

Merge "Refactored RemoteFillService logic into a common class."

parents 05083b01 31a1f803
Loading
Loading
Loading
Loading
+44 −365
Original line number Original line Diff line number Diff line
@@ -18,7 +18,6 @@ package com.android.server.autofill;


import static android.service.autofill.FillRequest.INVALID_REQUEST_ID;
import static android.service.autofill.FillRequest.INVALID_REQUEST_ID;


import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import static com.android.server.autofill.Helper.sDebug;
import static com.android.server.autofill.Helper.sDebug;
import static com.android.server.autofill.Helper.sVerbose;
import static com.android.server.autofill.Helper.sVerbose;


@@ -26,17 +25,11 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.ComponentName;
import android.content.Context;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
import android.content.IntentSender;
import android.content.ServiceConnection;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.IBinder;
import android.os.IBinder.DeathRecipient;
import android.os.ICancellationSignal;
import android.os.ICancellationSignal;
import android.os.IInterface;
import android.os.RemoteException;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.service.autofill.AutofillService;
import android.service.autofill.AutofillService;
import android.service.autofill.FillRequest;
import android.service.autofill.FillRequest;
import android.service.autofill.FillResponse;
import android.service.autofill.FillResponse;
@@ -47,59 +40,17 @@ import android.service.autofill.SaveRequest;
import android.text.format.DateUtils;
import android.text.format.DateUtils;
import android.util.Slog;
import android.util.Slog;


import com.android.internal.annotations.GuardedBy;
import com.android.server.AbstractRemoteService;
import com.android.server.FgThread;


import java.io.PrintWriter;
final class RemoteFillService extends AbstractRemoteService {
import java.lang.ref.WeakReference;


/**
 * This class represents a remote fill service. It abstracts away the binding
 * and unbinding from the remote implementation.
 *
 * <p>Clients can call methods of this class without worrying about when and
 * how to bind/unbind/timeout. All state of this class is modified on a handler
 * thread.
 */
final class RemoteFillService implements DeathRecipient {
    private static final String LOG_TAG = "RemoteFillService";
    // How long after the last interaction with the service we would unbind
    private static final long TIMEOUT_IDLE_BIND_MILLIS = 5 * DateUtils.SECOND_IN_MILLIS;
    private static final long TIMEOUT_IDLE_BIND_MILLIS = 5 * DateUtils.SECOND_IN_MILLIS;

    // How long after we make a remote request to a fill service we timeout
    private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 5 * DateUtils.SECOND_IN_MILLIS;
    private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 5 * DateUtils.SECOND_IN_MILLIS;


    private static final int MSG_UNBIND = 3;

    private final Context mContext;

    private final ComponentName mComponentName;

    private final Intent mIntent;

    private final FillServiceCallbacks mCallbacks;
    private final FillServiceCallbacks mCallbacks;

    private final int mUserId;

    private final ServiceConnection mServiceConnection = new RemoteServiceConnection();

    private final Handler mHandler;

    private final boolean mBindInstantServiceAllowed;

    private IAutoFillService mAutoFillService;
    private IAutoFillService mAutoFillService;


    private boolean mBinding;
    public interface FillServiceCallbacks extends VultureCallback {

    private boolean mDestroyed;

    private boolean mServiceDied;

    private boolean mCompleted;

    private PendingRequest mPendingRequest;

    public interface FillServiceCallbacks {
        void onFillRequestSuccess(int requestId, @Nullable FillResponse response,
        void onFillRequestSuccess(int requestId, @Nullable FillResponse response,
                @NonNull String servicePackageName, int requestFlags);
                @NonNull String servicePackageName, int requestFlags);
        void onFillRequestFailure(int requestId, @Nullable CharSequence message);
        void onFillRequestFailure(int requestId, @Nullable CharSequence message);
@@ -109,48 +60,42 @@ final class RemoteFillService implements DeathRecipient {
        // TODO(b/80093094): add timeout here too?
        // TODO(b/80093094): add timeout here too?
        void onSaveRequestFailure(@Nullable CharSequence message,
        void onSaveRequestFailure(@Nullable CharSequence message,
                @NonNull String servicePackageName);
                @NonNull String servicePackageName);
        void onServiceDied(RemoteFillService service);
    }
    }


    public RemoteFillService(Context context, ComponentName componentName,
    RemoteFillService(Context context, ComponentName componentName, int userId,
            int userId, FillServiceCallbacks callbacks, boolean bindInstantServiceAllowed) {
            FillServiceCallbacks callbacks, boolean bindInstantServiceAllowed) {
        mContext = context;
        super(context, AutofillService.SERVICE_INTERFACE, componentName, userId, callbacks,
                bindInstantServiceAllowed, sVerbose);
        mCallbacks = callbacks;
        mCallbacks = callbacks;
        mComponentName = componentName;
        mIntent = new Intent(AutofillService.SERVICE_INTERFACE).setComponent(mComponentName);
        mUserId = userId;
        mHandler = new Handler(FgThread.getHandler().getLooper());
        mBindInstantServiceAllowed = bindInstantServiceAllowed;
    }
    }


    public void destroy() {
    @Override
        mHandler.sendMessage(obtainMessage(RemoteFillService::handleDestroy, this));
    protected void onConnectedStateChanged(boolean state) {
        if (mAutoFillService == null) {
            Slog.w(mTag, "onConnectedStateChanged(): null service");
            return;
        }
        }

        try {
    private void handleDestroy() {
            mAutoFillService.onConnectedStateChanged(state);
        if (checkIfDestroyed()) return;
        } catch (Exception e) {
        if (mPendingRequest != null) {
            Slog.w(mTag, "Exception calling onConnectedStateChanged(): " + e);
            mPendingRequest.cancel();
            mPendingRequest = null;
        }
        }
        ensureUnbound();
        mDestroyed = true;
    }
    }


    @Override
    @Override
    public void binderDied() {
    protected IInterface getServiceInterface(IBinder service) {
        mHandler.sendMessage(obtainMessage(
        mAutoFillService = IAutoFillService.Stub.asInterface(service);
                RemoteFillService::handleBinderDied, this));
        return mAutoFillService;
    }
    }


    private void handleBinderDied() {
    @Override
        if (checkIfDestroyed()) return;
    protected long getTimeoutIdleBindMillis() {
        if (mAutoFillService != null) {
        return TIMEOUT_IDLE_BIND_MILLIS;
            mAutoFillService.asBinder().unlinkToDeath(this, 0);
    }
    }
        mAutoFillService = null;

        mServiceDied = true;
    @Override
        mCallbacks.onServiceDied(this);
    protected long getRemoteRequestMillis() {
        return TIMEOUT_REMOTE_REQUEST_MILLIS;
    }
    }


    /**
    /**
@@ -162,8 +107,9 @@ final class RemoteFillService implements DeathRecipient {
     * @return the id of the canceled request, or {@link FillRequest#INVALID_REQUEST_ID} if no
     * @return the id of the canceled request, or {@link FillRequest#INVALID_REQUEST_ID} if no
     *         {@link PendingFillRequest} was canceled.
     *         {@link PendingFillRequest} was canceled.
     */
     */
    // TODO(b/117779333): move this logic to super class (and make mPendingRequest private)
    public int cancelCurrentRequest() {
    public int cancelCurrentRequest() {
        if (mDestroyed) {
        if (isDestroyed()) {
            return INVALID_REQUEST_ID;
            return INVALID_REQUEST_ID;
        }
        }


@@ -190,118 +136,6 @@ final class RemoteFillService implements DeathRecipient {
        scheduleRequest(new PendingSaveRequest(request, this));
        scheduleRequest(new PendingSaveRequest(request, this));
    }
    }


    private void scheduleRequest(PendingRequest pendingRequest) {
        mHandler.sendMessage(obtainMessage(
                RemoteFillService::handlePendingRequest, this, pendingRequest));
    }

    // Note: we are dumping without a lock held so this is a bit racy but
    // adding a lock to a class that offloads to a handler thread would
    // mean adding a lock adding overhead to normal runtime operation.
    public void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
        String tab = "  ";
        pw.append(prefix).append("service:").println();
        pw.append(prefix).append(tab).append("userId=")
                .append(String.valueOf(mUserId)).println();
        pw.append(prefix).append(tab).append("componentName=")
                .append(mComponentName.flattenToString()).println();
        pw.append(prefix).append(tab).append("destroyed=")
                .append(String.valueOf(mDestroyed)).println();
        pw.append(prefix).append(tab).append("bound=")
                .append(String.valueOf(isBound())).println();
        pw.append(prefix).append(tab).append("hasPendingRequest=")
                .append(String.valueOf(mPendingRequest != null)).println();
        pw.append(prefix).append("mBindInstantServiceAllowed=").println(mBindInstantServiceAllowed);
        pw.println();
    }

    private void cancelScheduledUnbind() {
        mHandler.removeMessages(MSG_UNBIND);
    }

    private void scheduleUnbind() {
        cancelScheduledUnbind();
        mHandler.sendMessageDelayed(
                obtainMessage(RemoteFillService::handleUnbind, this)
                        .setWhat(MSG_UNBIND),
                TIMEOUT_IDLE_BIND_MILLIS);
    }

    private void handleUnbind() {
        if (checkIfDestroyed()) return;
        ensureUnbound();
    }

    private void handlePendingRequest(PendingRequest pendingRequest) {
        if (checkIfDestroyed()) return;
        if (mCompleted) {
            return;
        }
        if (!isBound()) {
            if (mPendingRequest != null) {
                mPendingRequest.cancel();
            }
            mPendingRequest = pendingRequest;
            ensureBound();
        } else {
            if (sVerbose) Slog.v(LOG_TAG, "[user: " + mUserId + "] handlePendingRequest()");
            pendingRequest.run();
            if (pendingRequest.isFinal()) {
                mCompleted = true;
            }
        }
    }

    private boolean isBound() {
        return mAutoFillService != null;
    }

    private void ensureBound() {
        if (isBound() || mBinding) {
            return;
        }
        if (sVerbose) Slog.v(LOG_TAG, "[user: " + mUserId + "] ensureBound()");
        mBinding = true;

        int flags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE;
        if (mBindInstantServiceAllowed) {
            flags |= Context.BIND_ALLOW_INSTANT;
        }

        final boolean willBind = mContext.bindServiceAsUser(mIntent, mServiceConnection, flags,
                new UserHandle(mUserId));

        if (!willBind) {
            Slog.w(LOG_TAG, "[user: " + mUserId + "] could not bind to " + mIntent + " using flags "
                    + flags);
            mBinding = false;

            if (!mServiceDied) {
                handleBinderDied();
            }
        }
    }

    private void ensureUnbound() {
        if (!isBound() && !mBinding) {
            return;
        }
        if (sVerbose) Slog.v(LOG_TAG, "[user: " + mUserId + "] ensureUnbound()");
        mBinding = false;
        if (isBound()) {
            try {
                mAutoFillService.onConnectedStateChanged(false);
            } catch (Exception e) {
                Slog.w(LOG_TAG, "Exception calling onDisconnected(): " + e);
            }
            if (mAutoFillService != null) {
                mAutoFillService.asBinder().unlinkToDeath(this, 0);
                mAutoFillService = null;
            }
        }
        mContext.unbindService(mServiceConnection);
    }

    private void dispatchOnFillRequestSuccess(@NonNull PendingFillRequest pendingRequest,
    private void dispatchOnFillRequestSuccess(@NonNull PendingFillRequest pendingRequest,
            @Nullable FillResponse response, int requestFlags) {
            @Nullable FillResponse response, int requestFlags) {
        mHandler.post(() -> {
        mHandler.post(() -> {
@@ -334,12 +168,12 @@ final class RemoteFillService implements DeathRecipient {
            try {
            try {
                cancellationSignal.cancel();
                cancellationSignal.cancel();
            } catch (RemoteException e) {
            } catch (RemoteException e) {
                Slog.w(LOG_TAG, "Error calling cancellation signal: " + e);
                Slog.w(mTag, "Error calling cancellation signal: " + e);
            }
            }
        });
        });
    }
    }


    private void dispatchOnSaveRequestSuccess(PendingRequest pendingRequest,
    private void dispatchOnSaveRequestSuccess(PendingSaveRequest pendingRequest,
            IntentSender intentSender) {
            IntentSender intentSender) {
        mHandler.post(() -> {
        mHandler.post(() -> {
            if (handleResponseCallbackCommon(pendingRequest)) {
            if (handleResponseCallbackCommon(pendingRequest)) {
@@ -348,7 +182,7 @@ final class RemoteFillService implements DeathRecipient {
        });
        });
    }
    }


    private void dispatchOnSaveRequestFailure(PendingRequest pendingRequest,
    private void dispatchOnSaveRequestFailure(PendingSaveRequest pendingRequest,
            @Nullable CharSequence message) {
            @Nullable CharSequence message) {
        mHandler.post(() -> {
        mHandler.post(() -> {
            if (handleResponseCallbackCommon(pendingRequest)) {
            if (handleResponseCallbackCommon(pendingRequest)) {
@@ -357,162 +191,7 @@ final class RemoteFillService implements DeathRecipient {
        });
        });
    }
    }


    private boolean handleResponseCallbackCommon(PendingRequest pendingRequest) {
    private static final class PendingFillRequest extends PendingRequest<RemoteFillService> {
        if (mDestroyed) {
            return false;
        }
        if (mPendingRequest == pendingRequest) {
            mPendingRequest = null;
        }
        if (mPendingRequest == null) {
            scheduleUnbind();
        }
        return true;
    }

    private class RemoteServiceConnection implements ServiceConnection {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            if (mDestroyed || !mBinding) {
                // This is abnormal. Unbinding the connection has been requested already.
                Slog.wtf(LOG_TAG, "onServiceConnected was dispatched after unbindService.");
                return;
            }
            mBinding = false;
            mAutoFillService = IAutoFillService.Stub.asInterface(service);
            try {
                service.linkToDeath(RemoteFillService.this, 0);
            } catch (RemoteException re) {
                handleBinderDied();
                return;
            }
            try {
                mAutoFillService.onConnectedStateChanged(true);
            } catch (RemoteException e) {
                Slog.w(LOG_TAG, "Exception calling onConnected(): " + e);
            }

            if (mPendingRequest != null) {
                PendingRequest pendingRequest = mPendingRequest;
                mPendingRequest = null;
                handlePendingRequest(pendingRequest);
            }

            mServiceDied = false;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mBinding = true;
            mAutoFillService = null;
        }
    }

    private boolean checkIfDestroyed() {
        if (mDestroyed) {
            if (sVerbose) {
                Slog.v(LOG_TAG, "Not handling operation as service for "
                        + mComponentName + " is already destroyed");
            }
        }
        return mDestroyed;
    }

    private static abstract class PendingRequest implements Runnable {
        protected final Object mLock = new Object();
        private final WeakReference<RemoteFillService> mWeakService;

        private final Runnable mTimeoutTrigger;
        private final Handler mServiceHandler;

        @GuardedBy("mLock")
        private boolean mCancelled;

        @GuardedBy("mLock")
        private boolean mCompleted;

        PendingRequest(RemoteFillService service) {
            mWeakService = new WeakReference<>(service);
            mServiceHandler = service.mHandler;
            mTimeoutTrigger = () -> {
                synchronized (mLock) {
                    if (mCancelled) {
                        return;
                    }
                    mCompleted = true;
                }

                Slog.w(LOG_TAG, getClass().getSimpleName() + " timed out");
                final RemoteFillService remoteService = mWeakService.get();
                if (remoteService != null) {
                    Slog.w(LOG_TAG, getClass().getSimpleName() + " timed out after "
                            + TIMEOUT_REMOTE_REQUEST_MILLIS + " ms");
                    onTimeout(remoteService);
                }
            };
            mServiceHandler.postAtTime(mTimeoutTrigger,
                    SystemClock.uptimeMillis() + TIMEOUT_REMOTE_REQUEST_MILLIS);
        }

        protected RemoteFillService getService() {
            return mWeakService.get();
        }

        /**
         * Sub-classes must call this method when the remote service finishes, i.e., when it
         * called {@code onFill...} or {@code onSave...}.
         *
         * @return {@code false} in the service is already finished, {@code true} otherwise.
         */
        protected final boolean finish() {
            synchronized (mLock) {
                if (mCompleted || mCancelled) {
                    return false;
                }
                mCompleted = true;
            }
            mServiceHandler.removeCallbacks(mTimeoutTrigger);
            return true;
        }

        @GuardedBy("mLock")
        protected boolean isCancelledLocked() {
            return mCancelled;
        }

        /**
         * Cancels the service.
         *
         * @return {@code false} if service is already canceled, {@code true} otherwise.
         */
        boolean cancel() {
            synchronized (mLock) {
                if (mCancelled || mCompleted) {
                    return false;
                }
                mCancelled = true;
            }

            mServiceHandler.removeCallbacks(mTimeoutTrigger);
            return true;
        }

        /**
         * Called by the self-destructure timeout when the AutofilllService didn't reply to the
         * request on time.
         */
        abstract void onTimeout(RemoteFillService remoteService);

        /**
         * @return whether this request leads to a final state where no
         * other requests can be made.
         */
        boolean isFinal() {
            return false;
        }
    }

    private static final class PendingFillRequest extends PendingRequest {
        private final FillRequest mRequest;
        private final FillRequest mRequest;
        private final IFillCallback mCallback;
        private final IFillCallback mCallback;
        private ICancellationSignal mCancellation;
        private ICancellationSignal mCancellation;
@@ -534,7 +213,7 @@ final class RemoteFillService implements DeathRecipient {
                            try {
                            try {
                                cancellation.cancel();
                                cancellation.cancel();
                            } catch (RemoteException e) {
                            } catch (RemoteException e) {
                                Slog.e(LOG_TAG, "Error requesting a cancellation", e);
                                Slog.e(mTag, "Error requesting a cancellation", e);
                            }
                            }
                        }
                        }
                    }
                    }
@@ -565,7 +244,7 @@ final class RemoteFillService implements DeathRecipient {
        }
        }


        @Override
        @Override
        void onTimeout(RemoteFillService remoteService) {
        protected void onTimeout(RemoteFillService remoteService) {
            // NOTE: Must make these 2 calls asynchronously, because the cancellation signal is
            // NOTE: Must make these 2 calls asynchronously, because the cancellation signal is
            // handled by the service, which could block.
            // handled by the service, which could block.
            final ICancellationSignal cancellation;
            final ICancellationSignal cancellation;
@@ -582,17 +261,17 @@ final class RemoteFillService implements DeathRecipient {
        public void run() {
        public void run() {
            synchronized (mLock) {
            synchronized (mLock) {
                if (isCancelledLocked()) {
                if (isCancelledLocked()) {
                    if (sDebug) Slog.d(LOG_TAG, "run() called after canceled: " + mRequest);
                    if (sDebug) Slog.d(mTag, "run() called after canceled: " + mRequest);
                    return;
                    return;
                }
                }
            }
            }
            final RemoteFillService remoteService = getService();
            final RemoteFillService remoteService = getService();
            if (remoteService != null) {
            if (remoteService != null) {
                if (sVerbose) Slog.v(LOG_TAG, "calling onFillRequest() for id=" + mRequest.getId());
                if (sVerbose) Slog.v(mTag, "calling onFillRequest() for id=" + mRequest.getId());
                try {
                try {
                    remoteService.mAutoFillService.onFillRequest(mRequest, mCallback);
                    remoteService.mAutoFillService.onFillRequest(mRequest, mCallback);
                } catch (RemoteException e) {
                } catch (RemoteException e) {
                    Slog.e(LOG_TAG, "Error calling on fill request", e);
                    Slog.e(mTag, "Error calling on fill request", e);


                    remoteService.dispatchOnFillRequestFailure(PendingFillRequest.this, null);
                    remoteService.dispatchOnFillRequestFailure(PendingFillRequest.this, null);
                }
                }
@@ -611,14 +290,14 @@ final class RemoteFillService implements DeathRecipient {
                try {
                try {
                    cancellation.cancel();
                    cancellation.cancel();
                } catch (RemoteException e) {
                } catch (RemoteException e) {
                    Slog.e(LOG_TAG, "Error cancelling a fill request", e);
                    Slog.e(mTag, "Error cancelling a fill request", e);
                }
                }
            }
            }
            return true;
            return true;
        }
        }
    }
    }


    private static final class PendingSaveRequest extends PendingRequest {
    private static final class PendingSaveRequest extends PendingRequest<RemoteFillService> {
        private final SaveRequest mRequest;
        private final SaveRequest mRequest;
        private final ISaveCallback mCallback;
        private final ISaveCallback mCallback;


@@ -653,7 +332,7 @@ final class RemoteFillService implements DeathRecipient {
        }
        }


        @Override
        @Override
        void onTimeout(RemoteFillService remoteService) {
        protected void onTimeout(RemoteFillService remoteService) {
            remoteService.dispatchOnSaveRequestFailure(PendingSaveRequest.this, null);
            remoteService.dispatchOnSaveRequestFailure(PendingSaveRequest.this, null);
        }
        }


@@ -661,11 +340,11 @@ final class RemoteFillService implements DeathRecipient {
        public void run() {
        public void run() {
            final RemoteFillService remoteService = getService();
            final RemoteFillService remoteService = getService();
            if (remoteService != null) {
            if (remoteService != null) {
                if (sVerbose) Slog.v(LOG_TAG, "calling onSaveRequest()");
                if (sVerbose) Slog.v(mTag, "calling onSaveRequest()");
                try {
                try {
                    remoteService.mAutoFillService.onSaveRequest(mRequest, mCallback);
                    remoteService.mAutoFillService.onSaveRequest(mRequest, mCallback);
                } catch (RemoteException e) {
                } catch (RemoteException e) {
                    Slog.e(LOG_TAG, "Error calling on save request", e);
                    Slog.e(mTag, "Error calling on save request", e);


                    remoteService.dispatchOnSaveRequestFailure(PendingSaveRequest.this, null);
                    remoteService.dispatchOnSaveRequestFailure(PendingSaveRequest.this, null);
                }
                }
+3 −2
Original line number Original line Diff line number Diff line
@@ -92,6 +92,7 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.ArrayUtils;
import com.android.server.AbstractRemoteService;
import com.android.server.autofill.ui.AutoFillUI;
import com.android.server.autofill.ui.AutoFillUI;
import com.android.server.autofill.ui.PendingUi;
import com.android.server.autofill.ui.PendingUi;


@@ -901,9 +902,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
                this, authenticationId, intent, fillInIntent));
                this, authenticationId, intent, fillInIntent));
    }
    }


    // FillServiceCallbacks
    // VultureCallback
    @Override
    @Override
    public void onServiceDied(RemoteFillService service) {
    public void onServiceDied(AbstractRemoteService service) {
        Slog.w(TAG, "removing session because service died");
        Slog.w(TAG, "removing session because service died");
        forceRemoveSelfLocked();
        forceRemoveSelfLocked();
    }
    }
+442 −0

File added.

Preview size limit exceeded, changes collapsed.