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

Commit 0c07db19 authored by Varun Shah's avatar Varun Shah
Browse files

Optimize Content Provider removal.

Delay the removal of content providers to avoid churn caused by
providers that get quickly re-acquired after release.

Bug: 156262145
Test: atest ContentProviderTest [all]
Test: manually observe lack of churn
Change-Id: Ia7ce4a04b105aaf13e849cef49434535483aa3db
parent 1669cd3c
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -265,4 +265,13 @@ public final class ContentProviderConnection extends Binder {
            return mUnstableCount;
        }
    }

    /**
     * Returns the total number of stable and unstable references.
     */
    int totalRefCount() {
        synchronized (mLock) {
            return mStableCount + mUnstableCount;
        }
    }
}
+45 −20
Original line number Diff line number Diff line
@@ -62,6 +62,7 @@ import android.util.Slog;
import android.util.SparseArray;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.ArrayUtils;
import com.android.server.RescueParty;

@@ -261,7 +262,8 @@ public class ContentProviderHelper {
                    // doesn't kill our process.
                    Slog.wtf(TAG, "Existing provider " + cpr.name.flattenToShortString()
                            + " is crashing; detaching " + r);
                    boolean lastRef = decProviderCountLocked(conn, cpr, token, stable);
                    boolean lastRef = decProviderCountLocked(conn, cpr, token, stable,
                            false, false);
                    if (!lastRef) {
                        // This wasn't the last ref our process had on
                        // the provider...  we will be killed during cleaning up, bail.
@@ -697,10 +699,7 @@ public class ContentProviderHelper {
                if (conn == null) {
                    throw new NullPointerException("connection is null");
                }
                if (decProviderCountLocked(conn, null, null, stable)) {
                    mService.updateOomAdjLocked(conn.provider.proc,
                            OomAdjuster.OOM_ADJ_REASON_REMOVE_PROVIDER);
                }
                decProviderCountLocked(conn, null, null, stable, true, true);
            }
        } finally {
            Binder.restoreCallingIdentity(ident);
@@ -1275,16 +1274,38 @@ public class ContentProviderHelper {

    @GuardedBy("mService")
    private boolean decProviderCountLocked(ContentProviderConnection conn,
            ContentProviderRecord cpr, IBinder externalProcessToken, boolean stable) {
            ContentProviderRecord cpr, IBinder externalProcessToken, boolean stable,
            boolean enforceDelay, boolean updateOomAdj) {
        if (conn == null) {
            cpr.removeExternalProcessHandleLocked(externalProcessToken);
            return false;
        }
        if (conn.decrementCount(stable) != 0) {

        if (conn.totalRefCount() > 1) {
            conn.decrementCount(stable);
            return false;
        }
        if (enforceDelay) {
            // delay the removal of the provider for 5 seconds - this optimizes for those cases
            // where providers are released and then quickly re-acquired, causing lots of churn.
            BackgroundThread.getHandler().postDelayed(() -> {
                handleProviderRemoval(conn, stable, updateOomAdj);
            }, 5 * 1000);
        } else {
            handleProviderRemoval(conn, stable, updateOomAdj);
        }
        return true;
    }

        cpr = conn.provider;
    private void handleProviderRemoval(ContentProviderConnection conn, boolean stable,
            boolean updateOomAdj) {
        synchronized (mService) {
            // if the proc was already killed or this is not the last reference, simply exit.
            if (conn == null || conn.provider == null || conn.decrementCount(stable) != 0) {
                return;
            }

            final ContentProviderRecord cpr = conn.provider;
            conn.stopAssociation();
            cpr.connections.remove(conn);
            conn.client.conProviders.remove(conn);
@@ -1298,7 +1319,11 @@ public class ContentProviderHelper {
            }
            mService.stopAssociationLocked(conn.client.uid, conn.client.processName, cpr.uid,
                    cpr.appInfo.longVersionCode, cpr.name, cpr.info.processName);
        return true;
            if (updateOomAdj) {
                mService.updateOomAdjLocked(conn.provider.proc,
                        OomAdjuster.OOM_ADJ_REASON_REMOVE_PROVIDER);
            }
        }
    }

    /**