diff options
| author | Jing Ji <jji@google.com> | 2020-08-05 23:53:14 +0000 |
|---|---|---|
| committer | Android (Google) Code Review <android-gerrit@google.com> | 2020-08-05 23:53:14 +0000 |
| commit | 9bd766deafe0313fbf63e870c51bbcd4460b7619 (patch) | |
| tree | a41a6350dc190d7ce06411bfa551c5755117758d /core/java | |
| parent | fb88679934a59e7ed72422aa20a01e5898972f77 (diff) | |
| parent | 4dc70f1c08e0c27863fae4c13343cfb47a861eaf (diff) | |
Merge "Move the waiting for the publishing of content provider to client side"
Diffstat (limited to 'core/java')
| -rw-r--r-- | core/java/android/app/ActivityThread.java | 74 | ||||
| -rw-r--r-- | core/java/android/app/ContentProviderHolder.java | 9 | ||||
| -rw-r--r-- | core/java/android/app/IApplicationThread.aidl | 3 |
3 files changed, 69 insertions, 17 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 9b13d256aea6..1e8d19bd59c4 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -420,6 +420,8 @@ public final class ActivityThread extends ClientTransactionHandler { private static final class ProviderKey { final String authority; final int userId; + ContentProviderHolder mHolder; // Temp holder to be used between notifier and waiter + int mWaiters; // Number of threads waiting on the publishing of the provider public ProviderKey(String authority, int userId) { this.authority = authority; @@ -437,7 +439,11 @@ public final class ActivityThread extends ClientTransactionHandler { @Override public int hashCode() { - return ((authority != null) ? authority.hashCode() : 0) ^ userId; + return hashCode(authority, userId); + } + + public static int hashCode(final String auth, final int userIdent) { + return ((auth != null) ? auth.hashCode() : 0) ^ userIdent; } } @@ -458,9 +464,8 @@ public final class ActivityThread extends ClientTransactionHandler { // 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<ProviderKey, Object> mGetProviderLocks = new ArrayMap<>(); + @GuardedBy("mGetProviderKeys") + final SparseArray<ProviderKey> mGetProviderKeys = new SparseArray<>(); final ArrayMap<Activity, ArrayList<OnActivityPausedListener>> mOnPauseListeners = new ArrayMap<Activity, ArrayList<OnActivityPausedListener>>(); @@ -1751,6 +1756,16 @@ public final class ActivityThread extends ClientTransactionHandler { ActivityThread.this, activityToken, actionId, arguments, cancellationSignal, resultCallback)); } + + @Override + public void notifyContentProviderPublishStatus(@NonNull ContentProviderHolder holder, + @NonNull String auth, int userId, boolean published) { + final ProviderKey key = getGetProviderKey(auth, userId); + synchronized (key) { + key.mHolder = holder; + key.notifyAll(); + } + } } private @NonNull SafeCancellationTransport createSafeCancellationTransport( @@ -6796,13 +6811,40 @@ public final class ActivityThread extends ClientTransactionHandler { // 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. ContentProviderHolder holder = null; - try { - synchronized (getGetProviderLock(auth, userId)) { - holder = ActivityManager.getService().getContentProvider( - getApplicationThread(), c.getOpPackageName(), auth, userId, stable); + final ProviderKey key = getGetProviderKey(auth, userId); + synchronized (key) { + boolean wasWaiting = false; + try { + if (key.mWaiters == 0) { + // No other thread is waiting for this provider, let's fetch one by ourselves. + // If the returned holder is non-null but its provider is null and it's not + // local, we'll need to wait for the publishing of the provider. + holder = ActivityManager.getService().getContentProvider( + getApplicationThread(), c.getOpPackageName(), auth, userId, stable); + } + if ((holder != null && holder.provider == null && !holder.mLocal) + || (key.mWaiters > 0 && (holder = key.mHolder) == null)) { + try { + key.mWaiters++; + wasWaiting = true; + key.wait(ContentResolver.CONTENT_PROVIDER_READY_TIMEOUT_MILLIS); + holder = key.mHolder; + if (holder != null && holder.provider == null) { + // probably timed out + holder = null; + } + } catch (InterruptedException e) { + holder = null; + } + } + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } finally { + if (wasWaiting && --key.mWaiters == 0) { + // Clear the holder from the key since the key itself is never cleared. + key.mHolder = null; + } } - } catch (RemoteException ex) { - throw ex.rethrowFromSystemServer(); } if (holder == null) { if (UserManager.get(c).isUserUnlocked(userId)) { @@ -6820,13 +6862,13 @@ 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); + private ProviderKey getGetProviderKey(String auth, int userId) { + final int key = ProviderKey.hashCode(auth, userId); + synchronized (mGetProviderKeys) { + ProviderKey lock = mGetProviderKeys.get(key); if (lock == null) { - lock = key; - mGetProviderLocks.put(key, lock); + lock = new ProviderKey(auth, userId); + mGetProviderKeys.put(key, lock); } return lock; } diff --git a/core/java/android/app/ContentProviderHolder.java b/core/java/android/app/ContentProviderHolder.java index 3d745831ce1c..e330a30de7b0 100644 --- a/core/java/android/app/ContentProviderHolder.java +++ b/core/java/android/app/ContentProviderHolder.java @@ -39,6 +39,11 @@ public class ContentProviderHolder implements Parcelable { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public boolean noReleaseNeeded; + /** + * Whether the provider here is a local provider or not. + */ + public boolean mLocal; + @UnsupportedAppUsage public ContentProviderHolder(ProviderInfo _info) { info = _info; @@ -59,6 +64,7 @@ public class ContentProviderHolder implements Parcelable { } dest.writeStrongBinder(connection); dest.writeInt(noReleaseNeeded ? 1 : 0); + dest.writeInt(mLocal ? 1 : 0); } public static final @android.annotation.NonNull Parcelable.Creator<ContentProviderHolder> CREATOR @@ -81,5 +87,6 @@ public class ContentProviderHolder implements Parcelable { source.readStrongBinder()); connection = source.readStrongBinder(); noReleaseNeeded = source.readInt() != 0; + mLocal = source.readInt() != 0; } -}
\ No newline at end of file +} diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl index 6e9157e2a8c3..e5d4a766a89d 100644 --- a/core/java/android/app/IApplicationThread.aidl +++ b/core/java/android/app/IApplicationThread.aidl @@ -16,6 +16,7 @@ package android.app; +import android.app.ContentProviderHolder; import android.app.IInstrumentationWatcher; import android.app.IUiAutomationConnection; import android.app.ProfilerInfo; @@ -147,4 +148,6 @@ oneway interface IApplicationThread { void performDirectAction(IBinder activityToken, String actionId, in Bundle arguments, in RemoteCallback cancellationCallback, in RemoteCallback resultCallback); + void notifyContentProviderPublishStatus(in ContentProviderHolder holder, String auth, + int userId, boolean published); } |
