summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/view/autofill/AutofillManager.java147
-rw-r--r--core/java/com/android/internal/util/SyncResultReceiver.java145
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerService.java7
3 files changed, 175 insertions, 124 deletions
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 56f973eb9e46..90ccc257b134 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -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;
@@ -324,6 +324,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.
*
* @param requestId The request 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;
- }
- }
}
diff --git a/core/java/com/android/internal/util/SyncResultReceiver.java b/core/java/com/android/internal/util/SyncResultReceiver.java
new file mode 100644
index 000000000000..9a346ac93a8d
--- /dev/null
+++ b/core/java/com/android/internal/util/SyncResultReceiver.java
@@ -0,0 +1,145 @@
+/*
+ * 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);
+ }
+ }
+}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 1a6bee9daaf3..6cccd62d563f 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -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) {