Added a UserManager.DISALLOW_AUTOFILL restriction.

bug: 35710740

Test: cts-tradefed run commandAndExit cts-dev -m CtsAutoFillServiceTestCases -t android.autofillservice.cts.LoginActivityTest#testUserRestriction
Test: cts-tradefed run commandAndExit cts-dev -m CtsDevicePolicyManagerTestCases -t com.android.cts.devicepolicy.MixedDeviceOwnerTest#testDisallowAutofill_allowed
Test: cts-tradefed run commandAndExit cts-dev -m CtsDevicePolicyManagerTestCases -t com.android.cts.devicepolicy.MixedProfileOwnerTest#testDisallowAutofill_allowed
Test: cts-tradefed run commandAndExit cts-dev -m CtsDevicePolicyManagerTestCases -t com.android.cts.devicepolicy.MixedManagedProfileOwnerTest#testDisallowAutofill_allowed

Change-Id: I41b2bf9fe3bc8df627c6650960bd11346c430a7e
This commit is contained in:
Felipe Leme
2017-03-21 14:13:58 -07:00
parent f974766169
commit 24d5893b25
11 changed files with 119 additions and 52 deletions

View File

@@ -31661,6 +31661,7 @@ package android.os {
field public static final java.lang.String DISALLOW_ADD_USER = "no_add_user";
field public static final java.lang.String DISALLOW_ADJUST_VOLUME = "no_adjust_volume";
field public static final java.lang.String DISALLOW_APPS_CONTROL = "no_control_apps";
field public static final java.lang.String DISALLOW_AUTOFILL = "no_autofill";
field public static final java.lang.String DISALLOW_BLUETOOTH = "no_bluetooth";
field public static final java.lang.String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth";
field public static final java.lang.String DISALLOW_CONFIG_CELL_BROADCASTS = "no_config_cell_broadcasts";

View File

@@ -34475,6 +34475,7 @@ package android.os {
field public static final java.lang.String DISALLOW_ADD_USER = "no_add_user";
field public static final java.lang.String DISALLOW_ADJUST_VOLUME = "no_adjust_volume";
field public static final java.lang.String DISALLOW_APPS_CONTROL = "no_control_apps";
field public static final java.lang.String DISALLOW_AUTOFILL = "no_autofill";
field public static final java.lang.String DISALLOW_BLUETOOTH = "no_bluetooth";
field public static final java.lang.String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth";
field public static final java.lang.String DISALLOW_CONFIG_CELL_BROADCASTS = "no_config_cell_broadcasts";

View File

@@ -31786,6 +31786,7 @@ package android.os {
field public static final java.lang.String DISALLOW_ADD_USER = "no_add_user";
field public static final java.lang.String DISALLOW_ADJUST_VOLUME = "no_adjust_volume";
field public static final java.lang.String DISALLOW_APPS_CONTROL = "no_control_apps";
field public static final java.lang.String DISALLOW_AUTOFILL = "no_autofill";
field public static final java.lang.String DISALLOW_BLUETOOTH = "no_bluetooth";
field public static final java.lang.String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth";
field public static final java.lang.String DISALLOW_CONFIG_CELL_BROADCASTS = "no_config_cell_broadcasts";

View File

@@ -1584,6 +1584,7 @@ public final class Pm {
System.err.println(" pm disable-user [--user USER_ID] PACKAGE_OR_COMPONENT");
System.err.println(" pm disable-until-used [--user USER_ID] PACKAGE_OR_COMPONENT");
System.err.println(" pm default-state [--user USER_ID] PACKAGE_OR_COMPONENT");
System.err.println(" pm set-user-restriction [--user USER_ID] RESTRICTION VALUE");
System.err.println(" pm hide [--user USER_ID] PACKAGE_OR_COMPONENT");
System.err.println(" pm unhide [--user USER_ID] PACKAGE_OR_COMPONENT");
System.err.println(" pm grant [--user USER_ID] PACKAGE PERMISSION");

View File

@@ -705,6 +705,20 @@ public class UserManager {
public static final String ALLOW_PARENT_PROFILE_APP_LINKING
= "allow_parent_profile_app_linking";
/**
* Specifies if a user is not allowed to use Autofill Services.
*
* <p>Device owner and profile owner can set this restriction. When it is set by device owner,
* only the target user will be affected.
*
* <p>The default value is <code>false</code>.
*
* @see DevicePolicyManager#addUserRestriction(ComponentName, String)
* @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
* @see #getUserRestrictions()
*/
public static final String DISALLOW_AUTOFILL = "no_autofill";
/**
* Application restriction key that is used to indicate the pending arrival
* of real restrictions for the app.

View File

@@ -228,8 +228,11 @@ public abstract class AutofillService extends Service {
*/
//TODO(b/33197203): remove once clients are not using anymore
@Deprecated
public abstract void onFillRequest(@NonNull AssistStructure structure, @Nullable Bundle data,
@NonNull CancellationSignal cancellationSignal, @NonNull FillCallback callback);
public void onFillRequest(@NonNull AssistStructure structure, @Nullable Bundle data,
@NonNull CancellationSignal cancellationSignal, @NonNull FillCallback callback) {
// Should never be called because it was abstract before.
throw new UnsupportedOperationException("deprecated");
}
/**
* Called when user requests service to save the fields of an {@link Activity}.

View File

@@ -208,7 +208,7 @@ public final class Dataset implements Parcelable {
}
/**
* Sets the value of a field, usin a custom presentation to visualize it.
* Sets the value of a field, using a custom presentation to visualize it.
*
* @param id id returned by {@link
* android.app.assist.AssistStructure.ViewNode#getAutofillId()}.
@@ -257,8 +257,7 @@ public final class Dataset implements Parcelable {
throwIfDestroyed();
mDestroyed = true;
if (mFieldIds == null) {
throw new IllegalArgumentException(
"at least one value must be set");
throw new IllegalArgumentException("at least one value must be set");
}
return new Dataset(this);
}

View File

@@ -18,7 +18,10 @@ package com.android.server.autofill;
import static android.Manifest.permission.MANAGE_AUTO_FILL;
import static android.content.Context.AUTOFILL_MANAGER_SERVICE;
import static com.android.server.autofill.Helper.DEBUG;
import static com.android.server.autofill.Helper.VERBOSE;
import static com.android.server.autofill.Helper.bundleToString;
import android.Manifest;
import android.annotation.NonNull;
@@ -28,8 +31,8 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.graphics.Rect;
import android.net.Uri;
@@ -41,16 +44,19 @@ import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManagerInternal;
import android.provider.Settings;
import android.util.LocalLog;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillValue;
import android.view.autofill.IAutoFillManager;
import android.view.autofill.IAutoFillManagerClient;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.BackgroundThread;
import com.android.internal.os.IResultReceiver;
@@ -90,20 +96,20 @@ public final class AutofillManagerService extends SystemService {
* It has to be mapped by user id because the same current user could have simultaneous sessions
* associated to different user profiles (for example, in a multi-window environment or when
* device has work profiles).
* <p>
* Entries on this cache are added on demand and removed when:
* <ol>
* <li>An autofill service app is removed.
* <li>The {@link android.provider.Settings.Secure#AUTOFILL_SERVICE} for an user change.
* </ol>
*/
// TODO(b/33197203): Update the above comment
@GuardedBy("mLock")
private SparseArray<AutofillManagerServiceImpl> mServicesCache = new SparseArray<>();
/**
* Users disabled due to {@link UserManager} restrictions.
*/
@GuardedBy("mLock")
private final SparseBooleanArray mDisabledUsers = new SparseBooleanArray();
// TODO(b/33197203): set a different max (or disable it) on low-memory devices.
private final LocalLog mRequestsHistory = new LocalLog(20);
// TODO(b/33197203): is this still needed?
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -122,10 +128,38 @@ public final class AutofillManagerService extends SystemService {
mContext = context;
mUi = new AutoFillUI(mContext);
IntentFilter filter = new IntentFilter();
final IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
mContext.registerReceiver(mBroadcastReceiver, filter, null,
FgThread.getHandler());
mContext.registerReceiver(mBroadcastReceiver, filter, null, FgThread.getHandler());
// Hookup with UserManager to disable service when necessary.
final UserManager um = context.getSystemService(UserManager.class);
final UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class);
final List<UserInfo> users = um.getUsers();
for (int i = 0; i < users.size(); i++) {
final int userId = users.get(i).id;
final boolean disabled = umi.getUserRestriction(userId, UserManager.DISALLOW_AUTOFILL);
if (disabled) {
mDisabledUsers.put(userId, disabled);
}
}
umi.addUserRestrictionsListener((userId, newRestrictions, prevRestrictions) -> {
final boolean disabledNow =
newRestrictions.getBoolean(UserManager.DISALLOW_AUTOFILL, false);
synchronized (mLock) {
final boolean disabledBefore = mDisabledUsers.get(userId);
if (disabledBefore == disabledNow) {
// Nothing changed, do nothing.
if (DEBUG) {
Slog.d(TAG, "Restriction not changed for user " + userId + ": "
+ bundleToString(newRestrictions));
return;
}
}
mDisabledUsers.put(userId, disabledNow);
updateCachedServiceLocked(userId, disabledNow);
}
});
}
@Override
@@ -164,7 +198,7 @@ public final class AutofillManagerService extends SystemService {
AutofillManagerServiceImpl service = mServicesCache.get(userId);
if (service == null) {
service = new AutofillManagerServiceImpl(mContext, mLock,
mRequestsHistory, userId, mUi);
mRequestsHistory, userId, mUi, mDisabledUsers.get(userId));
mServicesCache.put(userId, service);
}
return service;
@@ -272,9 +306,16 @@ public final class AutofillManagerService extends SystemService {
* Updates a cached service for a given user.
*/
private void updateCachedServiceLocked(int userId) {
updateCachedServiceLocked(userId, mDisabledUsers.get(userId));
}
/**
* Updates a cached service for a given user.
*/
private void updateCachedServiceLocked(int userId, boolean disabled) {
AutofillManagerServiceImpl service = mServicesCache.get(userId);
if (service != null) {
service.updateLocked();
service.updateLocked(disabled);
}
}
@@ -386,6 +427,7 @@ public final class AutofillManagerService extends SystemService {
return;
}
synchronized (mLock) {
pw.print("Disabled users: "); pw.println(mDisabledUsers);
final int size = mServicesCache.size();
pw.print("Cached services: ");
if (size == 0) {

View File

@@ -53,6 +53,7 @@ import android.os.Looper;
import android.os.Parcelable;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.UserManager;
import android.provider.Settings;
import android.service.autofill.AutofillService;
import android.service.autofill.AutofillServiceInfo;
@@ -105,6 +106,10 @@ final class AutofillManagerServiceImpl {
private AutofillServiceInfo mInfo;
private final LocalLog mRequestsHistory;
/**
* Whether service was disabled for user due to {@link UserManager} restrictions.
*/
private boolean mDisabled;
private final HandlerCaller.Callback mHandlerCallback = (msg) -> {
switch (msg.what) {
@@ -183,13 +188,13 @@ final class AutofillManagerServiceImpl {
};
AutofillManagerServiceImpl(Context context, Object lock, LocalLog requestsHistory,
int userId, AutoFillUI ui) {
int userId, AutoFillUI ui, boolean disabled) {
mContext = context;
mLock = lock;
mRequestsHistory = requestsHistory;
mUserId = userId;
mUi = ui;
updateLocked();
updateLocked(disabled);
}
CharSequence getServiceName() {
@@ -209,7 +214,9 @@ final class AutofillManagerServiceImpl {
}
}
void updateLocked() {
void updateLocked(boolean disabled) {
final boolean wasEnabled = isEnabled();
mDisabled = disabled;
ComponentName serviceComponent = null;
ServiceInfo serviceInfo = null;
final String componentName = Settings.Secure.getStringForUser(
@@ -225,15 +232,14 @@ final class AutofillManagerServiceImpl {
}
}
try {
final boolean hadService = hasService();
if (serviceInfo != null) {
mInfo = new AutofillServiceInfo(mContext.getPackageManager(),
serviceComponent, mUserId);
} else {
mInfo = null;
}
if (hadService != hasService()) {
if (!hasService()) {
if (wasEnabled != isEnabled()) {
if (!isEnabled()) {
final int sessionCount = mSessions.size();
for (int i = sessionCount - 1; i >= 0; i--) {
final Session session = mSessions.valueAt(i);
@@ -251,7 +257,7 @@ final class AutofillManagerServiceImpl {
* Used by {@link AutofillManagerServiceShellCommand} to request save for the current top app.
*/
void requestSaveForUserLocked(IBinder activityToken) {
if (!hasService()) {
if (!isEnabled()) {
return;
}
final Session session = mSessions.get(activityToken);
@@ -268,11 +274,11 @@ final class AutofillManagerServiceImpl {
mClients = new RemoteCallbackList<>();
}
mClients.register(client);
return hasService();
return isEnabled();
}
void setAuthenticationResultLocked(Bundle data, IBinder activityToken) {
if (!hasService()) {
if (!isEnabled()) {
return;
}
final Session session = mSessions.get(activityToken);
@@ -282,7 +288,7 @@ final class AutofillManagerServiceImpl {
}
void setHasCallback(IBinder activityToken, boolean hasIt) {
if (!hasService()) {
if (!isEnabled()) {
return;
}
final Session session = mSessions.get(activityToken);
@@ -295,7 +301,7 @@ final class AutofillManagerServiceImpl {
@NonNull IBinder appCallbackToken, @NonNull AutofillId autofillId, @NonNull Rect bounds,
@Nullable AutofillValue value, boolean hasCallback, int flags,
@NonNull String packageName) {
if (!hasService()) {
if (!isEnabled()) {
return;
}
@@ -318,7 +324,7 @@ final class AutofillManagerServiceImpl {
}
void finishSessionLocked(IBinder activityToken) {
if (!hasService()) {
if (!isEnabled()) {
return;
}
@@ -338,7 +344,7 @@ final class AutofillManagerServiceImpl {
}
void cancelSessionLocked(IBinder activityToken) {
if (!hasService()) {
if (!isEnabled()) {
return;
}
@@ -423,8 +429,9 @@ final class AutofillManagerServiceImpl {
pw.print(prefix); pw.print("Component:"); pw.println(mInfo != null
? mInfo.getServiceInfo().getComponentName() : null);
pw.print(prefix); pw.print("Disabled:"); pw.println(mDisabled);
if (VERBOSE) {
if (VERBOSE && mInfo != null) {
// ServiceInfo dump is too noisy and redundant (it can be obtained through other dumps)
pw.print(prefix); pw.println("ServiceInfo:");
mInfo.getServiceInfo().dump(new PrintWriterPrinter(pw), prefix + prefix);
@@ -467,9 +474,9 @@ final class AutofillManagerServiceImpl {
}
try {
for (int i = 0; i < userClientCount; i++) {
IAutoFillManagerClient client = clients.getBroadcastItem(i);
final IAutoFillManagerClient client = clients.getBroadcastItem(i);
try {
client.setState(hasService());
client.setState(isEnabled());
} catch (RemoteException re) {
/* ignore */
}
@@ -479,8 +486,8 @@ final class AutofillManagerServiceImpl {
}
}
private boolean hasService() {
return mInfo != null;
private boolean isEnabled() {
return mInfo != null && !mDisabled;
}
@Override

View File

@@ -31,24 +31,21 @@ final class Helper {
static final boolean DEBUG = true; // TODO(b/33197203): set to false when stable
static final boolean VERBOSE = false;
static final String REDACTED = "[REDACTED]";
static void append(StringBuilder builder, Bundle bundle) {
if (bundle == null) {
builder.append("N/A");
} else if (!VERBOSE) {
builder.append(REDACTED);
} else {
final Set<String> keySet = bundle.keySet();
builder.append("[Bundle with ").append(keySet.size()).append(" extras:");
for (String key : keySet) {
final Object value = bundle.get(key);
builder.append(' ').append(key).append('=');
builder.append((value instanceof Object[])
? Arrays.toString((Objects[]) value) : value);
}
builder.append(']');
if (bundle == null || !DEBUG) {
builder.append("null");
return;
}
final Set<String> keySet = bundle.keySet();
builder.append("[Bundle with ").append(keySet.size()).append(" extras:");
for (String key : keySet) {
final Object value = bundle.get(key);
builder.append(' ').append(key).append('=');
builder.append((value instanceof Object[])
? Arrays.toString((Objects[]) value) : value);
}
builder.append(']');
}
static String bundleToString(Bundle bundle) {

View File

@@ -109,6 +109,7 @@ public class UserRestrictionsUtils {
UserManager.DISALLOW_SET_WALLPAPER,
UserManager.DISALLOW_OEM_UNLOCK,
UserManager.DISALLOW_UNMUTE_DEVICE,
UserManager.DISALLOW_AUTOFILL,
});
/**