Loading core/java/android/view/autofill/AutofillManager.java +26 −121 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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. * Loading Loading @@ -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); Loading Loading @@ -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; Loading Loading @@ -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; Loading @@ -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(); } Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; Loading @@ -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(); Loading @@ -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; Loading Loading @@ -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(), Loading Loading @@ -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; Loading Loading @@ -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; } } } core/java/com/android/internal/util/SyncResultReceiver.java 0 → 100644 +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); } } } services/autofill/java/com/android/server/autofill/AutofillManagerService.java +4 −3 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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) { Loading Loading
core/java/android/view/autofill/AutofillManager.java +26 −121 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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. * Loading Loading @@ -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); Loading Loading @@ -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; Loading Loading @@ -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; Loading @@ -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(); } Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; Loading @@ -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(); Loading @@ -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; Loading Loading @@ -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(), Loading Loading @@ -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; Loading Loading @@ -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; } } }
core/java/com/android/internal/util/SyncResultReceiver.java 0 → 100644 +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); } } }
services/autofill/java/com/android/server/autofill/AutofillManagerService.java +4 −3 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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) { Loading