summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Joanne Chung <joannechung@google.com> 2020-03-25 02:21:47 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2020-03-25 02:21:47 +0000
commit291a32c9436a7d7f78c4c908c52c93d6633f457c (patch)
tree006df69de7d229b0dada711523485153c361586b
parent3361dd2ad3a1485b37052cdeb716607dff19900a (diff)
parent44f3ee4c206adc99d7d44728cce1c74eccc7f2cd (diff)
Merge "Fix potential deadlock in getAutofillOptions()." into rvc-dev
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerService.java249
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java137
2 files changed, 248 insertions, 138 deletions
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index e49c1ed47c93..c6a54fc3d206 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -50,6 +50,7 @@ import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ShellCallback;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.DeviceConfig;
@@ -63,6 +64,7 @@ import android.util.LocalLog;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
+import android.util.TimeUtils;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillManager.SmartSuggestionMode;
@@ -151,6 +153,7 @@ public final class AutofillManagerService
private final LocalLog mWtfHistory = new LocalLog(50);
private final AutofillCompatState mAutofillCompatState = new AutofillCompatState();
+ private final DisabledInfoCache mDisabledInfoCache = new DisabledInfoCache();
private final LocalService mLocalService = new LocalService();
private final ActivityManagerInternal mAm;
@@ -302,14 +305,15 @@ public final class AutofillManagerService
@Override // from AbstractMasterSystemService
protected AutofillManagerServiceImpl newServiceLocked(@UserIdInt int resolvedUserId,
boolean disabled) {
- return new AutofillManagerServiceImpl(this, mLock, mUiLatencyHistory,
- mWtfHistory, resolvedUserId, mUi, mAutofillCompatState, disabled);
+ return new AutofillManagerServiceImpl(this, mLock, mUiLatencyHistory, mWtfHistory,
+ resolvedUserId, mUi, mAutofillCompatState, disabled, mDisabledInfoCache);
}
@Override // AbstractMasterSystemService
protected void onServiceRemoved(@NonNull AutofillManagerServiceImpl service,
@UserIdInt int userId) {
service.destroyLocked();
+ mDisabledInfoCache.remove(userId);
mAutofillCompatState.removeCompatibilityModeRequests(userId);
}
@@ -835,15 +839,10 @@ public final class AutofillManagerService
private void injectDisableAppInfo(@NonNull AutofillOptions options, int userId,
String packageName) {
- synchronized (mLock) {
- final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
- if (service != null) {
- options.appDisabledExpiration = service.getAppDisabledExpirationLocked(
- packageName);
- options.disabledActivities = service.getAppDisabledActivitiesLocked(
- packageName);
- }
- }
+ options.appDisabledExpiration =
+ mDisabledInfoCache.getAppDisabledExpiration(userId, packageName);
+ options.disabledActivities =
+ mDisabledInfoCache.getAppDisabledActivities(userId, packageName);
}
}
@@ -867,6 +866,234 @@ public final class AutofillManagerService
}
/**
+ * Stores autofill disable information, i.e. {@link AutofillDisabledInfo}, keyed by user id.
+ * The information is cleaned up when the service is removed.
+ */
+ static final class DisabledInfoCache {
+
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private final SparseArray<AutofillDisabledInfo> mCache = new SparseArray<>();
+
+ void remove(@UserIdInt int userId) {
+ synchronized (mLock) {
+ mCache.remove(userId);
+ }
+ }
+
+ void addDisabledAppLocked(@UserIdInt int userId, @NonNull String packageName,
+ long expiration) {
+ Preconditions.checkNotNull(packageName);
+ synchronized (mLock) {
+ AutofillDisabledInfo info =
+ getOrCreateAutofillDisabledInfoByUserIdLocked(userId);
+ info.putDisableAppsLocked(packageName, expiration);
+ }
+ }
+
+ void addDisabledActivityLocked(@UserIdInt int userId, @NonNull ComponentName componentName,
+ long expiration) {
+ Preconditions.checkNotNull(componentName);
+ synchronized (mLock) {
+ AutofillDisabledInfo info =
+ getOrCreateAutofillDisabledInfoByUserIdLocked(userId);
+ info.putDisableActivityLocked(componentName, expiration);
+ }
+ }
+
+ boolean isAutofillDisabledLocked(@UserIdInt int userId,
+ @NonNull ComponentName componentName) {
+ Preconditions.checkNotNull(componentName);
+ final boolean disabled;
+ synchronized (mLock) {
+ final AutofillDisabledInfo info = mCache.get(userId);
+ disabled = info != null ? info.isAutofillDisabledLocked(componentName) : false;
+ }
+ return disabled;
+ }
+
+ long getAppDisabledExpiration(@UserIdInt int userId, @NonNull String packageName) {
+ Preconditions.checkNotNull(packageName);
+ final Long expiration;
+ synchronized (mLock) {
+ final AutofillDisabledInfo info = mCache.get(userId);
+ expiration = info != null ? info.getAppDisabledExpirationLocked(packageName) : 0;
+ }
+ return expiration;
+ }
+
+ @Nullable
+ ArrayMap<String, Long> getAppDisabledActivities(@UserIdInt int userId,
+ @NonNull String packageName) {
+ Preconditions.checkNotNull(packageName);
+ final ArrayMap<String, Long> disabledList;
+ synchronized (mLock) {
+ final AutofillDisabledInfo info = mCache.get(userId);
+ disabledList =
+ info != null ? info.getAppDisabledActivitiesLocked(packageName) : null;
+ }
+ return disabledList;
+ }
+
+ void dump(@UserIdInt int userId, String prefix, PrintWriter pw) {
+ synchronized (mLock) {
+ final AutofillDisabledInfo info = mCache.get(userId);
+ if (info != null) {
+ info.dumpLocked(prefix, pw);
+ }
+ }
+ }
+
+ @NonNull
+ private AutofillDisabledInfo getOrCreateAutofillDisabledInfoByUserIdLocked(
+ @UserIdInt int userId) {
+ AutofillDisabledInfo info = mCache.get(userId);
+ if (info == null) {
+ info = new AutofillDisabledInfo();
+ mCache.put(userId, info);
+ }
+ return info;
+ }
+ }
+
+ /**
+ * The autofill disable information.
+ * <p>
+ * This contains disable information set by the AutofillService, e.g. disabled application
+ * expiration, disable activity expiration.
+ */
+ private static final class AutofillDisabledInfo {
+ /**
+ * Apps disabled by the service; key is package name, value is when they will be enabled
+ * again.
+ */
+ private ArrayMap<String, Long> mDisabledApps;
+ /**
+ * Activities disabled by the service; key is component name, value is when they will be
+ * enabled again.
+ */
+ private ArrayMap<ComponentName, Long> mDisabledActivities;
+
+ void putDisableAppsLocked(@NonNull String packageName, long expiration) {
+ if (mDisabledApps == null) {
+ mDisabledApps = new ArrayMap<>(1);
+ }
+ mDisabledApps.put(packageName, expiration);
+ }
+
+ void putDisableActivityLocked(@NonNull ComponentName componentName, long expiration) {
+ if (mDisabledActivities == null) {
+ mDisabledActivities = new ArrayMap<>(1);
+ }
+ mDisabledActivities.put(componentName, expiration);
+ }
+
+ long getAppDisabledExpirationLocked(@NonNull String packageName) {
+ if (mDisabledApps == null) {
+ return 0;
+ }
+ final Long expiration = mDisabledApps.get(packageName);
+ return expiration != null ? expiration : 0;
+ }
+
+ ArrayMap<String, Long> getAppDisabledActivitiesLocked(@NonNull String packageName) {
+ if (mDisabledActivities != null) {
+ final int size = mDisabledActivities.size();
+ ArrayMap<String, Long> disabledList = null;
+ for (int i = 0; i < size; i++) {
+ final ComponentName component = mDisabledActivities.keyAt(i);
+ if (packageName.equals(component.getPackageName())) {
+ if (disabledList == null) {
+ disabledList = new ArrayMap<>();
+ }
+ final long expiration = mDisabledActivities.valueAt(i);
+ disabledList.put(component.flattenToShortString(), expiration);
+ }
+ }
+ return disabledList;
+ }
+ return null;
+ }
+
+ boolean isAutofillDisabledLocked(@NonNull ComponentName componentName) {
+ // Check activities first.
+ long elapsedTime = 0;
+ if (mDisabledActivities != null) {
+ elapsedTime = SystemClock.elapsedRealtime();
+ final Long expiration = mDisabledActivities.get(componentName);
+ if (expiration != null) {
+ if (expiration >= elapsedTime) return true;
+ // Restriction expired - clean it up.
+ if (sVerbose) {
+ Slog.v(TAG, "Removing " + componentName.toShortString()
+ + " from disabled list");
+ }
+ mDisabledActivities.remove(componentName);
+ }
+ }
+
+ // Then check apps.
+ final String packageName = componentName.getPackageName();
+ if (mDisabledApps == null) return false;
+
+ final Long expiration = mDisabledApps.get(packageName);
+ if (expiration == null) return false;
+
+ if (elapsedTime == 0) {
+ elapsedTime = SystemClock.elapsedRealtime();
+ }
+
+ if (expiration >= elapsedTime) return true;
+
+ // Restriction expired - clean it up.
+ if (sVerbose) Slog.v(TAG, "Removing " + packageName + " from disabled list");
+ mDisabledApps.remove(packageName);
+ return false;
+ }
+
+ void dumpLocked(String prefix, PrintWriter pw) {
+ pw.print(prefix); pw.print("Disabled apps: ");
+ if (mDisabledApps == null) {
+ pw.println("N/A");
+ } else {
+ final int size = mDisabledApps.size();
+ pw.println(size);
+ final StringBuilder builder = new StringBuilder();
+ final long now = SystemClock.elapsedRealtime();
+ for (int i = 0; i < size; i++) {
+ final String packageName = mDisabledApps.keyAt(i);
+ final long expiration = mDisabledApps.valueAt(i);
+ builder.append(prefix).append(prefix)
+ .append(i).append(". ").append(packageName).append(": ");
+ TimeUtils.formatDuration((expiration - now), builder);
+ builder.append('\n');
+ }
+ pw.println(builder);
+ }
+
+ pw.print(prefix); pw.print("Disabled activities: ");
+ if (mDisabledActivities == null) {
+ pw.println("N/A");
+ } else {
+ final int size = mDisabledActivities.size();
+ pw.println(size);
+ final StringBuilder builder = new StringBuilder();
+ final long now = SystemClock.elapsedRealtime();
+ for (int i = 0; i < size; i++) {
+ final ComponentName component = mDisabledActivities.keyAt(i);
+ final long expiration = mDisabledActivities.valueAt(i);
+ builder.append(prefix).append(prefix)
+ .append(i).append(". ").append(component).append(": ");
+ TimeUtils.formatDuration((expiration - now), builder);
+ builder.append('\n');
+ }
+ pw.println(builder);
+ }
+ }
+ }
+
+ /**
* Compatibility mode metadata associated with all services.
*
* <p>This object is defined here instead of on each {@link AutofillManagerServiceImpl} because
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 6fbe1410bbad..d1805d96cad8 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -67,7 +67,6 @@ import android.util.LocalLog;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
-import android.util.TimeUtils;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillManager.SmartSuggestionMode;
@@ -80,6 +79,7 @@ import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.server.LocalServices;
import com.android.server.autofill.AutofillManagerService.AutofillCompatState;
+import com.android.server.autofill.AutofillManagerService.DisabledInfoCache;
import com.android.server.autofill.RemoteAugmentedAutofillService.RemoteAugmentedAutofillServiceCallbacks;
import com.android.server.autofill.ui.AutoFillUI;
import com.android.server.contentcapture.ContentCaptureManagerInternal;
@@ -90,7 +90,6 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
-
/**
* Bridge between the {@code system_server}'s {@link AutofillManagerService} and the
* app's {@link IAutoFillService} implementation.
@@ -125,19 +124,6 @@ final class AutofillManagerServiceImpl
private RemoteInlineSuggestionRenderService mRemoteInlineSuggestionRenderService;
/**
- * Apps disabled by the service; key is package name, value is when they will be enabled again.
- */
- @GuardedBy("mLock")
- private ArrayMap<String, Long> mDisabledApps;
-
- /**
- * Activities disabled by the service; key is component name, value is when they will be enabled
- * again.
- */
- @GuardedBy("mLock")
- private ArrayMap<ComponentName, Long> mDisabledActivities;
-
- /**
* Data used for field classification.
*/
@GuardedBy("mLock")
@@ -186,10 +172,12 @@ final class AutofillManagerServiceImpl
private final ContentCaptureManagerInternal mContentCaptureManagerInternal;
+ private final DisabledInfoCache mDisabledInfoCache;
+
AutofillManagerServiceImpl(AutofillManagerService master, Object lock,
LocalLog uiLatencyHistory, LocalLog wtfHistory, int userId, AutoFillUI ui,
AutofillCompatState autofillCompatState,
- boolean disabled) {
+ boolean disabled, DisabledInfoCache disableCache) {
super(master, lock, userId);
mUiLatencyHistory = uiLatencyHistory;
@@ -200,7 +188,7 @@ final class AutofillManagerServiceImpl
mInputMethodManagerInternal = LocalServices.getService(InputMethodManagerInternal.class);
mContentCaptureManagerInternal = LocalServices.getService(
ContentCaptureManagerInternal.class);
-
+ mDisabledInfoCache = disableCache;
updateLocked(disabled);
}
@@ -1045,45 +1033,7 @@ final class AutofillManagerServiceImpl
pw.println(isInlineSuggestionsEnabled());
pw.print(prefix); pw.print("Last prune: "); pw.println(mLastPrune);
- pw.print(prefix); pw.print("Disabled apps: ");
-
- if (mDisabledApps == null) {
- pw.println("N/A");
- } else {
- final int size = mDisabledApps.size();
- pw.println(size);
- final StringBuilder builder = new StringBuilder();
- final long now = SystemClock.elapsedRealtime();
- for (int i = 0; i < size; i++) {
- final String packageName = mDisabledApps.keyAt(i);
- final long expiration = mDisabledApps.valueAt(i);
- builder.append(prefix).append(prefix)
- .append(i).append(". ").append(packageName).append(": ");
- TimeUtils.formatDuration((expiration - now), builder);
- builder.append('\n');
- }
- pw.println(builder);
- }
-
- pw.print(prefix); pw.print("Disabled activities: ");
-
- if (mDisabledActivities == null) {
- pw.println("N/A");
- } else {
- final int size = mDisabledActivities.size();
- pw.println(size);
- final StringBuilder builder = new StringBuilder();
- final long now = SystemClock.elapsedRealtime();
- for (int i = 0; i < size; i++) {
- final ComponentName component = mDisabledActivities.keyAt(i);
- final long expiration = mDisabledActivities.valueAt(i);
- builder.append(prefix).append(prefix)
- .append(i).append(". ").append(component).append(": ");
- TimeUtils.formatDuration((expiration - now), builder);
- builder.append('\n');
- }
- pw.println(builder);
- }
+ mDisabledInfoCache.dump(mUserId, prefix, pw);
final int size = mSessions.size();
if (size == 0) {
@@ -1480,15 +1430,13 @@ final class AutofillManagerServiceImpl
void disableAutofillForApp(@NonNull String packageName, long duration, int sessionId,
boolean compatMode) {
synchronized (mLock) {
- if (mDisabledApps == null) {
- mDisabledApps = new ArrayMap<>(1);
- }
long expiration = SystemClock.elapsedRealtime() + duration;
// Protect it against overflow
if (expiration < 0) {
expiration = Long.MAX_VALUE;
}
- mDisabledApps.put(packageName, expiration);
+ mDisabledInfoCache.addDisabledAppLocked(mUserId, packageName, expiration);
+
int intDuration = duration > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) duration;
mMetricsLogger.write(Helper.newLogMaker(MetricsEvent.AUTOFILL_SERVICE_DISABLED_APP,
packageName, getServicePackageName(), sessionId, compatMode)
@@ -1502,15 +1450,12 @@ final class AutofillManagerServiceImpl
void disableAutofillForActivity(@NonNull ComponentName componentName, long duration,
int sessionId, boolean compatMode) {
synchronized (mLock) {
- if (mDisabledActivities == null) {
- mDisabledActivities = new ArrayMap<>(1);
- }
long expiration = SystemClock.elapsedRealtime() + duration;
// Protect it against overflow
if (expiration < 0) {
expiration = Long.MAX_VALUE;
}
- mDisabledActivities.put(componentName, expiration);
+ mDisabledInfoCache.addDisabledActivityLocked(mUserId, componentName, expiration);
final int intDuration = duration > Integer.MAX_VALUE
? Integer.MAX_VALUE
: (int) duration;
@@ -1528,74 +1473,12 @@ final class AutofillManagerServiceImpl
}
}
- // Called by AutofillManagerService
- long getAppDisabledExpirationLocked(@NonNull String packageName) {
- if (mDisabledApps == null) {
- return 0;
- }
- final Long expiration = mDisabledApps.get(packageName);
- return expiration != null ? expiration : 0;
- }
-
- // Called by AutofillManagerService
- @Nullable
- ArrayMap<String, Long> getAppDisabledActivitiesLocked(@NonNull String packageName) {
- if (mDisabledActivities != null) {
- final int size = mDisabledActivities.size();
- ArrayMap<String, Long> disabledList = null;
- for (int i = 0; i < size; i++) {
- final ComponentName component = mDisabledActivities.keyAt(i);
- if (packageName.equals(component.getPackageName())) {
- if (disabledList == null) {
- disabledList = new ArrayMap<>();
- }
- final long expiration = mDisabledActivities.valueAt(i);
- disabledList.put(component.flattenToShortString(), expiration);
- }
- }
- return disabledList;
- }
- return null;
- }
-
/**
* Checks if autofill is disabled by service to the given activity.
*/
@GuardedBy("mLock")
private boolean isAutofillDisabledLocked(@NonNull ComponentName componentName) {
- // Check activities first.
- long elapsedTime = 0;
- if (mDisabledActivities != null) {
- elapsedTime = SystemClock.elapsedRealtime();
- final Long expiration = mDisabledActivities.get(componentName);
- if (expiration != null) {
- if (expiration >= elapsedTime) return true;
- // Restriction expired - clean it up.
- if (sVerbose) {
- Slog.v(TAG, "Removing " + componentName.toShortString()
- + " from disabled list");
- }
- mDisabledActivities.remove(componentName);
- }
- }
-
- // Then check apps.
- final String packageName = componentName.getPackageName();
- if (mDisabledApps == null) return false;
-
- final Long expiration = mDisabledApps.get(packageName);
- if (expiration == null) return false;
-
- if (elapsedTime == 0) {
- elapsedTime = SystemClock.elapsedRealtime();
- }
-
- if (expiration >= elapsedTime) return true;
-
- // Restriction expired - clean it up.
- if (sVerbose) Slog.v(TAG, "Removing " + packageName + " from disabled list");
- mDisabledApps.remove(packageName);
- return false;
+ return mDisabledInfoCache.isAutofillDisabledLocked(mUserId, componentName);
}
// Called by AutofillManager, checks UID.