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

Commit 69a1cae4 authored by Felipe Leme's avatar Felipe Leme
Browse files

Add Shell commands to list and reset auto-fill sessions.

These commands are useful during development and CTS tests (for
example, the test can assert there is no dangling session after it's
finished).

BUG: 33802548

Test: manual verification
Change-Id: I61f96e30d07642fa2165df9b982c6bf32a4e8716
parent 62185042
Loading
Loading
Loading
Loading
+63 −0
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ import android.database.ContentObserver;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -54,12 +55,14 @@ import android.view.autofill.AutoFillValue;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.BackgroundThread;
import com.android.internal.os.HandlerCaller;
import com.android.internal.os.IResultReceiver;
import com.android.internal.os.SomeArgs;
import com.android.server.LocalServices;
import com.android.server.SystemService;

import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

/**
@@ -77,6 +80,10 @@ public final class AutoFillManagerService extends SystemService {
    private static final int MSG_UPDATE_SESSION = 2;
    private static final int MSG_FINISH_SESSION = 3;
    private static final int MSG_REQUEST_SAVE_FOR_USER = 4;
    private static final int MSG_LIST_SESSIONS = 5;
    private static final int MSG_RESET = 6;

    static final String RECEIVER_BUNDLE_EXTRA_SESSIONS = "sessions";

    private final Context mContext;
    private final AutoFillUI mUi;
@@ -111,6 +118,12 @@ public final class AutoFillManagerService extends SystemService {
                final int flags = args.argi6;
                handleUpdateSession(userId, activityToken, autoFillId, bounds, value, flags);
                return;
            } case MSG_LIST_SESSIONS: {
                handleListForUser(msg.arg1, (IResultReceiver) msg.obj);
                return;
            } case MSG_RESET: {
                handleReset();
                return;
            } default: {
                Slog.w(TAG, "Invalid message: " + msg);
            }
@@ -203,12 +216,29 @@ public final class AutoFillManagerService extends SystemService {
        return service;
    }

    // Called by Shell command.
    void requestSaveForUser(int userId) {
        Slog.i(TAG, "requestSaveForUser(): " + userId);
        mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
        mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageI(
                MSG_REQUEST_SAVE_FOR_USER, userId));
    }

    // Called by Shell command.
    void listSessions(int userId, IResultReceiver receiver) {
        Slog.i(TAG, "listSessions() for userId " + userId);
        mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
        mHandlerCaller.sendMessage(
                mHandlerCaller.obtainMessageIO(MSG_LIST_SESSIONS, userId, receiver));
    }

    // Called by Shell command.
    void reset() {
        Slog.i(TAG, "reset()");
        mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
        mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_RESET));
    }

    /**
     * Removes a cached service for a given user.
     */
@@ -279,6 +309,39 @@ public final class AutoFillManagerService extends SystemService {
        }
    }

    private void handleListForUser(int userId, IResultReceiver receiver) {
        final Bundle resultData = new Bundle();
        final ArrayList<String> sessions = new ArrayList<>();

        synchronized (mLock) {
            if (userId != UserHandle.USER_ALL) {
                mServicesCache.get(userId).listSessionsLocked(sessions);
            } else {
                final int size = mServicesCache.size();
                for (int i = 0; i < size; i++) {
                    mServicesCache.valueAt(i).listSessionsLocked(sessions);
                }
            }
        }

        resultData.putStringArrayList(RECEIVER_BUNDLE_EXTRA_SESSIONS, sessions);
        try {
            receiver.send(0, resultData);
        } catch (RemoteException e) {
            // Just ignore it...
        }
    }

    private void handleReset() {
        synchronized (mLock) {
            final int size = mServicesCache.size();
            for (int i = 0; i < size; i++) {
                mServicesCache.valueAt(i).destroyLocked();
            }
            mServicesCache.clear();
        }
    }

    final class AutoFillManagerServiceStub extends IAutoFillManagerService.Stub {

        @Override
+7 −0
Original line number Diff line number Diff line
@@ -70,6 +70,7 @@ import com.android.internal.os.IResultReceiver;
import com.android.server.FgThread;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Map;
import java.util.Map.Entry;

@@ -330,6 +331,12 @@ final class AutoFillManagerServiceImpl {
        }
    }

    void listSessionsLocked(ArrayList<String> output) {
        for (IBinder activityToken : mSessions.keySet()) {
            output.add(mComponentName + ":" + activityToken);
        }
    }

    @Override
    public String toString() {
        return "AutoFillManagerServiceImpl: [userId=" + mUserId
+77 −13
Original line number Diff line number Diff line
@@ -16,12 +16,20 @@

package com.android.server.autofill;

import static com.android.server.autofill.AutoFillManagerService.RECEIVER_BUNDLE_EXTRA_SESSIONS;

import android.app.ActivityManager;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.ShellCommand;
import android.os.UserHandle;

import com.android.internal.os.IResultReceiver;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

public final class AutoFillManagerServiceShellCommand extends ShellCommand {

@@ -37,17 +45,16 @@ public final class AutoFillManagerServiceShellCommand extends ShellCommand {
            return handleDefaultCommands(cmd);
        }
        final PrintWriter pw = getOutPrintWriter();
        try {
        switch (cmd) {
            case "save":
                return requestSave();
            case "list":
                return requestList(pw);
            case "reset":
                return requestReset();
            default:
                return handleDefaultCommands(cmd);
        }
        } catch (RemoteException e) {
            pw.println("error: " + e);
        }
        return -1;
    }

    @Override
@@ -57,22 +64,79 @@ public final class AutoFillManagerServiceShellCommand extends ShellCommand {
            pw.println("  help");
            pw.println("    Prints this help text.");
            pw.println("");
            pw.println("  list sessions [--user USER_ID]");
            pw.println("    List all pending sessions.");
            pw.println("");
            pw.println("  save [--user USER_ID]");
            pw.println("    Request provider to save contents of the top activity. ");
            pw.println("");
            pw.println("  reset");
            pw.println("    Reset all pending sessions and cached service connections.");
            pw.println("");
        }
    }

    private int requestSave() throws RemoteException {
        final int userId = getUserIdFromArgs();
    private int requestSave() {
        final int userId = getUserIdFromArgsOrCurrentUser();
        mService.requestSaveForUser(userId);
        return 0;
    }

    private int getUserIdFromArgs() {
    private int requestList(PrintWriter pw) {
        final String type = getNextArgRequired();
        if (!type.equals("sessions")) {
            pw.println("Error: invalid list type");
            return -1;

        }
        final int userId = getUserIdFromArgsOrAllUsers();
        final CountDownLatch latch = new CountDownLatch(1);
        final IResultReceiver receiver = new IResultReceiver.Stub() {

            @Override
            public void send(int resultCode, Bundle resultData) throws RemoteException {
                final ArrayList<String> sessions = resultData
                        .getStringArrayList(RECEIVER_BUNDLE_EXTRA_SESSIONS);

                for (String session : sessions) {
                    pw.println(session);
                }
                latch.countDown();
            }
        };

        mService.listSessions(userId, receiver);

        try {
            final boolean received = latch.await(5, TimeUnit.SECONDS);
            if (!received) {
                pw.println("Timed out after 5 seconds");
                return -1;
            }
        } catch (InterruptedException e) {
            pw.println("System call interrupted");
            Thread.currentThread().interrupt();
            return -1;
        }
        return 0;
    }

    private int requestReset() {
        mService.reset();
        return 0;
    }

    private int getUserIdFromArgsOrCurrentUser() {
        if ("--user".equals(getNextArg())) {
            return UserHandle.parseUserArg(getNextArgRequired());
        }
        return ActivityManager.getCurrentUser();
    }

    private int getUserIdFromArgsOrAllUsers() {
        if ("--user".equals(getNextArg())) {
            return UserHandle.parseUserArg(getNextArgRequired());
        }
        return UserHandle.USER_ALL;
    }
}