Initial implementation of AutofillManager.setAugmentedAutofillWhitelist()

For now it only whitelists packages, not activities.

Test: atest CtsAutoFillServiceTestCases:android.autofillservice.cts.augmented.AugmentedLoginActivityTest

Bug: 123100824

Change-Id: I043f4a22684fcdac7409393c208c2c1e6d987c5e
This commit is contained in:
Felipe Leme
2019-02-14 10:56:52 -08:00
parent d6ea41c22e
commit 80e7bf114d
6 changed files with 194 additions and 14 deletions

View File

@@ -369,6 +369,11 @@ public final class AutofillManager {
public static final String DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES =
"smart_suggestion_supported_modes";
/** @hide */
public static final int RESULT_OK = 0;
/** @hide */
public static final int RESULT_CODE_NOT_SERVICE = -1;
/**
* Makes an authentication id from a request id and a dataset id.
*
@@ -1789,7 +1794,11 @@ public final class AutofillManager {
@Deprecated
public void setAugmentedAutofillWhitelist(@Nullable List<String> packages,
@Nullable List<ComponentName> activities) {
// TODO(b/123100824): implement
setAugmentedAutofillWhitelist(toSet(packages), toSet(activities));
}
private <T> ArraySet<T> toSet(@Nullable List<T> set) {
return set == null ? null : new ArraySet<T>(set);
}
/**
@@ -1814,7 +1823,32 @@ public final class AutofillManager {
@TestApi
public void setAugmentedAutofillWhitelist(@Nullable Set<String> packages,
@Nullable Set<ComponentName> activities) {
// TODO(b/123100824): implement
if (!hasAutofillFeature()) {
return;
}
final SyncResultReceiver resultReceiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
final int resultCode;
try {
mService.setAugmentedAutofillWhitelist(toList(packages), toList(activities),
resultReceiver);
resultCode = resultReceiver.getIntResult();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
switch (resultCode) {
case RESULT_OK:
return;
case RESULT_CODE_NOT_SERVICE:
throw new SecurityException("caller is not user's Augmented Autofill Service");
default:
Log.wtf(TAG, "setAugmentedAutofillWhitelist(): received invalid result: "
+ resultCode);
}
}
private <T> ArrayList<T> toList(@Nullable Set<T> set) {
return set == null ? null : new ArrayList<T>(set);
}
private void requestShowFillUi(int sessionId, AutofillId id, int width, int height,

View File

@@ -63,4 +63,6 @@ oneway interface IAutoFillManager {
void getAutofillServiceComponentName(in IResultReceiver result);
void getAvailableFieldClassificationAlgorithms(in IResultReceiver result);
void getDefaultFieldClassificationAlgorithm(in IResultReceiver result);
void setAugmentedAutofillWhitelist(in List<String> packages, in List<ComponentName> activities,
in IResultReceiver result);
}

View File

@@ -1025,6 +1025,29 @@ public final class AutofillManagerService
send(receiver, algorithm);
}
@Override
public void setAugmentedAutofillWhitelist(@Nullable List<String> packages,
@Nullable List<ComponentName> activities, @NonNull IResultReceiver receiver)
throws RemoteException {
final int userId = UserHandle.getCallingUserId();
boolean ok;
synchronized (mLock) {
final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
if (service != null) {
ok = service.setAugmentedAutofillWhitelistLocked(packages, activities,
getCallingUid());
} else {
if (sVerbose) {
Slog.v(TAG, "setAugmentedAutofillWhitelist(): no service for " + userId);
}
ok = false;
}
}
send(receiver,
ok ? AutofillManager.RESULT_OK : AutofillManager.RESULT_CODE_NOT_SERVICE);
}
@Override
public void getAvailableFieldClassificationAlgorithms(@NonNull IResultReceiver receiver)
throws RemoteException {

View File

@@ -40,6 +40,7 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -58,6 +59,7 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.DebugUtils;
import android.util.LocalLog;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
@@ -165,6 +167,16 @@ final class AutofillManagerServiceImpl
@Nullable
private RemoteAugmentedAutofillService mRemoteAugmentedAutofillService;
@GuardedBy("mLock")
@Nullable
private ServiceInfo mRemoteAugmentedAutofillServiceInfo;
/**
* List of packages that are whitelisted to be trigger augmented autofill.
*/
@GuardedBy("mLock")
private final ArraySet<String> mWhitelistedAugmentAutofillPackages = new ArraySet<>();
AutofillManagerServiceImpl(AutofillManagerService master, Object lock,
LocalLog uiLatencyHistory, LocalLog wtfHistory, int userId, AutoFillUI ui,
AutofillCompatState autofillCompatState,
@@ -844,10 +856,11 @@ final class AutofillManagerServiceImpl
}
@GuardedBy("mLock")
private boolean isCalledByServiceLocked(String methodName, int callingUid) {
if (getServiceUidLocked() != callingUid) {
private boolean isCalledByServiceLocked(@NonNull String methodName, int callingUid) {
final int serviceUid = getServiceUidLocked();
if (serviceUid != callingUid) {
Slog.w(TAG, methodName + "() called by UID " + callingUid
+ ", but service UID is " + getServiceUidLocked());
+ ", but service UID is " + serviceUid);
return false;
}
return true;
@@ -886,6 +899,19 @@ final class AutofillManagerServiceImpl
pw.print(prefix); pw.println("RemoteAugmentedAutofillService: ");
mRemoteAugmentedAutofillService.dump(prefix2, pw);
}
if (mRemoteAugmentedAutofillServiceInfo != null) {
pw.print(prefix); pw.print("RemoteAugmentedAutofillServiceInfo: ");
pw.println(mRemoteAugmentedAutofillServiceInfo);
}
final int whitelistSize = mWhitelistedAugmentAutofillPackages.size();
pw.print(prefix); pw.print("Packages whitelisted for augmented autofill: ");
pw.println(whitelistSize);
for (int i = 0; i < whitelistSize; i++) {
final String whitelistedPkg = mWhitelistedAugmentAutofillPackages.valueAt(i);
pw.print(prefix2); pw.print(i + 1); pw.print(": "); pw.println(whitelistedPkg);
}
pw.print(prefix); pw.print("Field classification enabled: ");
pw.println(isFieldClassificationEnabledLocked());
pw.print(prefix); pw.print("Compat pkgs: ");
@@ -1037,9 +1063,13 @@ final class AutofillManagerServiceImpl
}
return null;
}
final ComponentName componentName = RemoteAugmentedAutofillService.getComponentName(
serviceName, mUserId, mAugmentedAutofillResolver.isTemporary(mUserId));
if (componentName == null) return null;
final Pair<ServiceInfo, ComponentName> pair = RemoteAugmentedAutofillService
.getComponentName(
serviceName, mUserId, mAugmentedAutofillResolver.isTemporary(mUserId));
if (pair == null) return null;
mRemoteAugmentedAutofillServiceInfo = pair.first;
final ComponentName componentName = pair.second;
if (sVerbose) {
Slog.v(TAG, "getRemoteAugmentedAutofillServiceLocked(): " + componentName);
}
@@ -1067,9 +1097,87 @@ final class AutofillManagerServiceImpl
private void updateRemoteAugmentedAutofillService(@Nullable String serviceName) {
if (serviceName == null) {
if (sVerbose) Slog.v(TAG, "updateRemoteAugmentedAutofillService(): time's up!");
if (mRemoteAugmentedAutofillService != null) {
mRemoteAugmentedAutofillService.destroy();
mRemoteAugmentedAutofillService = null;
synchronized (mLock) {
if (mRemoteAugmentedAutofillService != null) {
mRemoteAugmentedAutofillService.destroy();
mRemoteAugmentedAutofillService = null;
}
}
}
}
/**
* Sets which packages and activities can trigger augmented autofill.
*
* @return whether caller UID is the augmented autofill service for the user
*/
boolean setAugmentedAutofillWhitelistLocked(List<String> packages,
List<ComponentName> activities, int callingUid) {
if (!isCalledByAugmentedAutofillServiceLocked("setAugmentedAutofillWhitelistLocked",
callingUid)) {
return false;
}
if (mMaster.verbose) {
Slog.v(TAG, "setAugmentedAutofillWhitelistLocked(packages=" + packages + ", activities="
+ activities + ")");
}
whitelistForAugmentedAutofillPackages(packages);
// TODO(b/123100824): whitelist activities as well
// TODO(b/122858578): log metrics
return true;
}
@GuardedBy("mLock")
private boolean isCalledByAugmentedAutofillServiceLocked(@NonNull String methodName,
int callingUid) {
// Lazy load service first
final RemoteAugmentedAutofillService service = getRemoteAugmentedAutofillServiceLocked();
if (service == null) {
Slog.w(TAG, methodName + "() called by UID " + callingUid
+ ", but there is no augmented autofill service defined for user "
+ getUserId());
return false;
}
if (getAugmentedAutofillServiceUidLocked() != callingUid) {
Slog.w(TAG, methodName + "() called by UID " + callingUid
+ ", but service UID is " + getAugmentedAutofillServiceUidLocked()
+ " for user " + getUserId());
return false;
}
return true;
}
@GuardedBy("mLock")
private int getAugmentedAutofillServiceUidLocked() {
if (mRemoteAugmentedAutofillServiceInfo == null) {
if (mMaster.verbose) {
Slog.v(TAG, "getAugmentedAutofillServiceUid(): "
+ "no mRemoteAugmentedAutofillServiceInfo");
}
return Process.INVALID_UID;
}
return mRemoteAugmentedAutofillServiceInfo.applicationInfo.uid;
}
@GuardedBy("mLock")
boolean isWhitelistedForAugmentedAutofillLocked(@NonNull ComponentName componentName) {
// TODO(b/122595322): need to check whitelisted activities as well.
final String packageName = componentName.getPackageName();
return mWhitelistedAugmentAutofillPackages.contains(packageName);
}
private void whitelistForAugmentedAutofillPackages(@NonNull List<String> packages) {
// TODO(b/123100824): add CTS test for when it's null
synchronized (mLock) {
if (packages == null) {
if (mMaster.verbose) Slog.v(TAG, "clearing all whitelisted augmented packages");
mWhitelistedAugmentAutofillPackages.clear();
} else {
if (mMaster.verbose) Slog.v(TAG, "whitelisting augmented packages: " + packages);
mWhitelistedAugmentAutofillPackages.addAll(packages);
}
}
}

View File

@@ -32,6 +32,7 @@ import android.service.autofill.augmented.AugmentedAutofillService;
import android.service.autofill.augmented.IAugmentedAutofillService;
import android.service.autofill.augmented.IFillCallback;
import android.text.format.DateUtils;
import android.util.Pair;
import android.util.Slog;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
@@ -57,7 +58,7 @@ final class RemoteAugmentedAutofillService
}
@Nullable
public static ComponentName getComponentName(@NonNull String componentName,
static Pair<ServiceInfo, ComponentName> getComponentName(@NonNull String componentName,
@UserIdInt int userId, boolean isTemporary) {
int flags = PackageManager.GET_META_DATA;
if (!isTemporary) {
@@ -78,7 +79,7 @@ final class RemoteAugmentedAutofillService
Slog.e(TAG, "Error getting service info for '" + componentName + "': " + e);
return null;
}
return serviceComponent;
return new Pair<>(serviceInfo, serviceComponent);
}
@Override // from AbstractRemoteService

View File

@@ -2613,13 +2613,25 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
+ " when server returned null for session " + this.id);
}
final boolean isWhitelisted = mService
.isWhitelistedForAugmentedAutofillLocked(mComponentName);
final String historyItem =
"aug:id=" + id + " u=" + uid + " m=" + mode
+ " a=" + ComponentName.flattenToShortString(mComponentName)
+ " f=" + mCurrentViewId
+ " s=" + remoteService.getComponentName();
+ " s=" + remoteService.getComponentName()
+ " w=" + isWhitelisted;
mService.getMaster().logRequestLocked(historyItem);
if (!isWhitelisted) {
if (sVerbose) {
Slog.v(TAG, mComponentName.toShortString() + " is not whitelisted for "
+ "augmented autofill");
}
return null;
}
final AutofillValue currentValue = mViewStates.get(mCurrentViewId).getCurrentValue();
// TODO(b/111330312): we might need to add a new state in the AutofillManager to optimize