Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 39738c7f authored by yuanhuihui's avatar yuanhuihui Committed by Joey Rizzoli
Browse files

fix anr when concurrent request provider

anr reason:
1. system_server process: each binder thread is  waiting for provider publish,
so there is no idle binder thread;
2. providerTest process: process which contains target provider
 is publishing Content Provider, so binder call to system_server,
but no idle binder thread in system_server.

details as below:
https://code.google.com/p/android/issues/detail?id=239971



Test: using providerTest.apk can reproduct anr issue

Change-Id: I6a759a36b5a73a04bc884e56ad2abb6f8173312d
Signed-off-by: default avataryuanhuihui <yuanhuihui@xiaomi.com>
parent 94d8c279
Loading
Loading
Loading
Loading
+40 −8
Original line number Diff line number Diff line
@@ -293,6 +293,8 @@ public final class ActivityThread {
    // The lock of mProviderMap protects the following variables.
    final ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap
        = new ArrayMap<ProviderKey, ProviderClientRecord>();
    final ArrayMap<ProviderKey, ProviderAcquiringCount> mProviderAcquiringCountMap
        = new ArrayMap<>();
    final ArrayMap<IBinder, ProviderRefCount> mProviderRefCountMap
        = new ArrayMap<IBinder, ProviderRefCount>();
    final ArrayMap<IBinder, ProviderClientRecord> mLocalProviders
@@ -3832,6 +3834,14 @@ public final class ActivityThread {
        }
    }

    static final class ProviderAcquiringCount {
        public int acquiringCount;

        ProviderAcquiringCount(int aCount) {
            acquiringCount = aCount;
        }
    }

    /**
     * Core implementation of stopping an activity.  Note this is a little
     * tricky because the server's meaning of stop is slightly different
@@ -5495,11 +5505,23 @@ 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;
        }

        ProviderAcquiringCount pac;
        synchronized (mProviderMap) {
            pac = mProviderAcquiringCountMap.get(key);
            if (pac == null) {
                pac = new ProviderAcquiringCount(1);
                mProviderAcquiringCountMap.put(key, pac);
            } else {
                pac.acquiringCount++;
            }
        }

        // 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.
@@ -5507,11 +5529,17 @@ public final class ActivityThread {
        // 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;
        synchronized (pac) {
            try {
                holder = ActivityManagerNative.getDefault().getContentProvider(
                        getApplicationThread(), auth, userId, stable);
            } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
            }
        }
        synchronized (mProviderMap) {
            if(--pac.acquiringCount == 0) {
                mProviderAcquiringCountMap.remove(key);
            }
        }
        if (holder == null) {
            Slog.e(TAG, "Failed to find provider info for " + auth);
@@ -5595,8 +5623,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);
    }

    public 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;
@@ -5607,7 +5639,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;