Merge changes from topic "aa_whitelist"

* changes:
  Check for empty arguments in setWhitelist().
  Implemented a WhitelistHelper for whitelisting packages/activities for Augmented Autofill and Content Capture.
This commit is contained in:
Adam He
2019-03-06 18:31:59 +00:00
committed by Android (Google) Code Review
11 changed files with 420 additions and 66 deletions

View File

@@ -563,11 +563,13 @@ package android.content {
ctor public AutofillOptions(int, boolean);
method public int describeContents();
method public static android.content.AutofillOptions forWhitelistingItself();
method public boolean isAugmentedAutofillEnabled(@NonNull android.content.Context);
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.content.AutofillOptions> CREATOR;
field public boolean augmentedEnabled;
field public boolean augmentedAutofillEnabled;
field public final boolean compatModeEnabled;
field public final int loggingLevel;
field @Nullable public android.util.ArraySet<android.content.ComponentName> whitelistedActivitiesForAugmentedAutofill;
}
public final class ContentCaptureOptions implements android.os.Parcelable {

View File

@@ -127,6 +127,7 @@ import android.view.autofill.AutofillPopupWindow;
import android.view.autofill.IAutofillWindowPresenter;
import android.view.contentcapture.ContentCaptureContext;
import android.view.contentcapture.ContentCaptureManager;
import android.view.contentcapture.ContentCaptureManager.ContentCaptureClient;
import android.widget.AdapterView;
import android.widget.Toast;
import android.widget.Toolbar;
@@ -717,7 +718,7 @@ public class Activity extends ContextThemeWrapper
Window.Callback, KeyEvent.Callback,
OnCreateContextMenuListener, ComponentCallbacks2,
Window.OnWindowDismissedCallback, WindowControllerCallback,
AutofillManager.AutofillClient {
AutofillManager.AutofillClient, ContentCaptureManager.ContentCaptureClient {
private static final String TAG = "Activity";
private static final boolean DEBUG_LIFECYCLE = false;
@@ -1119,6 +1120,12 @@ public class Activity extends ContextThemeWrapper
return this;
}
/** @hide */
@Override
public final ContentCaptureClient getContentCaptureClient() {
return this;
}
/**
* Register an {@link Application.ActivityLifecycleCallbacks} instance that receives
* lifecycle callbacks for only this Activity.
@@ -6464,6 +6471,12 @@ public class Activity extends ContextThemeWrapper
return getComponentName();
}
/** @hide */
@Override
public final ComponentName contentCaptureClientGetComponentName() {
return getComponentName();
}
/**
* Retrieve a {@link SharedPreferences} object for accessing preferences
* that are private to this activity. This simply calls the underlying

View File

@@ -16,12 +16,15 @@
package android.content;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
import android.app.ActivityThread;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.ArraySet;
import android.util.Log;
import android.view.autofill.AutofillManager;
import android.view.contentcapture.ContentCaptureManager.ContentCaptureClient;
import java.io.PrintWriter;
@@ -51,14 +54,33 @@ public final class AutofillOptions implements Parcelable {
/**
* Whether package is whitelisted for augmented autofill.
*/
public boolean augmentedEnabled;
// TODO(b/123100824): add (optional) list of activities
public boolean augmentedAutofillEnabled;
/**
* List of whitelisted activities.
*/
@Nullable
public ArraySet<ComponentName> whitelistedActivitiesForAugmentedAutofill;
public AutofillOptions(int loggingLevel, boolean compatModeEnabled) {
this.loggingLevel = loggingLevel;
this.compatModeEnabled = compatModeEnabled;
}
/**
* Returns whether activity is whitelisted for augmented autofill.
*/
public boolean isAugmentedAutofillEnabled(@NonNull Context context) {
if (!augmentedAutofillEnabled) return false;
final ContentCaptureClient contentCaptureClient = context.getContentCaptureClient();
if (contentCaptureClient == null) return false;
final ComponentName component = contentCaptureClient.contentCaptureClientGetComponentName();
return whitelistedActivitiesForAugmentedAutofill == null
|| whitelistedActivitiesForAugmentedAutofill.contains(component);
}
/**
* @hide
*/
@@ -78,7 +100,7 @@ public final class AutofillOptions implements Parcelable {
final AutofillOptions options = new AutofillOptions(
AutofillManager.FLAG_ADD_CLIENT_VERBOSE, /* compatModeAllowed= */ true);
options.augmentedEnabled = true;
options.augmentedAutofillEnabled = true;
// Always log, as it's used by test only
Log.i(TAG, "forWhitelistingItself(" + packageName + "): " + options);
@@ -87,15 +109,19 @@ public final class AutofillOptions implements Parcelable {
@Override
public String toString() {
return "AutofillOptions [loggingLevel=" + loggingLevel + ", compatMode="
+ compatModeEnabled + ", augmentedEnabled=" + augmentedEnabled + "]";
return "AutofillOptions [loggingLevel=" + loggingLevel + ", compatMode=" + compatModeEnabled
+ ", augmentedAutofillEnabled=" + augmentedAutofillEnabled + "]";
}
/** @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);
pw.print(", augmented="); pw.print(augmentedAutofillEnabled);
if (whitelistedActivitiesForAugmentedAutofill != null) {
pw.print(", whitelistedActivitiesForAugmentedAutofill=");
pw.print(whitelistedActivitiesForAugmentedAutofill);
}
}
@Override
@@ -107,7 +133,8 @@ public final class AutofillOptions implements Parcelable {
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(loggingLevel);
parcel.writeBoolean(compatModeEnabled);
parcel.writeBoolean(augmentedEnabled);
parcel.writeBoolean(augmentedAutofillEnabled);
parcel.writeArraySet(whitelistedActivitiesForAugmentedAutofill);
}
public static final @android.annotation.NonNull Parcelable.Creator<AutofillOptions> CREATOR =
@@ -118,7 +145,9 @@ public final class AutofillOptions implements Parcelable {
final int loggingLevel = parcel.readInt();
final boolean compatMode = parcel.readBoolean();
final AutofillOptions options = new AutofillOptions(loggingLevel, compatMode);
options.augmentedEnabled = parcel.readBoolean();
options.augmentedAutofillEnabled = parcel.readBoolean();
options.whitelistedActivitiesForAugmentedAutofill =
(ArraySet<ComponentName>) parcel.readArraySet(null);
return options;
}

View File

@@ -69,6 +69,7 @@ import android.view.View;
import android.view.ViewDebug;
import android.view.WindowManager;
import android.view.autofill.AutofillManager.AutofillClient;
import android.view.contentcapture.ContentCaptureManager.ContentCaptureClient;
import android.view.textclassifier.TextClassificationManager;
import java.io.File;
@@ -5340,6 +5341,14 @@ public abstract class Context {
public void setAutofillClient(@SuppressWarnings("unused") AutofillClient client) {
}
/**
* @hide
*/
@Nullable
public ContentCaptureClient getContentCaptureClient() {
return null;
}
/**
* @hide
*/

View File

@@ -9530,8 +9530,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
// View is not important for "regular" autofill, so we must check if Augmented Autofill
// is enabled for the activity
final AutofillOptions options = mContext.getAutofillOptions();
if (options == null || !options.augmentedEnabled) {
// TODO(b/123100824): should also check if activity is whitelisted
if (options == null || !options.isAugmentedAutofillEnabled(mContext)) {
return false;
}
final AutofillManager afm = getAutofillManager();

View File

@@ -192,6 +192,15 @@ public final class ContentCaptureManager {
@GuardedBy("mLock")
private MainContentCaptureSession mMainSession;
/** @hide */
public interface ContentCaptureClient {
/**
* Gets the component name of the client.
*/
@NonNull
ComponentName contentCaptureClientGetComponentName();
}
/** @hide */
public ContentCaptureManager(@NonNull Context context,
@NonNull IContentCaptureManager service, @NonNull ContentCaptureOptions options) {

View File

@@ -121,11 +121,11 @@ public abstract class ContentCaptureSession implements AutoCloseable {
public static final int STATE_INTERNAL_ERROR = 0x100;
/**
* Session is disabled because service didn't whitelist package.
* Session is disabled because service didn't whitelist package or activity.
*
* @hide
*/
public static final int STATE_PACKAGE_NOT_WHITELISTED = 0x200;
public static final int STATE_NOT_WHITELISTED = 0x200;
private static final int INITIAL_CHILDREN_CAPACITY = 5;

View File

@@ -0,0 +1,163 @@
/*
* Copyright (C) 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 com.android.internal.infra;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
import com.android.internal.util.Preconditions;
import java.io.PrintWriter;
/**
* Helper class for keeping track of whitelisted packages/activities.
*
* @hide
*/
public final class WhitelistHelper {
private static final String TAG = "WhitelistHelper";
/**
* Map of whitelisted packages/activities. The whole package is whitelisted if its
* corresponding value is {@code null}.
*/
@Nullable
private ArrayMap<String, ArraySet<ComponentName>> mWhitelistedPackages;
/**
* Sets the whitelist with the given packages and activities. The list is cleared if both
* packageNames and components are {@code null}.
*
* @param packageNames packages to be whitelisted.
* @param components activities to be whitelisted.
*
* @throws IllegalArgumentException if packages or components are empty.
*/
public void setWhitelist(@Nullable ArraySet<String> packageNames,
@Nullable ArraySet<ComponentName> components) {
mWhitelistedPackages = null;
if (packageNames == null && components == null) return;
if ((packageNames != null && packageNames.isEmpty())
|| (components != null && components.isEmpty())) {
throw new IllegalArgumentException("Packages or Components cannot be empty.");
}
mWhitelistedPackages = new ArrayMap<>();
if (packageNames != null) {
for (int i = 0; i < packageNames.size(); i++) {
mWhitelistedPackages.put(packageNames.valueAt(i), null);
}
}
if (components != null) {
for (int i = 0; i < components.size(); i++) {
final ComponentName component = components.valueAt(i);
if (component == null) {
Log.w(TAG, "setWhitelist(): component is null");
continue;
}
final String packageName = component.getPackageName();
ArraySet<ComponentName> set = mWhitelistedPackages.get(packageName);
if (set == null) {
set = new ArraySet<>();
mWhitelistedPackages.put(packageName, set);
}
set.add(component);
}
}
}
/**
* Returns {@code true} if the entire package is whitelisted.
*/
public boolean isWhitelisted(@NonNull String packageName) {
Preconditions.checkNotNull(packageName);
if (mWhitelistedPackages == null) return false;
return mWhitelistedPackages.containsKey(packageName)
&& mWhitelistedPackages.get(packageName) == null;
}
/**
* Returns {@code true} if the specified activity is whitelisted.
*/
public boolean isWhitelisted(@NonNull ComponentName componentName) {
Preconditions.checkNotNull(componentName);
final String packageName = componentName.getPackageName();
final ArraySet<ComponentName> whitelistedComponents = getWhitelistedComponents(packageName);
if (whitelistedComponents != null) {
return whitelistedComponents.contains(componentName);
}
return isWhitelisted(packageName);
}
/**
* Returns a set of whitelisted components with the given package, or null if nothing is
* whitelisted.
*/
@Nullable
public ArraySet<ComponentName> getWhitelistedComponents(@NonNull String packageName) {
Preconditions.checkNotNull(packageName);
return mWhitelistedPackages == null ? null : mWhitelistedPackages.get(packageName);
}
@Override
public String toString() {
return "WhitelistHelper[" + mWhitelistedPackages + ']';
}
/**
* Dumps it!
*/
public void dump(@NonNull String prefix, @NonNull String message, @NonNull PrintWriter pw) {
if (mWhitelistedPackages == null || mWhitelistedPackages.size() == 0) {
pw.print(prefix); pw.print(message); pw.println(": (no whitelisted packages)");
return;
}
final int size = mWhitelistedPackages.size();
pw.print(prefix); pw.print(message); pw.print(": "); pw.print(size);
pw.println(" packages");
for (int i = 0; i < mWhitelistedPackages.size(); i++) {
final String packageName = mWhitelistedPackages.keyAt(i);
final ArraySet<ComponentName> components = mWhitelistedPackages.valueAt(i);
pw.print(prefix); pw.print(i); pw.print("."); pw.print(packageName); pw.print(": ");
if (components == null) {
pw.println("(whole package)");
continue;
}
pw.print("["); pw.print(components.valueAt(0));
for (int j = 1; j < components.size(); j++) {
pw.print(", "); pw.print(components.valueAt(i));
}
pw.println("]");
}
}
}

View File

@@ -0,0 +1,138 @@
/*
* Copyright (C) 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 com.android.internal.infra;
import static com.google.common.truth.Truth.assertThat;
import static org.testng.Assert.assertThrows;
import android.content.ComponentName;
import android.util.ArraySet;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
/**
* Unit test for {@link WhitelistHelper}.
*
* <p>To run it:
* {@code atest FrameworksCoreTests:com.android.internal.infra.WhitelistHelperTest}
*/
@RunWith(MockitoJUnitRunner.class)
public class WhitelistHelperTest {
private WhitelistHelper mWhitelistHelper = new WhitelistHelper();
private String mPackage1 = "com.example";
private String mPackage2 = "com.example2";
private ComponentName mComponent1 = new ComponentName(mPackage1, "class1");
private ComponentName mComponent2 = new ComponentName(mPackage1, "class2");
private ComponentName mComponentDifferentPkg = new ComponentName(mPackage2, "class3");
@Test
public void testSetWhitelist_emptyArguments() {
assertThrows(IllegalArgumentException.class,
() -> mWhitelistHelper.setWhitelist(new ArraySet<>(), null));
assertThrows(IllegalArgumentException.class,
() -> mWhitelistHelper.setWhitelist(null, new ArraySet<>()));
assertThrows(IllegalArgumentException.class,
() -> mWhitelistHelper.setWhitelist(new ArraySet<>(), new ArraySet<>()));
}
@Test
public void testWhitelistHelper_nullArguments() {
assertThrows(NullPointerException.class,
() -> mWhitelistHelper.isWhitelisted((String) null));
assertThrows(NullPointerException.class,
() -> mWhitelistHelper.isWhitelisted((ComponentName) null));
assertThrows(NullPointerException.class,
() -> mWhitelistHelper.getWhitelistedComponents(null));
}
@Test
public void testSetWhitelist_nullPackage() {
final ArraySet<String> packages = new ArraySet<>();
packages.add(null);
mWhitelistHelper.setWhitelist(packages, null);
assertThat(mWhitelistHelper.isWhitelisted(mPackage1)).isFalse();
assertThat(mWhitelistHelper.isWhitelisted(mPackage2)).isFalse();
assertThat(mWhitelistHelper.isWhitelisted(mComponent1)).isFalse();
assertThat(mWhitelistHelper.isWhitelisted(mComponent2)).isFalse();
assertThat(mWhitelistHelper.isWhitelisted(mComponentDifferentPkg)).isFalse();
}
@Test
public void testSetWhitelist_nullActivity() {
final ArraySet<ComponentName> components = new ArraySet<>();
components.add(null);
mWhitelistHelper.setWhitelist(null, components);
assertThat(mWhitelistHelper.isWhitelisted(mPackage1)).isFalse();
assertThat(mWhitelistHelper.isWhitelisted(mPackage2)).isFalse();
assertThat(mWhitelistHelper.isWhitelisted(mComponent1)).isFalse();
assertThat(mWhitelistHelper.isWhitelisted(mComponent2)).isFalse();
assertThat(mWhitelistHelper.isWhitelisted(mComponentDifferentPkg)).isFalse();
}
@Test
public void testSetWhitelist_replaceWhitelist() {
final ArraySet<ComponentName> components = new ArraySet<>();
components.add(mComponent1);
mWhitelistHelper.setWhitelist(null, components);
assertThat(mWhitelistHelper.isWhitelisted(mComponent1)).isTrue();
assertThat(mWhitelistHelper.isWhitelisted(mComponent2)).isFalse();
final ArraySet<ComponentName> components2 = new ArraySet<>();
components2.add(mComponent2);
mWhitelistHelper.setWhitelist(null, components2);
assertThat(mWhitelistHelper.isWhitelisted(mComponent1)).isFalse();
assertThat(mWhitelistHelper.isWhitelisted(mComponent2)).isTrue();
}
@Test
public void testIsWhitelisted_packageWhitelisted() {
final ArraySet<String> packages = new ArraySet<>();
packages.add(mPackage1);
mWhitelistHelper.setWhitelist(packages, null);
assertThat(mWhitelistHelper.isWhitelisted(mPackage1)).isTrue();
assertThat(mWhitelistHelper.isWhitelisted(mPackage2)).isFalse();
assertThat(mWhitelistHelper.isWhitelisted(mComponent1)).isTrue();
assertThat(mWhitelistHelper.isWhitelisted(mComponent2)).isTrue();
assertThat(mWhitelistHelper.isWhitelisted(mComponentDifferentPkg)).isFalse();
}
@Test
public void testIsWhitelisted_activityWhitelisted() {
final ArraySet<ComponentName> components = new ArraySet<>();
components.add(mComponent1);
mWhitelistHelper.setWhitelist(null, components);
assertThat(mWhitelistHelper.isWhitelisted(mPackage1)).isFalse();
assertThat(mWhitelistHelper.isWhitelisted(mPackage2)).isFalse();
assertThat(mWhitelistHelper.isWhitelisted(mComponent1)).isTrue();
assertThat(mWhitelistHelper.isWhitelisted(mComponent2)).isFalse();
assertThat(mWhitelistHelper.isWhitelisted(mComponentDifferentPkg)).isFalse();
}
}

View File

@@ -72,6 +72,7 @@ import android.view.autofill.IAutoFillManagerClient;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.infra.WhitelistHelper;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.server.LocalServices;
@@ -173,10 +174,10 @@ final class AutofillManagerServiceImpl
private ServiceInfo mRemoteAugmentedAutofillServiceInfo;
/**
* List of packages that are whitelisted to be trigger augmented autofill.
* List of packages/activities that are whitelisted to be trigger augmented autofill.
*/
@GuardedBy("mLock")
private final ArraySet<String> mWhitelistedAugmentAutofillPackages = new ArraySet<>();
private final WhitelistHelper mAugmentedWhitelistHelper = new WhitelistHelper();
AutofillManagerServiceImpl(AutofillManagerService master, Object lock,
LocalLog uiLatencyHistory, LocalLog wtfHistory, int userId, AutoFillUI ui,
@@ -905,13 +906,8 @@ final class AutofillManagerServiceImpl
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("augmented autofill whitelist: ");
mAugmentedWhitelistHelper.dump(prefix2, "Whitelist", pw);
pw.print(prefix); pw.print("Field classification enabled: ");
pw.println(isFieldClassificationEnabledLocked());
@@ -1129,9 +1125,8 @@ final class AutofillManagerServiceImpl
Slog.v(TAG, "setAugmentedAutofillWhitelistLocked(packages=" + packages + ", activities="
+ activities + ")");
}
whitelistForAugmentedAutofillPackages(packages);
whitelistForAugmentedAutofillPackages(packages, activities);
// TODO(b/123100824): whitelist activities as well
// TODO(b/122858578): log metrics
return true;
}
@@ -1171,28 +1166,30 @@ final class AutofillManagerServiceImpl
@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);
return mAugmentedWhitelistHelper.isWhitelisted(componentName);
}
@GuardedBy("mLock")
void setAugmentedAutofillWhitelistLocked(@NonNull AutofillOptions options,
@NonNull String packageName) {
// TODO(b/122595322): need to setwhitelisted activities as well.
options.augmentedEnabled = mWhitelistedAugmentAutofillPackages.contains(packageName);
options.augmentedAutofillEnabled = mAugmentedWhitelistHelper.isWhitelisted(packageName);
options.whitelistedActivitiesForAugmentedAutofill = mAugmentedWhitelistHelper
.getWhitelistedComponents(packageName);
}
private void whitelistForAugmentedAutofillPackages(@NonNull List<String> packages) {
/**
*
* @throws IllegalArgumentException if packages or components are empty.
*/
private void whitelistForAugmentedAutofillPackages(@Nullable List<String> packages,
@Nullable List<ComponentName> components) {
// 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);
if (mMaster.verbose) {
Slog.v(TAG, "whitelisting packages: " + packages + "and activities: " + components);
}
mAugmentedWhitelistHelper.setWhitelist(new ArraySet<>(packages),
new ArraySet<>(components));
mRemoteAugmentedAutofillService = getRemoteAugmentedAutofillServiceLocked();
}
}

View File

@@ -20,8 +20,8 @@ import static android.service.contentcapture.ContentCaptureService.setClientStat
import static android.view.contentcapture.ContentCaptureSession.STATE_DISABLED;
import static android.view.contentcapture.ContentCaptureSession.STATE_DUPLICATED_ID;
import static android.view.contentcapture.ContentCaptureSession.STATE_INTERNAL_ERROR;
import static android.view.contentcapture.ContentCaptureSession.STATE_NOT_WHITELISTED;
import static android.view.contentcapture.ContentCaptureSession.STATE_NO_SERVICE;
import static android.view.contentcapture.ContentCaptureSession.STATE_PACKAGE_NOT_WHITELISTED;
import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_CONTENT;
import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_DATA;
@@ -29,6 +29,7 @@ import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_STRUC
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.ActivityManagerInternal;
import android.app.AppGlobals;
@@ -55,6 +56,7 @@ import android.util.Slog;
import android.view.contentcapture.UserDataRemovalRequest;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.infra.WhitelistHelper;
import com.android.internal.os.IResultReceiver;
import com.android.server.LocalServices;
import com.android.server.contentcapture.RemoteContentCaptureService.ContentCaptureServiceCallbacks;
@@ -94,7 +96,7 @@ final class ContentCapturePerUserService
* List of packages that are whitelisted to be content captured.
*/
@GuardedBy("mLock")
private final ArraySet<String> mWhitelistedPackages = new ArraySet<>();
private final WhitelistHelper mWhitelistHelper = new WhitelistHelper();
// TODO(b/111276913): add mechanism to prune stale sessions, similar to Autofill's
@@ -194,7 +196,7 @@ final class ContentCapturePerUserService
final int taskId = activityPresentationInfo.taskId;
final int displayId = activityPresentationInfo.displayId;
final ComponentName componentName = activityPresentationInfo.componentName;
final boolean whitelisted = isWhitelistedLocked(componentName);
final boolean whiteListed = isWhitelistedLocked(componentName);
final ComponentName serviceComponentName = getServiceComponentName();
final boolean enabled = isEnabledLocked();
if (mMaster.mRequestsHistory != null) {
@@ -204,7 +206,7 @@ final class ContentCapturePerUserService
+ " t=" + taskId + " d=" + displayId
+ " s=" + ComponentName.flattenToShortString(serviceComponentName)
+ " u=" + mUserId + " f=" + flags + (enabled ? "" : " (disabled)")
+ " w=" + whitelisted;
+ " w=" + whiteListed;
mMaster.mRequestsHistory.log(historyItem);
}
@@ -225,12 +227,12 @@ final class ContentCapturePerUserService
return;
}
if (!whitelisted) {
if (!whiteListed) {
if (mMaster.debug) {
Slog.d(TAG, "startSession(" + componentName + "): not whitelisted");
Slog.d(TAG, "startSession(" + componentName + "): package or component "
+ "not whitelisted");
}
// TODO(b/122595322): need to return STATE_ACTIVITY_NOT_WHITELISTED as well
setClientState(clientReceiver, STATE_DISABLED | STATE_PACKAGE_NOT_WHITELISTED,
setClientState(clientReceiver, STATE_DISABLED | STATE_NOT_WHITELISTED,
/* binder= */ null);
return;
}
@@ -270,21 +272,20 @@ final class ContentCapturePerUserService
@GuardedBy("mLock")
private boolean isWhitelistedLocked(@NonNull ComponentName componentName) {
// TODO(b/122595322): need to check whitelisted activities as well.
final String packageName = componentName.getPackageName();
return mWhitelistedPackages.contains(packageName);
return mWhitelistHelper.isWhitelisted(componentName);
}
private void whitelistPackages(@NonNull List<String> packages) {
/**
* @throws IllegalArgumentException if packages or components are empty.
*/
private void setWhitelist(@Nullable List<String> packages,
@Nullable List<ComponentName> components) {
// TODO(b/122595322): add CTS test for when it's null
synchronized (mLock) {
if (packages == null) {
if (mMaster.verbose) Slog.v(TAG, "clearing all whitelisted packages");
mWhitelistedPackages.clear();
} else {
if (mMaster.verbose) Slog.v(TAG, "whitelisting packages: " + packages);
mWhitelistedPackages.addAll(packages);
if (mMaster.verbose) {
Slog.v(TAG, "whitelisting packages: " + packages + "and activities: " + components);
}
mWhitelistHelper.setWhitelist(new ArraySet<>(packages), new ArraySet<>(components));
}
}
@@ -411,15 +412,15 @@ final class ContentCapturePerUserService
@GuardedBy("mLock")
ContentCaptureOptions getOptionsForPackageLocked(@NonNull String packageName) {
if (!mWhitelistedPackages.contains(packageName)) {
if (!mWhitelistHelper.isWhitelisted(packageName)) {
if (mMaster.verbose) {
Slog.v(mTag, "getOptionsForPackage(" + packageName + "): not whitelisted");
}
return null;
}
// TODO(b/122595322): need to check whitelisted activities as well.
final ArraySet<ComponentName> whitelistedComponents = null;
final ArraySet<ComponentName> whitelistedComponents = mWhitelistHelper
.getWhitelistedComponents(packageName);
ContentCaptureOptions options = new ContentCaptureOptions(mMaster.mDevCfgLoggingLevel,
mMaster.mDevCfgMaxBufferSize, mMaster.mDevCfgIdleFlushingFrequencyMs,
mMaster.mDevCfgTextChangeFlushingFrequencyMs, mMaster.mDevCfgLogHistorySize,
@@ -440,12 +441,7 @@ final class ContentCapturePerUserService
mRemoteService.dump(prefix2, pw);
}
final int whitelistSize = mWhitelistedPackages.size();
pw.print(prefix); pw.print("Whitelisted packages: "); pw.println(whitelistSize);
for (int i = 0; i < whitelistSize; i++) {
final String whitelistedPkg = mWhitelistedPackages.valueAt(i);
pw.print(prefix2); pw.print(i + 1); pw.print(": "); pw.println(whitelistedPkg);
}
pw.print(prefix); pw.print("Whitelist: "); pw.println(mWhitelistHelper);
if (mSessions.isEmpty()) {
pw.print(prefix); pw.println("no sessions");
@@ -485,9 +481,8 @@ final class ContentCapturePerUserService
Slog.v(TAG, "setContentCaptureWhitelist(packages=" + packages + ", activities="
+ activities + ")");
}
whitelistPackages(packages);
setWhitelist(packages, activities);
// TODO(b/122595322): whitelist activities as well
// TODO(b/119613670): log metrics
}