diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 37bf21a898b14..87b334992d2da 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -347,6 +347,13 @@ public final class ActivityThread extends ClientTransactionHandler { final ArrayMap mLocalProvidersByName = new ArrayMap(); + // Mitigation for b/74523247: Used to serialize calls to AM.getContentProvider(). + // Note we never removes items from this map but that's okay because there are only so many + // users and so many authorities. + // TODO Remove it once we move CPR.wait() from AMS to the client side. + @GuardedBy("mGetProviderLocks") + final ArrayMap mGetProviderLocks = new ArrayMap<>(); + final ArrayMap> mOnPauseListeners = new ArrayMap>(); @@ -5959,8 +5966,10 @@ public final class ActivityThread extends ClientTransactionHandler { // be re-entrant in the case where the provider is in the same process. ContentProviderHolder holder = null; try { - holder = ActivityManager.getService().getContentProvider( - getApplicationThread(), auth, userId, stable); + synchronized (getGetProviderLock(auth, userId)) { + holder = ActivityManager.getService().getContentProvider( + getApplicationThread(), auth, userId, stable); + } } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } @@ -5976,6 +5985,18 @@ public final class ActivityThread extends ClientTransactionHandler { return holder.provider; } + private Object getGetProviderLock(String auth, int userId) { + final ProviderKey key = new ProviderKey(auth, userId); + synchronized (mGetProviderLocks) { + Object lock = mGetProviderLocks.get(key); + if (lock == null) { + lock = key; + mGetProviderLocks.put(key, lock); + } + return lock; + } + } + private final void incProviderRefLocked(ProviderRefCount prc, boolean stable) { if (stable) { prc.stableCount += 1;