Refactored Autofill properties that are optimized on application level.

Prior to this CL we were just caching whether the service supported compatibility mode for the app,
but now we're also caching the logging level and whether the app is whitelisted for augmented
autofill - although right now the augmented autofill info is not used, it will allow us to trigger
it in the scenarios where autofill is disabled for the app.

Bug: 123099842
Bug: 123100824
Test: atest CtsAutoFillServiceTestCases:AugmentedLoginActivityTest \
            CtsAutoFillServiceTestCases:VirtualContainerActivityCompatModeTest
      atest CtsAutoFillServiceTestCases # sanity check, although still flaky

Change-Id: Iaf8ea6634ca94e5e61131890ec17c96c2fbb329a
This commit is contained in:
Felipe Leme
2019-02-19 15:08:59 -08:00
parent a48e54edd8
commit a4f39cd150
15 changed files with 250 additions and 41 deletions

View File

@@ -483,6 +483,17 @@ package android.bluetooth {
package android.content {
public final class AutofillOptions implements android.os.Parcelable {
ctor public AutofillOptions(int, boolean);
method public int describeContents();
method public static android.content.AutofillOptions forWhitelistingItself();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.content.AutofillOptions> CREATOR;
field public boolean augmentedEnabled;
field public final boolean compatModeEnabled;
field public final int loggingLevel;
}
public final class ContentCaptureOptions implements android.os.Parcelable {
ctor public ContentCaptureOptions(int, int, int, int, int, @Nullable android.util.ArraySet<android.content.ComponentName>);
method public int describeContents();
@@ -509,7 +520,7 @@ package android.content {
method public android.content.Context createPackageContextAsUser(String, int, android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.os.UserHandle getUser();
method public int getUserId();
method public void setAutofillCompatibilityEnabled(boolean);
method public void setAutofillOptions(@Nullable android.content.AutofillOptions);
method public void setContentCaptureOptions(@Nullable android.content.ContentCaptureOptions);
}

View File

@@ -7608,7 +7608,7 @@ public class Activity extends ContextThemeWrapper
mWindow.setColorMode(info.colorMode);
setAutofillCompatibilityEnabled(application.isAutofillCompatibilityEnabled());
setAutofillOptions(application.getAutofillOptions());
setContentCaptureOptions(application.getContentCaptureOptions());
}

View File

@@ -43,6 +43,7 @@ import android.app.servertransaction.PendingTransactionActions;
import android.app.servertransaction.PendingTransactionActions.StopInfo;
import android.app.servertransaction.TransactionExecutor;
import android.app.servertransaction.TransactionExecutorHelper;
import android.content.AutofillOptions;
import android.content.BroadcastReceiver;
import android.content.ComponentCallbacks2;
import android.content.ComponentName;
@@ -745,7 +746,7 @@ public final class ActivityThread extends ClientTransactionHandler {
/** Initial values for {@link Profiler}. */
ProfilerInfo initProfilerInfo;
boolean autofillCompatibilityEnabled;
AutofillOptions autofillOptions;
/**
* Content capture options for the application - when null, it means ContentCapture is not
@@ -975,9 +976,8 @@ public final class ActivityThread extends ClientTransactionHandler {
boolean enableBinderTracking, boolean trackAllocation,
boolean isRestrictedBackupMode, boolean persistent, Configuration config,
CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
String buildSerial, boolean autofillCompatibilityEnabled,
String buildSerial, AutofillOptions autofillOptions,
ContentCaptureOptions contentCaptureOptions) {
if (services != null) {
if (false) {
// Test code to make sure the app could see the passed-in services.
@@ -1023,7 +1023,7 @@ public final class ActivityThread extends ClientTransactionHandler {
data.compatInfo = compatInfo;
data.initProfilerInfo = profilerInfo;
data.buildSerial = buildSerial;
data.autofillCompatibilityEnabled = autofillCompatibilityEnabled;
data.autofillOptions = autofillOptions;
data.contentCaptureOptions = contentCaptureOptions;
sendMessage(H.BIND_APPLICATION, data);
}
@@ -6164,7 +6164,7 @@ public final class ActivityThread extends ClientTransactionHandler {
app = data.info.makeApplication(data.restrictedBackupMode, null);
// Propagate autofill compat state
app.setAutofillCompatibilityEnabled(data.autofillCompatibilityEnabled);
app.setAutofillOptions(data.autofillOptions);
// Propagate Content Capture options
app.setContentCaptureOptions(data.contentCaptureOptions);

View File

@@ -19,8 +19,8 @@ package android.app;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
import android.content.AutofillOptions;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentCaptureOptions;
@@ -215,8 +215,8 @@ class ContextImpl extends Context {
// The name of the split this Context is representing. May be null.
private @Nullable String mSplitName = null;
private AutofillClient mAutofillClient = null;
private boolean mIsAutofillCompatEnabled;
private @Nullable AutofillClient mAutofillClient = null;
private @Nullable AutofillOptions mAutofillOptions;
private ContentCaptureOptions mContentCaptureOptions = null;
@@ -2376,15 +2376,14 @@ class ContextImpl extends Context {
/** @hide */
@Override
public boolean isAutofillCompatibilityEnabled() {
return mIsAutofillCompatEnabled;
public AutofillOptions getAutofillOptions() {
return mAutofillOptions;
}
/** @hide */
@TestApi
@Override
public void setAutofillCompatibilityEnabled(boolean autofillCompatEnabled) {
mIsAutofillCompatEnabled = autofillCompatEnabled;
public void setAutofillOptions(AutofillOptions options) {
mAutofillOptions = options;
}
/** @hide */

View File

@@ -21,6 +21,7 @@ import android.app.IUiAutomationConnection;
import android.app.ProfilerInfo;
import android.app.ResultInfo;
import android.app.servertransaction.ClientTransaction;
import android.content.AutofillOptions;
import android.content.ComponentName;
import android.content.ContentCaptureOptions;
import android.content.IIntentReceiver;
@@ -69,7 +70,7 @@ oneway interface IApplicationThread {
int debugMode, boolean enableBinderTracking, boolean trackAllocation,
boolean restrictedBackupMode, boolean persistent, in Configuration config,
in CompatibilityInfo compatInfo, in Map services,
in Bundle coreSettings, in String buildSerial, boolean isAutofillCompatEnabled,
in Bundle coreSettings, in String buildSerial, in AutofillOptions autofillOptions,
in ContentCaptureOptions contentCaptureOptions);
void runIsolatedEntryPoint(in String entryPoint, in String[] entryPointArgs);
void scheduleExit();

View File

@@ -0,0 +1,19 @@
/*
** Copyright 2019, 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 android.content;
parcelable AutofillOptions;

View File

@@ -0,0 +1,130 @@
/*
* 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 android.content;
import android.annotation.NonNull;
import android.annotation.TestApi;
import android.app.ActivityThread;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
import android.view.autofill.AutofillManager;
import java.io.PrintWriter;
/**
* Autofill options for a given package.
*
* <p>This object is created by the Autofill System Service and passed back to the app when the
* application is created.
*
* @hide
*/
@TestApi
public final class AutofillOptions implements Parcelable {
private static final String TAG = AutofillOptions.class.getSimpleName();
/**
* Logging level for {@code logcat} statements.
*/
public final int loggingLevel;
/**
* Whether compatibility mode is enabled for the package.
*/
public final boolean compatModeEnabled;
/**
* Whether package is whitelisted for augmented autofill.
*/
public boolean augmentedEnabled;
// TODO(b/123100824): add (optional) list of activities
public AutofillOptions(int loggingLevel, boolean compatModeEnabled) {
this.loggingLevel = loggingLevel;
this.compatModeEnabled = compatModeEnabled;
}
/**
* @hide
*/
@TestApi
public static AutofillOptions forWhitelistingItself() {
final ActivityThread at = ActivityThread.currentActivityThread();
if (at == null) {
throw new IllegalStateException("No ActivityThread");
}
final String packageName = at.getApplication().getPackageName();
if (!"android.autofillservice.cts".equals(packageName)) {
Log.e(TAG, "forWhitelistingItself(): called by " + packageName);
throw new SecurityException("Thou shall not pass!");
}
final AutofillOptions options = new AutofillOptions(
AutofillManager.FLAG_ADD_CLIENT_VERBOSE, /* compatModeAllowed= */ true);
options.augmentedEnabled = true;
// Always log, as it's used by test only
Log.i(TAG, "forWhitelistingItself(" + packageName + "): " + options);
return options;
}
@Override
public String toString() {
return "AutofillOptions [loggingLevel=" + loggingLevel + ", compatMode="
+ compatModeEnabled + ", augmentedEnabled=" + augmentedEnabled + "]";
}
/** @hide */
public void dumpShort(@NonNull PrintWriter pw) {
pw.print("logLvl="); pw.print(loggingLevel);
pw.print(", compatMode="); pw.print(compatModeEnabled);
pw.print(", augmented="); pw.print(augmentedEnabled);
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(loggingLevel);
parcel.writeBoolean(compatModeEnabled);
parcel.writeBoolean(augmentedEnabled);
}
public static final Parcelable.Creator<AutofillOptions> CREATOR =
new Parcelable.Creator<AutofillOptions>() {
@Override
public AutofillOptions createFromParcel(Parcel parcel) {
final int loggingLevel = parcel.readInt();
final boolean compatMode = parcel.readBoolean();
final AutofillOptions options = new AutofillOptions(loggingLevel, compatMode);
options.augmentedEnabled = parcel.readBoolean();
return options;
}
@Override
public AutofillOptions[] newArray(int size) {
return new AutofillOptions[size];
}
};
}

View File

@@ -5340,16 +5340,24 @@ public abstract class Context {
/**
* @hide
*/
public boolean isAutofillCompatibilityEnabled() {
return false;
public final boolean isAutofillCompatibilityEnabled() {
final AutofillOptions options = getAutofillOptions();
return options != null && options.compatModeEnabled;
}
/**
* @hide
*/
@Nullable
public AutofillOptions getAutofillOptions() {
return null;
}
/**
* @hide
*/
@TestApi
public void setAutofillCompatibilityEnabled(
@SuppressWarnings("unused") boolean autofillCompatEnabled) {
public void setAutofillOptions(@SuppressWarnings("unused") @Nullable AutofillOptions options) {
}
/**

View File

@@ -1031,22 +1031,17 @@ public class ContextWrapper extends Context {
mBase.setAutofillClient(client);
}
/**
* @hide
*/
/** @hide */
@Override
public boolean isAutofillCompatibilityEnabled() {
return mBase != null && mBase.isAutofillCompatibilityEnabled();
public AutofillOptions getAutofillOptions() {
return mBase == null ? null : mBase.getAutofillOptions();
}
/**
* @hide
*/
@TestApi
/** @hide */
@Override
public void setAutofillCompatibilityEnabled(boolean autofillCompatEnabled) {
public void setAutofillOptions(AutofillOptions options) {
if (mBase != null) {
mBase.setAutofillCompatibilityEnabled(autofillCompatEnabled);
mBase.setAutofillOptions(options);
}
}

View File

@@ -28,6 +28,7 @@ import android.annotation.RequiresFeature;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.content.AutofillOptions;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -482,6 +483,9 @@ public final class AutofillManager {
@GuardedBy("mLock")
private CompatibilityBridge mCompatibilityBridge;
@Nullable
private final AutofillOptions mOptions;
/** @hide */
public interface AutofillClient {
/**
@@ -618,6 +622,12 @@ public final class AutofillManager {
public AutofillManager(Context context, IAutoFillManager service) {
mContext = Preconditions.checkNotNull(context, "context cannot be null");
mService = service;
mOptions = context.getAutofillOptions();
if (mOptions != null) {
sDebug = (mOptions.loggingLevel & FLAG_ADD_CLIENT_DEBUG) != 0;
sVerbose = (mOptions.loggingLevel & FLAG_ADD_CLIENT_VERBOSE) != 0;
}
}
/**
@@ -2352,6 +2362,9 @@ public final class AutofillManager {
pw.print(pfx); pw.print("entered ids: "); pw.println(mEnteredIds);
pw.print(pfx); pw.print("save trigger id: "); pw.println(mSaveTriggerId);
pw.print(pfx); pw.print("save on finish(): "); pw.println(mSaveOnFinish);
if (mOptions != null) {
pw.print(pfx); pw.print("options: "); mOptions.dumpShort(pw); pw.println();
}
pw.print(pfx); pw.print("compat mode enabled: ");
synchronized (mLock) {
if (mCompatibilityBridge != null) {

View File

@@ -16,7 +16,9 @@
package android.view.autofill;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.AutofillOptions;
/**
* Autofill Manager local system service interface.
@@ -31,12 +33,13 @@ public abstract class AutofillManagerInternal {
public abstract void onBackKeyPressed();
/**
* Gets whether compatibility mode is enabled for a package
* Gets autofill options for a package
*
* @param packageName The package for which to query.
* @param versionCode The package version code.
* @param userId The user id for which to query.
*/
public abstract boolean isCompatibilityModeRequested(@NonNull String packageName,
@Nullable
public abstract AutofillOptions getAutofillOptions(@NonNull String packageName,
long versionCode, @UserIdInt int userId);
}

View File

@@ -28,6 +28,7 @@ import android.app.IApplicationThread;
import android.app.IInstrumentationWatcher;
import android.app.IUiAutomationConnection;
import android.app.ProfilerInfo;
import android.content.AutofillOptions;
import android.content.ComponentName;
import android.content.ContentCaptureOptions;
import android.content.IIntentReceiver;
@@ -407,7 +408,7 @@ public class TransactionParcelTests {
IUiAutomationConnection iUiAutomationConnection, int i, boolean b, boolean b1,
boolean b2, boolean b3, Configuration configuration,
CompatibilityInfo compatibilityInfo, Map map, Bundle bundle1, String s1,
boolean autofillCompatEnabled, ContentCaptureOptions o) throws RemoteException {
AutofillOptions ao, ContentCaptureOptions co) throws RemoteException {
}
@Override

View File

@@ -30,6 +30,7 @@ import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.ActivityManagerInternal;
import android.app.ActivityThread;
import android.content.AutofillOptions;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -699,12 +700,31 @@ public final class AutofillManagerService
}
@Override
public boolean isCompatibilityModeRequested(@NonNull String packageName,
public AutofillOptions getAutofillOptions(@NonNull String packageName,
long versionCode, @UserIdInt int userId) {
return mAutofillCompatState.isCompatibilityModeRequested(
final int loggingLevel;
if (verbose) {
loggingLevel = AutofillManager.FLAG_ADD_CLIENT_VERBOSE
| AutofillManager.FLAG_ADD_CLIENT_DEBUG;
} else if (debug) {
loggingLevel = AutofillManager.FLAG_ADD_CLIENT_DEBUG;
} else {
loggingLevel = AutofillManager.NO_LOGGING;
}
final boolean compatModeEnabled = mAutofillCompatState.isCompatibilityModeRequested(
packageName, versionCode, userId);
}
final AutofillOptions options = new AutofillOptions(loggingLevel, compatModeEnabled);
synchronized (mLock) {
final AutofillManagerServiceImpl service =
getServiceForUserLocked(UserHandle.getCallingUserId());
if (service != null) {
service.setAugmentedAutofillWhitelistLocked(options, packageName);
}
}
return options;
}
}
/**

View File

@@ -28,6 +28,7 @@ import android.annotation.Nullable;
import android.app.ActivityManagerInternal;
import android.app.ActivityTaskManager;
import android.app.IActivityTaskManager;
import android.content.AutofillOptions;
import android.content.ComponentName;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -1169,6 +1170,13 @@ final class AutofillManagerServiceImpl
return mWhitelistedAugmentAutofillPackages.contains(packageName);
}
@GuardedBy("mLock")
void setAugmentedAutofillWhitelistLocked(@NonNull AutofillOptions options,
@NonNull String packageName) {
// TODO(b/122595322): need to setwhitelisted activities as well.
options.augmentedEnabled = mWhitelistedAugmentAutofillPackages.contains(packageName);
}
private void whitelistForAugmentedAutofillPackages(@NonNull List<String> packages) {
// TODO(b/123100824): add CTS test for when it's null
synchronized (mLock) {

View File

@@ -187,6 +187,7 @@ import android.app.backup.IBackupManager;
import android.app.usage.UsageEvents;
import android.app.usage.UsageStatsManagerInternal;
import android.appwidget.AppWidgetManager;
import android.content.AutofillOptions;
import android.content.BroadcastReceiver;
import android.content.ComponentCallbacks2;
import android.content.ComponentName;
@@ -4741,12 +4742,12 @@ public class ActivityManagerService extends IActivityManager.Stub
// Figure out whether the app needs to run in autofill compat mode.
boolean isAutofillCompatEnabled = false;
AutofillOptions autofillOptions = null;
if (UserHandle.getAppId(app.info.uid) >= Process.FIRST_APPLICATION_UID) {
final AutofillManagerInternal afm = LocalServices.getService(
AutofillManagerInternal.class);
if (afm != null) {
isAutofillCompatEnabled = afm.isCompatibilityModeRequested(
autofillOptions = afm.getAutofillOptions(
app.info.packageName, app.info.versionCode, app.userId);
}
}
@@ -4779,7 +4780,7 @@ public class ActivityManagerService extends IActivityManager.Stub
new Configuration(app.getWindowProcessController().getConfiguration()),
app.compat, getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, isAutofillCompatEnabled, contentCaptureOptions);
buildSerial, autofillOptions, contentCaptureOptions);
} else {
thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
null, null, null, testMode,
@@ -4788,7 +4789,7 @@ public class ActivityManagerService extends IActivityManager.Stub
new Configuration(app.getWindowProcessController().getConfiguration()),
app.compat, getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, isAutofillCompatEnabled, contentCaptureOptions);
buildSerial, autofillOptions, contentCaptureOptions);
}
if (profilerInfo != null) {
profilerInfo.closeFd();