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

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

Merge "Prune abandoned autofill sessions" into oc-dev

parents 2a86bad9 f539389e
Loading
Loading
Loading
Loading
+89 −2
Original line number Diff line number Diff line
@@ -19,17 +19,21 @@ package com.android.server.autofill;
import static android.view.autofill.AutofillManager.ACTION_START_SESSION;
import static android.view.autofill.AutofillManager.NO_SESSION;

import static com.android.server.autofill.Helper.sDebug;
import static com.android.server.autofill.Helper.sVerbose;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.AppGlobals;
import android.app.IActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.graphics.Rect;
import android.os.AsyncTask;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
@@ -46,6 +50,7 @@ import android.service.autofill.FillEventHistory.Event;
import android.service.autofill.FillResponse;
import android.service.autofill.IAutoFillService;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.LocalLog;
import android.util.Slog;
import android.util.SparseArray;
@@ -72,6 +77,9 @@ final class AutofillManagerServiceImpl {
    private static final String TAG = "AutofillManagerServiceImpl";
    private static final int MAX_SESSION_ID_CREATE_TRIES = 2048;

    /** Minimum interval to prune abandoned sessions */
    private static final int MAX_ABANDONED_SESSION_MILLIS = 30000;

    static final int MSG_SERVICE_SAVE = 1;

    private final int mUserId;
@@ -104,10 +112,10 @@ final class AutofillManagerServiceImpl {
            mHandlerCallback, true);

    /**
     * Cache of pending {@link Session}s, keyed by {@code activityToken}.
     * Cache of pending {@link Session}s, keyed by sessionId.
     *
     * <p>They're kept until the {@link AutofillService} finished handling a request, an error
     * occurs, or the session times out.
     * occurs, or the session is abandoned.
     */
    @GuardedBy("mLock")
    private final SparseArray<Session> mSessions = new SparseArray<>();
@@ -116,6 +124,9 @@ final class AutofillManagerServiceImpl {
    @GuardedBy("mLock")
    private FillEventHistory mEventHistory;

    /** When was {@link PruneTask} last executed? */
    private long mLastPrune = 0;

    AutofillManagerServiceImpl(Context context, Object lock, LocalLog requestsHistory,
            int userId, AutoFillUI ui, boolean disabled) {
        mContext = context;
@@ -260,6 +271,9 @@ final class AutofillManagerServiceImpl {
            return 0;
        }

        // Occasionally clean up abandoned sessions
        pruneAbandonedSessionsLocked();

        final Session newSession = createSessionByTokenLocked(activityToken, uid, windowToken,
                appCallbackToken, hasCallback, flags, packageName);
        if (newSession == null) {
@@ -277,6 +291,20 @@ final class AutofillManagerServiceImpl {
        return newSession.id;
    }

    /**
     * Remove abandoned sessions if needed.
     */
    private void pruneAbandonedSessionsLocked() {
        long now = System.currentTimeMillis();
        if (mLastPrune < now - MAX_ABANDONED_SESSION_MILLIS) {
            mLastPrune = now;

            if (mSessions.size() > 0) {
                (new PruneTask()).execute();
            }
        }
    }

    void finishSessionLocked(int sessionId, int uid) {
        if (!isEnabled()) {
            return;
@@ -513,6 +541,7 @@ final class AutofillManagerServiceImpl {
        pw.print(prefix); pw.print("Default component: ");
            pw.println(mContext.getString(R.string.config_defaultAutofillService));
        pw.print(prefix); pw.print("Disabled: "); pw.println(mDisabled);
        pw.print(prefix); pw.print("Last prune: "); pw.println(mLastPrune);

        final int size = mSessions.size();
        if (size == 0) {
@@ -604,4 +633,62 @@ final class AutofillManagerServiceImpl {
                + ", component=" + (mInfo != null
                ? mInfo.getServiceInfo().getComponentName() : null) + "]";
    }

    /** Task used to prune abandoned session */
    private class PruneTask extends AsyncTask<Void, Void, Void> {
        @Override
        protected Void doInBackground(Void... ignored) {
            int numSessionsToRemove;
            ArrayMap<IBinder, Integer> sessionsToRemove;

            synchronized (mLock) {
                numSessionsToRemove = mSessions.size();
                sessionsToRemove = new ArrayMap<>(numSessionsToRemove);

                for (int i = 0; i < numSessionsToRemove; i++) {
                    Session session = mSessions.valueAt(i);

                    sessionsToRemove.put(session.getActivityTokenLocked(), session.id);
                }
            }

            IActivityManager am = ActivityManager.getService();

            // Only remove sessions which's activities are not known to the activity manager anymore
            for (int i = 0; i < numSessionsToRemove; i++) {
                try {
                    // The activity manager cannot resolve activities that have been removed
                    if (am.getActivityClassForToken(sessionsToRemove.keyAt(i)) != null) {
                        sessionsToRemove.removeAt(i);
                        i--;
                        numSessionsToRemove--;
                    }
                } catch (RemoteException e) {
                    Slog.w(TAG, "Cannot figure out if activity is finished", e);
                }
            }

            synchronized (mLock) {
                for (int i = 0; i < numSessionsToRemove; i++) {
                    Session sessionToRemove = mSessions.get(sessionsToRemove.valueAt(i));

                    if (sessionToRemove != null) {
                        if (sessionToRemove.isSavingLocked()) {
                            if (sVerbose) {
                                Slog.v(TAG, "Session " + sessionToRemove.id + " is saving");
                            }
                        } else {
                            if (sDebug) {
                                Slog.i(TAG, "Prune session " + sessionToRemove.id + " ("
                                    + sessionToRemove.getActivityTokenLocked() + ")");
                            }
                            sessionToRemove.removeSelfLocked();
                        }
                    }
                }
            }

            return null;
        }
    }
}
+21 −1
Original line number Diff line number Diff line
@@ -177,6 +177,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
    @GuardedBy("mLock")
    private boolean mDestroyed;

    /** Whether the session is currently saving */
    @GuardedBy("mLock")
    private boolean mIsSaving;

    /**
     * Receiver of assist data from the app's {@link Activity}.
     */
@@ -361,7 +365,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
     *
     * @return The activity token
     */
    IBinder getActivityTokenLocked() {
    @NonNull IBinder getActivityTokenLocked() {
        return mActivityToken;
    }

@@ -474,6 +478,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
    @Override
    public void onSaveRequestSuccess(@NonNull String servicePackageName) {
        synchronized (mLock) {
            mIsSaving = false;

            if (mDestroyed) {
                Slog.w(TAG, "Call to Session#onSaveRequestSuccess() rejected - session: "
                        + id + " destroyed");
@@ -496,6 +502,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
    public void onSaveRequestFailure(@Nullable CharSequence message,
            @NonNull String servicePackageName) {
        synchronized (mLock) {
            mIsSaving = false;

            if (mDestroyed) {
                Slog.w(TAG, "Call to Session#onSaveRequestFailure() rejected - session: "
                        + id + " destroyed");
@@ -596,6 +604,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
    @Override
    public void cancelSave() {
        synchronized (mLock) {
            mIsSaving = false;

            if (mDestroyed) {
                Slog.w(TAG, "Call to Session#cancelSave() rejected - session: "
                        + id + " destroyed");
@@ -831,6 +841,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
            if (atLeastOneChanged) {
                mService.setSaveShown();
                getUiForShowing().showSaveUi(mService.getServiceLabel(), saveInfo, mPackageName);

                mIsSaving = true;
                return false;
            }
        }
@@ -843,6 +855,13 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
        return true;
    }

    /**
     * Returns whether the session is currently showing the save UI
     */
    boolean isSavingLocked() {
        return mIsSaving;
    }

    /**
     * Calls service when user requested save.
     */
@@ -1349,6 +1368,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
        pw.print(prefix); pw.print("mCurrentViewId: "); pw.println(mCurrentViewId);
        pw.print(prefix); pw.print("mViewStates size: "); pw.println(mViewStates.size());
        pw.print(prefix); pw.print("mDestroyed: "); pw.println(mDestroyed);
        pw.print(prefix); pw.print("mIsSaving: "); pw.println(mIsSaving);
        final String prefix2 = prefix + "  ";
        for (Map.Entry<AutofillId, ViewState> entry : mViewStates.entrySet()) {
            pw.print(prefix); pw.print("State for id "); pw.println(entry.getKey());
+4 −0
Original line number Diff line number Diff line
@@ -264,6 +264,10 @@ public final class AutoFillUI {
                public void onDestroy() {
                    if (log.getType() == MetricsProto.MetricsEvent.TYPE_UNKNOWN) {
                        log.setType(MetricsProto.MetricsEvent.TYPE_CLOSE);

                        if (mCallback != null) {
                            mCallback.cancelSave();
                        }
                    }
                    mMetricsLogger.write(log);
                }