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

Commit adda5000 authored by Jing Ji's avatar Jing Ji
Browse files

Move the waiting for the publishing of content provider to client side

...except the external provider client.

Previously the waiting is within the system_server and holds a binder
thread of the system_server. Now the waiting will be in client side
and the system_server will notify the client when the provider is
ready.

Bug: 149935749
Bug: 162450085
Test: atest CtsContentTestCases:android.content.cts
Test: atest FrameworksCoreTests:android.content
Test: atest ActivityManagerPerfTests:ContentProviderPerfTest
Change-Id: I0c8ef1c397103ac38f2fb7da79e647c0b8cd63cc
parent 5605ab66
Loading
Loading
Loading
Loading
+49 −11
Original line number Diff line number Diff line
@@ -421,9 +421,14 @@ public final class ActivityThread extends ClientTransactionHandler {
        final String authority;
        final int userId;

        @GuardedBy("mLock")
        ContentProviderHolder mHolder; // Temp holder to be used between notifier and waiter
        Object mLock; // The lock to be used to get notified when the provider is ready

        public ProviderKey(String authority, int userId) {
            this.authority = authority;
            this.userId = userId;
            this.mLock = new Object();
        }

        @Override
@@ -437,7 +442,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 +467,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 +1759,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.mLock) {
                key.mHolder = holder;
                key.mLock.notifyAll();
            }
        }
    }

    private @NonNull SafeCancellationTransport createSafeCancellationTransport(
@@ -6796,13 +6814,33 @@ 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;
        final ProviderKey key = getGetProviderKey(auth, userId);
        try {
            synchronized (getGetProviderLock(auth, userId)) {
            synchronized (key) {
                holder = ActivityManager.getService().getContentProvider(
                        getApplicationThread(), c.getOpPackageName(), auth, userId, stable);
                // 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.
                if (holder != null && holder.provider == null && !holder.mLocal) {
                    synchronized (key.mLock) {
                        key.mLock.wait(ContentResolver.CONTENT_PROVIDER_READY_TIMEOUT_MILLIS);
                        holder = key.mHolder;
                    }
                    if (holder != null && holder.provider == null) {
                        // probably timed out
                        holder = null;
                    }
                }
            }
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        } catch (InterruptedException e) {
            holder = null;
        } finally {
            // Clear the holder from the key since the key itself is never cleared.
            synchronized (key.mLock) {
                key.mHolder = null;
            }
        }
        if (holder == null) {
            if (UserManager.get(c).isUserUnlocked(userId)) {
@@ -6820,13 +6858,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;
        }
+8 −1
Original line number Diff line number Diff line
@@ -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;
    }
}
+3 −0
Original line number Diff line number Diff line
@@ -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);
}
+6 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import static android.app.servertransaction.TestUtils.resultInfoList;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import android.app.ContentProviderHolder;
import android.app.IApplicationThread;
import android.app.IInstrumentationWatcher;
import android.app.IUiAutomationConnection;
@@ -664,5 +665,10 @@ public class TransactionParcelTests {
        public void performDirectAction(IBinder activityToken, String actionId, Bundle arguments,
                RemoteCallback cancellationCallback, RemoteCallback resultCallback) {
        }

        @Override
        public void notifyContentProviderPublishStatus(ContentProviderHolder holder, String auth,
                int userId, boolean published) {
        }
    }
}
+6 −0
Original line number Diff line number Diff line
@@ -1579,6 +1579,7 @@ public class ActivityManagerService extends IActivityManager.Stub
    static final int DISPATCH_OOM_ADJ_OBSERVER_MSG = 70;
    static final int KILL_APP_ZYGOTE_MSG = 71;
    static final int BINDER_HEAVYHITTER_AUTOSAMPLER_TIMEOUT_MSG = 72;
    static final int WAIT_FOR_CONTENT_PROVIDER_TIMEOUT_MSG = 73;
    static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1915,6 +1916,11 @@ public class ActivityManagerService extends IActivityManager.Stub
                case BINDER_HEAVYHITTER_AUTOSAMPLER_TIMEOUT_MSG: {
                    handleBinderHeavyHitterAutoSamplerTimeOut();
                } break;
                case WAIT_FOR_CONTENT_PROVIDER_TIMEOUT_MSG: {
                    synchronized (ActivityManagerService.this) {
                        ((ContentProviderRecord) msg.obj).onProviderPublishStatusLocked(false);
                    }
                } break;
            }
        }
    }
Loading