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

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

Moved AutofillManager.SyncResultReceiver to an internal utility package

Bug: 121047489
Test: atest CtsAutoFillServiceTestCases # which is crashing due to unrelated issue

Change-Id: I4aba260e9878b1b420dfb7290f2389199c32a82f
parent e6baf1a4
Loading
Loading
Loading
Loading
+26 −121
Original line number Diff line number Diff line
@@ -62,6 +62,7 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.os.IResultReceiver;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
import com.android.internal.util.SyncResultReceiver;

import org.xmlpull.v1.XmlPullParserException;

@@ -75,8 +76,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

//TODO: use java.lang.ref.Cleaner once Android supports Java 9
import sun.misc.Cleaner;

@@ -323,6 +323,11 @@ public final class AutofillManager {
     */
    public static final int FC_SERVICE_TIMEOUT = 5000;

    /**
     * Timeout for calls to system_server.
     */
    private static final int SYNC_CALLS_TIMEOUT_MS = 5000;

    /**
     * Makes an authentication id from a request id and a dataset id.
     *
@@ -612,7 +617,8 @@ public final class AutofillManager {

                final AutofillClient client = getClient();
                if (client != null) {
                    final SyncResultReceiver receiver = new SyncResultReceiver();
                    final SyncResultReceiver receiver = new SyncResultReceiver(
                            SYNC_CALLS_TIMEOUT_MS);
                    try {
                        mService.restoreSession(mSessionId, client.autofillClientGetActivityToken(),
                                mServiceClient.asBinder(), receiver);
@@ -732,9 +738,9 @@ public final class AutofillManager {
     */
    @Nullable public FillEventHistory getFillEventHistory() {
        try {
            final SyncResultReceiver receiver = new SyncResultReceiver();
            final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
            mService.getFillEventHistory(receiver);
            return receiver.getObjectResult(SyncResultReceiver.TYPE_PARCELABLE);
            return receiver.getParcelableResult();
        } catch (RemoteException e) {
            e.rethrowFromSystemServer();
            return null;
@@ -1287,7 +1293,7 @@ public final class AutofillManager {
    public boolean hasEnabledAutofillServices() {
        if (mService == null) return false;

        final SyncResultReceiver receiver = new SyncResultReceiver();
        final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
        try {
            mService.isServiceEnabled(mContext.getUserId(), mContext.getPackageName(), receiver);
            return receiver.getIntResult() == 1;
@@ -1304,10 +1310,10 @@ public final class AutofillManager {
    public ComponentName getAutofillServiceComponentName() {
        if (mService == null) return null;

        final SyncResultReceiver receiver = new SyncResultReceiver();
        final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
        try {
            mService.getAutofillServiceComponentName(receiver);
            return receiver.getObjectResult(SyncResultReceiver.TYPE_PARCELABLE);
            return receiver.getParcelableResult();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
@@ -1330,9 +1336,9 @@ public final class AutofillManager {
     */
    @Nullable public String getUserDataId() {
        try {
            final SyncResultReceiver receiver = new SyncResultReceiver();
            final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
            mService.getUserDataId(receiver);
            return receiver.getObjectResult(SyncResultReceiver.TYPE_STRING);
            return receiver.getStringResult();
        } catch (RemoteException e) {
            e.rethrowFromSystemServer();
            return null;
@@ -1352,9 +1358,9 @@ public final class AutofillManager {
     */
    @Nullable public UserData getUserData() {
        try {
            final SyncResultReceiver receiver = new SyncResultReceiver();
            final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
            mService.getUserData(receiver);
            return receiver.getObjectResult(SyncResultReceiver.TYPE_PARCELABLE);
            return receiver.getParcelableResult();
        } catch (RemoteException e) {
            e.rethrowFromSystemServer();
            return null;
@@ -1390,7 +1396,7 @@ public final class AutofillManager {
     * the user.
     */
    public boolean isFieldClassificationEnabled() {
        final SyncResultReceiver receiver = new SyncResultReceiver();
        final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
        try {
            mService.isFieldClassificationEnabled(receiver);
            return receiver.getIntResult() == 1;
@@ -1413,10 +1419,10 @@ public final class AutofillManager {
     */
    @Nullable
    public String getDefaultFieldClassificationAlgorithm() {
        final SyncResultReceiver receiver = new SyncResultReceiver();
        final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
        try {
            mService.getDefaultFieldClassificationAlgorithm(receiver);
            return receiver.getObjectResult(SyncResultReceiver.TYPE_STRING);
            return receiver.getStringResult();
        } catch (RemoteException e) {
            e.rethrowFromSystemServer();
            return null;
@@ -1433,11 +1439,10 @@ public final class AutofillManager {
     */
    @NonNull
    public List<String> getAvailableFieldClassificationAlgorithms() {
        final SyncResultReceiver receiver = new SyncResultReceiver();
        final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
        try {
            mService.getAvailableFieldClassificationAlgorithms(receiver);
            final String[] algorithms = receiver
                .getObjectResult(SyncResultReceiver.TYPE_STRING_ARRAY);
            final String[] algorithms = receiver.getStringArrayResult();
            return algorithms != null ? Arrays.asList(algorithms) : Collections.emptyList();
        } catch (RemoteException e) {
            e.rethrowFromSystemServer();
@@ -1458,7 +1463,7 @@ public final class AutofillManager {
    public boolean isAutofillSupported() {
        if (mService == null) return false;

        final SyncResultReceiver receiver = new SyncResultReceiver();
        final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
        try {
            mService.isServiceSupported(mContext.getUserId(), receiver);
            return receiver.getIntResult() == 1;
@@ -1582,7 +1587,7 @@ public final class AutofillManager {
            final AutofillClient client = getClient();
            if (client == null) return; // NOTE: getClient() already logged it..

            final SyncResultReceiver receiver = new SyncResultReceiver();
            final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
            mService.startSession(client.autofillClientGetActivityToken(),
                    mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(),
                    mCallback != null, flags, client.autofillClientGetComponentName(),
@@ -1665,7 +1670,7 @@ public final class AutofillManager {
            mServiceClient = new AutofillManagerClient(this);
            try {
                final int userId = mContext.getUserId();
                final SyncResultReceiver receiver = new SyncResultReceiver();
                final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
                mService.addClient(mServiceClient, userId, receiver);
                final int flags = receiver.getIntResult();
                mEnabled = (flags & FLAG_ADD_CLIENT_ENABLED) != 0;
@@ -2986,104 +2991,4 @@ public final class AutofillManager {
            }
        }
    }

    /**
     * @hide
     */
    public static final class SyncResultReceiver extends IResultReceiver.Stub {

        private static final String EXTRA = "EXTRA";

        /**
         * How long to block waiting for {@link IResultReceiver} callbacks when calling server.
         */
        private static final long BINDER_TIMEOUT_MS = 5000;

        private static final int TYPE_STRING = 0;
        private static final int TYPE_STRING_ARRAY = 1;
        private static final int TYPE_PARCELABLE = 2;

        private final CountDownLatch mLatch  = new CountDownLatch(1);
        private int mResult;
        private Bundle mBundle;

        private void waitResult() {
            try {
                if (!mLatch.await(BINDER_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
                    throw new IllegalStateException("Not called in " + BINDER_TIMEOUT_MS + "ms");
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }

        /**
         * Gets the result from an operation that returns an {@code int}.
         */
        int getIntResult() {
            waitResult();
            return mResult;
        }

        /**
         * Gets the result from an operation that returns an {@code Object}.
         *
         * @param type type of expected object.
         */
        @Nullable
        @SuppressWarnings("unchecked")
        <T> T getObjectResult(int type) {
            waitResult();
            if (mBundle == null) {
                return null;
            }
            switch (type) {
                case TYPE_STRING:
                    return (T) mBundle.getString(EXTRA);
                case TYPE_STRING_ARRAY:
                    return (T) mBundle.getStringArray(EXTRA);
                case TYPE_PARCELABLE:
                    return (T) mBundle.getParcelable(EXTRA);
                default:
                    throw new IllegalArgumentException("unsupported type: " + type);
            }
        }

        @Override
        public void send(int resultCode, Bundle resultData) {
            mResult = resultCode;
            mBundle = resultData;
            mLatch.countDown();
        }

        /**
         * Creates a bundle for a {@code String} value.
         */
        @NonNull
        public static Bundle bundleFor(@Nullable String value) {
            final Bundle bundle = new Bundle();
            bundle.putString(EXTRA, value);
            return bundle;
        }

        /**
         * Creates a bundle for a {@code String[]} value.
         */
        @NonNull
        public static Bundle bundleFor(@Nullable String[] value) {
            final Bundle bundle = new Bundle();
            bundle.putStringArray(EXTRA, value);
            return bundle;
        }

        /**
         * Creates a bundle for a {@code Parcelable} value.
         */
        @NonNull
        public static Bundle bundleFor(@Nullable Parcelable value) {
            final Bundle bundle = new Bundle();
            bundle.putParcelable(EXTRA, value);
            return bundle;
        }
    }
}
+145 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.internal.util;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Bundle;
import android.os.Parcelable;
import android.os.RemoteException;

import com.android.internal.os.IResultReceiver;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * A {@code IResultReceiver} implementation that can be used to make "sync" Binder calls by blocking
 * until it receives a result
 *
 * @hide
 */
public final class SyncResultReceiver extends IResultReceiver.Stub {

    private static final String EXTRA = "EXTRA";

    private final CountDownLatch mLatch  = new CountDownLatch(1);
    private final int mTimeoutMs;
    private int mResult;
    private Bundle mBundle;

    /**
     * Default constructor.
     *
     * @param timeoutMs how long to block waiting for {@link IResultReceiver} callbacks.
     */
    public SyncResultReceiver(int timeoutMs) {
        mTimeoutMs = timeoutMs;
    }

    private void waitResult() throws TimeoutException {
        try {
            if (!mLatch.await(mTimeoutMs, TimeUnit.MILLISECONDS)) {
                throw new TimeoutException("Not called in " + mTimeoutMs + "ms");
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new TimeoutException("Interrupted");
        }
    }

    /**
     * Gets the result from an operation that returns an {@code int}.
     */
    public int getIntResult() throws TimeoutException {
        waitResult();
        return mResult;
    }

    /**
     * Gets the result from an operation that returns an {@code String}.
     */
    @Nullable
    public String getStringResult() throws TimeoutException {
        waitResult();
        return mBundle == null ? null : mBundle.getString(EXTRA);
    }

    /**
     * Gets the result from an operation that returns a {@code String[]}.
     */
    @Nullable
    public String[] getStringArrayResult() throws TimeoutException {
        waitResult();
        return mBundle == null ? null : mBundle.getStringArray(EXTRA);
    }

    /**
     * Gets the result from an operation that returns a {@code Parcelable}.
     */
    @Nullable
    public <P extends Parcelable> P getParcelableResult() throws TimeoutException {
        waitResult();
        return mBundle == null ? null : mBundle.getParcelable(EXTRA);
    }

    @Override
    public void send(int resultCode, Bundle resultData) {
        mResult = resultCode;
        mBundle = resultData;
        mLatch.countDown();
    }

    /**
     * Creates a bundle for a {@code String} value so it can be retrieved by
     * {@link #getStringResult()}.
     */
    @NonNull
    public static Bundle bundleFor(@Nullable String value) {
        final Bundle bundle = new Bundle();
        bundle.putString(EXTRA, value);
        return bundle;
    }

    /**
     * Creates a bundle for a {@code String[]} value so it can be retrieved by
     * {@link #getStringArrayResult()}.
     */
    @NonNull
    public static Bundle bundleFor(@Nullable String[] value) {
        final Bundle bundle = new Bundle();
        bundle.putStringArray(EXTRA, value);
        return bundle;
    }

    /**
     * Creates a bundle for a {@code Parcelable} value so it can be retrieved by
     * {@link #getParcelableResult()}.
     */
    @NonNull
    public static Bundle bundleFor(@Nullable Parcelable value) {
        final Bundle bundle = new Bundle();
        bundle.putParcelable(EXTRA, value);
        return bundle;
    }

    /** @hide */
    public static final class TimeoutException extends RemoteException {
        private TimeoutException(String msg) {
            super(msg);
        }
    }
}
+4 −3
Original line number Diff line number Diff line
@@ -70,6 +70,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.IResultReceiver;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.Preconditions;
import com.android.internal.util.SyncResultReceiver;
import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.autofill.ui.AutoFillUI;
@@ -606,15 +607,15 @@ public final class AutofillManagerService
    }

    private void send(@NonNull IResultReceiver receiver, @Nullable String value) {
        send(receiver, AutofillManager.SyncResultReceiver.bundleFor(value));
        send(receiver, SyncResultReceiver.bundleFor(value));
    }

    private void send(@NonNull IResultReceiver receiver, @Nullable String[] value) {
        send(receiver, AutofillManager.SyncResultReceiver.bundleFor(value));
        send(receiver, SyncResultReceiver.bundleFor(value));
    }

    private void send(@NonNull IResultReceiver receiver, @Nullable Parcelable value) {
        send(receiver, AutofillManager.SyncResultReceiver.bundleFor(value));
        send(receiver, SyncResultReceiver.bundleFor(value));
    }

    private void send(@NonNull IResultReceiver receiver, boolean value) {