diff options
| author | Felipe Leme <felipeal@google.com> | 2018-06-18 13:56:38 -0700 |
|---|---|---|
| committer | Felipe Leme <felipeal@google.com> | 2018-07-12 10:37:05 -0700 |
| commit | d4e52285ed840d438ea59104f6ee606ed3b5d8db (patch) | |
| tree | f1e756dcf5f3bcf3cb0e2a6fada0f218e16a74fe /core/java | |
| parent | d955be72b74638402fa723c023c1cdb795869a36 (diff) | |
Make IAutofillManager fully oneway.
The critical methods on this interface - like updateSession() - were already
void, so all we had to do were to "onewaywize" the other methods. We could
either refactor them to be truly async, or implement a blocking mechanism that
let them still be sync *and* oneway - because these methods are not in the
critical path, we opted for the latter, which is simpler and less risky.
Fixes: 73536867
Test: mmma -j ./frameworks/base/apct-tests/perftests/autofill/ && \
adb install -r $OUT/data/app/AutofillPerfTests/AutofillPerfTests.apk && \
adb shell am instrument -w -e class android.view.autofill.LoginTest \
com.android.perftests.autofill/android.support.test.runner.AndroidJUnitRunner
Test: CtsAutoFillServiceTestCases
Change-Id: I380430aa2a7805aed6f629afb360566fc5402abb
Diffstat (limited to 'core/java')
| -rw-r--r-- | core/java/android/view/autofill/AutofillManager.java | 157 | ||||
| -rw-r--r-- | core/java/android/view/autofill/IAutoFillManager.aidl | 50 |
2 files changed, 165 insertions, 42 deletions
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index 8f28102016d7..0504d1ede603 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -57,6 +57,7 @@ import android.view.accessibility.AccessibilityWindowInfo; import com.android.internal.annotations.GuardedBy; import com.android.internal.logging.MetricsLogger; 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; @@ -72,6 +73,8 @@ 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; @@ -572,10 +575,11 @@ public final class AutofillManager { final AutofillClient client = getClient(); if (client != null) { + final SyncResultReceiver receiver = new SyncResultReceiver(); try { - final boolean sessionWasRestored = mService.restoreSession(mSessionId, - client.autofillClientGetActivityToken(), - mServiceClient.asBinder()); + mService.restoreSession(mSessionId, client.autofillClientGetActivityToken(), + mServiceClient.asBinder(), receiver); + final boolean sessionWasRestored = receiver.getIntResult() == 1; if (!sessionWasRestored) { Log.w(TAG, "Session " + mSessionId + " could not be restored"); @@ -691,7 +695,9 @@ public final class AutofillManager { */ @Nullable public FillEventHistory getFillEventHistory() { try { - return mService.getFillEventHistory(); + final SyncResultReceiver receiver = new SyncResultReceiver(); + mService.getFillEventHistory(receiver); + return receiver.getObjectResult(SyncResultReceiver.TYPE_PARCELABLE); } catch (RemoteException e) { e.rethrowFromSystemServer(); return null; @@ -1242,8 +1248,10 @@ public final class AutofillManager { public boolean hasEnabledAutofillServices() { if (mService == null) return false; + final SyncResultReceiver receiver = new SyncResultReceiver(); try { - return mService.isServiceEnabled(mContext.getUserId(), mContext.getPackageName()); + mService.isServiceEnabled(mContext.getUserId(), mContext.getPackageName(), receiver); + return receiver.getIntResult() == 1; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1257,8 +1265,10 @@ public final class AutofillManager { public ComponentName getAutofillServiceComponentName() { if (mService == null) return null; + final SyncResultReceiver receiver = new SyncResultReceiver(); try { - return mService.getAutofillServiceComponentName(); + mService.getAutofillServiceComponentName(receiver); + return receiver.getObjectResult(SyncResultReceiver.TYPE_PARCELABLE); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1281,7 +1291,9 @@ public final class AutofillManager { */ @Nullable public String getUserDataId() { try { - return mService.getUserDataId(); + final SyncResultReceiver receiver = new SyncResultReceiver(); + mService.getUserDataId(receiver); + return receiver.getObjectResult(SyncResultReceiver.TYPE_STRING); } catch (RemoteException e) { e.rethrowFromSystemServer(); return null; @@ -1301,7 +1313,9 @@ public final class AutofillManager { */ @Nullable public UserData getUserData() { try { - return mService.getUserData(); + final SyncResultReceiver receiver = new SyncResultReceiver(); + mService.getUserData(receiver); + return receiver.getObjectResult(SyncResultReceiver.TYPE_PARCELABLE); } catch (RemoteException e) { e.rethrowFromSystemServer(); return null; @@ -1337,8 +1351,10 @@ public final class AutofillManager { * the user. */ public boolean isFieldClassificationEnabled() { + final SyncResultReceiver receiver = new SyncResultReceiver(); try { - return mService.isFieldClassificationEnabled(); + mService.isFieldClassificationEnabled(receiver); + return receiver.getIntResult() == 1; } catch (RemoteException e) { e.rethrowFromSystemServer(); return false; @@ -1358,8 +1374,10 @@ public final class AutofillManager { */ @Nullable public String getDefaultFieldClassificationAlgorithm() { + final SyncResultReceiver receiver = new SyncResultReceiver(); try { - return mService.getDefaultFieldClassificationAlgorithm(); + mService.getDefaultFieldClassificationAlgorithm(receiver); + return receiver.getObjectResult(SyncResultReceiver.TYPE_STRING); } catch (RemoteException e) { e.rethrowFromSystemServer(); return null; @@ -1376,9 +1394,10 @@ public final class AutofillManager { */ @NonNull public List<String> getAvailableFieldClassificationAlgorithms() { - final String[] algorithms; + final SyncResultReceiver receiver = new SyncResultReceiver(); try { - algorithms = mService.getAvailableFieldClassificationAlgorithms(); + mService.getAvailableFieldClassificationAlgorithms(receiver); + final String[] algorithms = receiver.getObjectResult(SyncResultReceiver.TYPE_STRING); return algorithms != null ? Arrays.asList(algorithms) : Collections.emptyList(); } catch (RemoteException e) { e.rethrowFromSystemServer(); @@ -1399,8 +1418,10 @@ public final class AutofillManager { public boolean isAutofillSupported() { if (mService == null) return false; + final SyncResultReceiver receiver = new SyncResultReceiver(); try { - return mService.isServiceSupported(mContext.getUserId()); + mService.isServiceSupported(mContext.getUserId(), receiver); + return receiver.getIntResult() == 1; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1521,10 +1542,12 @@ public final class AutofillManager { final AutofillClient client = getClient(); if (client == null) return; // NOTE: getClient() already logged it.. - mSessionId = mService.startSession(client.autofillClientGetActivityToken(), + final SyncResultReceiver receiver = new SyncResultReceiver(); + mService.startSession(client.autofillClientGetActivityToken(), mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(), mCallback != null, flags, client.autofillClientGetComponentName(), - isCompatibilityModeEnabledLocked()); + isCompatibilityModeEnabledLocked(), receiver); + mSessionId = receiver.getIntResult(); if (mSessionId != NO_SESSION) { mState = STATE_ACTIVE; } @@ -1602,7 +1625,9 @@ public final class AutofillManager { mServiceClient = new AutofillManagerClient(this); try { final int userId = mContext.getUserId(); - final int flags = mService.addClient(mServiceClient, userId); + final SyncResultReceiver receiver = new SyncResultReceiver(); + mService.addClient(mServiceClient, userId, receiver); + final int flags = receiver.getIntResult(); mEnabled = (flags & FLAG_ADD_CLIENT_ENABLED) != 0; sDebug = (flags & FLAG_ADD_CLIENT_DEBUG) != 0; sVerbose = (flags & FLAG_ADD_CLIENT_VERBOSE) != 0; @@ -2818,4 +2843,104 @@ 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.getString(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/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl index 6b26f233f58c..26aeba5cfdfa 100644 --- a/core/java/android/view/autofill/IAutoFillManager.aidl +++ b/core/java/android/view/autofill/IAutoFillManager.aidl @@ -28,41 +28,39 @@ import android.service.autofill.UserData; import android.view.autofill.AutofillId; import android.view.autofill.AutofillValue; import android.view.autofill.IAutoFillManagerClient; +import com.android.internal.os.IResultReceiver; /** * Mediator between apps being auto-filled and auto-fill service implementations. * * {@hide} */ - // TODO(b/73536867) STOPSHIP : this whole interface should be either oneway or not, and we're - // gradually converting the methods (as some of them return a value form the server and must be - // refactored). -interface IAutoFillManager { +oneway interface IAutoFillManager { // Returns flags: FLAG_ADD_CLIENT_ENABLED | FLAG_ADD_CLIENT_DEBUG | FLAG_ADD_CLIENT_VERBOSE - int addClient(in IAutoFillManagerClient client, int userId); + void addClient(in IAutoFillManagerClient client, int userId, in IResultReceiver result); void removeClient(in IAutoFillManagerClient client, int userId); - int startSession(IBinder activityToken, in IBinder appCallback, in AutofillId autoFillId, - in Rect bounds, in AutofillValue value, int userId, boolean hasCallback, int flags, - in ComponentName componentName, boolean compatMode); - FillEventHistory getFillEventHistory(); - boolean restoreSession(int sessionId, in IBinder activityToken, in IBinder appCallback); - oneway void updateSession(int sessionId, in AutofillId id, in Rect bounds, - in AutofillValue value, int action, int flags, int userId); - oneway void setAutofillFailure(int sessionId, in List<AutofillId> ids, int userId); - oneway void finishSession(int sessionId, int userId); - oneway void cancelSession(int sessionId, int userId); - oneway void setAuthenticationResult(in Bundle data, int sessionId, int authenticationId, - int userId); - oneway void setHasCallback(int sessionId, int userId, boolean hasIt); + void startSession(IBinder activityToken, in IBinder appCallback, in AutofillId autoFillId, + in Rect bounds, in AutofillValue value, int userId, boolean hasCallback, int flags, + in ComponentName componentName, boolean compatMode, in IResultReceiver result); + void getFillEventHistory(in IResultReceiver result); + void restoreSession(int sessionId, in IBinder activityToken, in IBinder appCallback, + in IResultReceiver result); + void updateSession(int sessionId, in AutofillId id, in Rect bounds, + in AutofillValue value, int action, int flags, int userId); + void setAutofillFailure(int sessionId, in List<AutofillId> ids, int userId); + void finishSession(int sessionId, int userId); + void cancelSession(int sessionId, int userId); + void setAuthenticationResult(in Bundle data, int sessionId, int authenticationId, int userId); + void setHasCallback(int sessionId, int userId, boolean hasIt); void disableOwnedAutofillServices(int userId); - boolean isServiceSupported(int userId); - boolean isServiceEnabled(int userId, String packageName); + void isServiceSupported(int userId, in IResultReceiver result); + void isServiceEnabled(int userId, String packageName, in IResultReceiver result); void onPendingSaveUi(int operation, IBinder token); - UserData getUserData(); - String getUserDataId(); + void getUserData(in IResultReceiver result); + void getUserDataId(in IResultReceiver result); void setUserData(in UserData userData); - boolean isFieldClassificationEnabled(); - ComponentName getAutofillServiceComponentName(); - String[] getAvailableFieldClassificationAlgorithms(); - String getDefaultFieldClassificationAlgorithm(); + void isFieldClassificationEnabled(in IResultReceiver result); + void getAutofillServiceComponentName(in IResultReceiver result); + void getAvailableFieldClassificationAlgorithms(in IResultReceiver result); + void getDefaultFieldClassificationAlgorithm(in IResultReceiver result); } |
