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
This commit is contained in:
Felipe Leme
2018-06-18 13:56:38 -07:00
parent d955be72b7
commit d4e52285ed
3 changed files with 254 additions and 84 deletions

View File

@@ -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;
}
}
}

View File

@@ -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);
}