diff options
author | Olawale Ogunwale <ogunwale@google.com> | 2015-04-01 15:18:45 +0000 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2015-04-01 15:18:45 +0000 |
commit | 259a649a935ca2ed63419a079211b0ac35f67496 (patch) | |
tree | 931113482aaed0f9bcf525f806d3265da301cc89 /core/java/android/app/ActivityThread.java | |
parent | 22c930457a3f5848ec699fc79e38c4c0d2e5963a (diff) | |
parent | 6091dcbb80d3b1b885b6e02386ccb3139e5e43ae (diff) | |
download | frameworks_base-259a649a935ca2ed63419a079211b0ac35f67496.zip frameworks_base-259a649a935ca2ed63419a079211b0ac35f67496.tar.gz frameworks_base-259a649a935ca2ed63419a079211b0ac35f67496.tar.bz2 |
am 6091dcbb: Merge "[ActivityManager] Improve multi-thread access the same provider"
* commit '6091dcbb80d3b1b885b6e02386ccb3139e5e43ae':
[ActivityManager] Improve multi-thread access the same provider
Diffstat (limited to 'core/java/android/app/ActivityThread.java')
-rw-r--r-- | core/java/android/app/ActivityThread.java | 102 |
1 files changed, 69 insertions, 33 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 3a78734..63287e4 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -257,18 +257,21 @@ public final class ActivityThread { } } + static final class AcquiringProviderRecord { + IActivityManager.ContentProviderHolder holder; + boolean acquiring = true; + int requests = 1; + } + // The lock of mProviderMap protects the following variables. - final ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap - = new ArrayMap<ProviderKey, ProviderClientRecord>(); - final ArrayMap<IBinder, ProviderRefCount> mProviderRefCountMap - = new ArrayMap<IBinder, ProviderRefCount>(); - final ArrayMap<IBinder, ProviderClientRecord> mLocalProviders - = new ArrayMap<IBinder, ProviderClientRecord>(); - final ArrayMap<ComponentName, ProviderClientRecord> mLocalProvidersByName - = new ArrayMap<ComponentName, ProviderClientRecord>(); + final ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap = new ArrayMap<>(); + final ArrayMap<ProviderKey, AcquiringProviderRecord> mAcquiringProviderMap = new ArrayMap<>(); + final ArrayMap<IBinder, ProviderRefCount> mProviderRefCountMap = new ArrayMap<>(); + final ArrayMap<IBinder, ProviderClientRecord> mLocalProviders = new ArrayMap<>(); + final ArrayMap<ComponentName, ProviderClientRecord> mLocalProvidersByName = new ArrayMap<>(); final ArrayMap<Activity, ArrayList<OnActivityPausedListener>> mOnPauseListeners - = new ArrayMap<Activity, ArrayList<OnActivityPausedListener>>(); + = new ArrayMap<>(); final GcIdler mGcIdler = new GcIdler(); boolean mGcIdlerScheduled = false; @@ -345,7 +348,7 @@ public final class ActivityThread { } } - final class ProviderClientRecord { + static final class ProviderClientRecord { final String[] mNames; final IContentProvider mProvider; final ContentProvider mLocalProvider; @@ -4645,22 +4648,57 @@ public final class ActivityThread { public final IContentProvider acquireProvider( Context c, String auth, int userId, boolean stable) { - final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable); + final ProviderKey key = new ProviderKey(auth, userId); + final IContentProvider provider = acquireExistingProvider(c, key, stable); if (provider != null) { return provider; } + AcquiringProviderRecord r; + boolean first = false; + synchronized (mAcquiringProviderMap) { + r = mAcquiringProviderMap.get(key); + if (r == null) { + r = new AcquiringProviderRecord(); + mAcquiringProviderMap.put(key, r); + first = true; + } else { + r.requests++; + } + } - // There is a possible race here. Another thread may try to acquire - // the same provider at the same time. When this happens, we want to ensure - // that the first one wins. - // Note that we cannot hold the lock while acquiring and installing the - // provider since it might take a long time to run and it could also potentially - // be re-entrant in the case where the provider is in the same process. IActivityManager.ContentProviderHolder holder = null; - try { - holder = ActivityManagerNative.getDefault().getContentProvider( - getApplicationThread(), auth, userId, stable); - } catch (RemoteException ex) { + if (first) { + // Multiple threads may try to acquire the same provider at the same time. + // When this happens, we only let the first one really gets provider. + // Other threads just wait for its result. + // Note that we cannot hold the lock while acquiring and installing the + // provider since it might take a long time to run and it could also potentially + // be re-entrant in the case where the provider is in the same process. + try { + holder = ActivityManagerNative.getDefault().getContentProvider( + getApplicationThread(), auth, userId, stable); + } catch (RemoteException ex) { + } + synchronized (r) { + r.holder = holder; + r.acquiring = false; + r.notifyAll(); + } + } else { + synchronized (r) { + while (r.acquiring) { + try { + r.wait(); + } catch (InterruptedException e) { + } + } + holder = r.holder; + } + } + synchronized (mAcquiringProviderMap) { + if (--r.requests == 0) { + mAcquiringProviderMap.remove(key); + } } if (holder == null) { Slog.e(TAG, "Failed to find provider info for " + auth); @@ -4744,8 +4782,12 @@ public final class ActivityThread { public final IContentProvider acquireExistingProvider( Context c, String auth, int userId, boolean stable) { + return acquireExistingProvider(c, new ProviderKey(auth, userId), stable); + } + + final IContentProvider acquireExistingProvider( + Context c, ProviderKey key, boolean stable) { synchronized (mProviderMap) { - final ProviderKey key = new ProviderKey(auth, userId); final ProviderClientRecord pr = mProviderMap.get(key); if (pr == null) { return null; @@ -4756,7 +4798,7 @@ public final class ActivityThread { if (!jBinder.isBinderAlive()) { // The hosting process of the provider has died; we can't // use this one. - Log.i(TAG, "Acquiring provider " + auth + " for user " + userId + Log.i(TAG, "Acquiring provider " + key.authority + " for user " + key.userId + ": existing object's process dead"); handleUnstableProviderDiedLocked(jBinder, true); return null; @@ -5078,18 +5120,12 @@ public final class ActivityThread { if (DEBUG_PROVIDER) { Slog.v(TAG, "installProvider: lost the race, updating ref count"); } - // We need to transfer our new reference to the existing - // ref count, releasing the old one... but only if - // release is needed (that is, it is not running in the - // system process). + // The provider has already been installed, so we need + // to increase reference count to the existing one, but + // only if release is needed (that is, it is not running + // in the system process or local to the process). if (!noReleaseNeeded) { incProviderRefLocked(prc, stable); - try { - ActivityManagerNative.getDefault().removeContentProvider( - holder.connection, stable); - } catch (RemoteException e) { - //do nothing content provider object is dead any way - } } } else { ProviderClientRecord client = installProviderAuthoritiesLocked( |