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

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

Merge "Moved AutofillManager.SyncResultReceiver to an internal utility package"

parents 7936113d c0c15a3f
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) {