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

Commit 715d62fd authored by Jeff Sharkey's avatar Jeff Sharkey
Browse files

[7/?] Reduce BroadcastQueue interface complexity.

Converge towards always using IApplicationThread to identify the
remote caller that is finishing a broadcast.  This pivot will enable
us to scale nicely to our future redesigned per-app stack, since that
will still only ever dispatch a single broadcast per app.

Add explicit setCurrent() and clearCurrent() methods to ensure that
all BroadcastRecord fields are updated consistently.

Bug: 243656033
Test: atest CtsContentTestCases:BroadcastReceiverTest
Test: atest FrameworksMockingServicesTests:BroadcastQueueTest
Change-Id: I3db8382798bb25fabe20aa9864cf6f8831b64371
parent 9d11e150
Loading
Loading
Loading
Loading
+13 −9
Original line number Diff line number Diff line
@@ -1390,8 +1390,9 @@ class ContextImpl extends Context {
                if (scheduler == null) {
                    scheduler = mMainThread.getHandler();
                }
                rd = new LoadedApk.ReceiverDispatcher(
                        resultReceiver, getOuterContext(), scheduler, null, false).getIIntentReceiver();
                rd = new LoadedApk.ReceiverDispatcher(mMainThread.getApplicationThread(),
                        resultReceiver, getOuterContext(), scheduler, null, false)
                                .getIIntentReceiver();
            }
        }
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
@@ -1497,8 +1498,9 @@ class ContextImpl extends Context {
                if (scheduler == null) {
                    scheduler = mMainThread.getHandler();
                }
                rd = new LoadedApk.ReceiverDispatcher(resultReceiver, getOuterContext(),
                        scheduler, null, false).getIIntentReceiver();
                rd = new LoadedApk.ReceiverDispatcher(mMainThread.getApplicationThread(),
                        resultReceiver, getOuterContext(), scheduler, null, false)
                                .getIIntentReceiver();
            }
        }
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
@@ -1616,8 +1618,9 @@ class ContextImpl extends Context {
                if (scheduler == null) {
                    scheduler = mMainThread.getHandler();
                }
                rd = new LoadedApk.ReceiverDispatcher(
                        resultReceiver, getOuterContext(), scheduler, null, false).getIIntentReceiver();
                rd = new LoadedApk.ReceiverDispatcher(mMainThread.getApplicationThread(),
                        resultReceiver, getOuterContext(), scheduler, null, false)
                                .getIIntentReceiver();
            }
        }
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
@@ -1699,8 +1702,9 @@ class ContextImpl extends Context {
                if (scheduler == null) {
                    scheduler = mMainThread.getHandler();
                }
                rd = new LoadedApk.ReceiverDispatcher(
                        resultReceiver, getOuterContext(), scheduler, null, false).getIIntentReceiver();
                rd = new LoadedApk.ReceiverDispatcher(mMainThread.getApplicationThread(),
                        resultReceiver, getOuterContext(), scheduler, null, false)
                                .getIIntentReceiver();
            }
        }
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
@@ -1802,7 +1806,7 @@ class ContextImpl extends Context {
                if (scheduler == null) {
                    scheduler = mMainThread.getHandler();
                }
                rd = new LoadedApk.ReceiverDispatcher(
                rd = new LoadedApk.ReceiverDispatcher(mMainThread.getApplicationThread(),
                        receiver, context, scheduler, null, true).getIIntentReceiver();
            }
        }
+7 −5
Original line number Diff line number Diff line
@@ -1598,8 +1598,8 @@ public final class LoadedApk {
                }
            }
            if (rd == null) {
                rd = new ReceiverDispatcher(r, context, handler,
                        instrumentation, registered);
                rd = new ReceiverDispatcher(mActivityThread.getApplicationThread(), r, context,
                        handler, instrumentation, registered);
                if (registered) {
                    if (map == null) {
                        map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
@@ -1714,6 +1714,7 @@ public final class LoadedApk {
            }
        }

        final IApplicationThread mAppThread;
        final IIntentReceiver.Stub mIIntentReceiver;
        @UnsupportedAppUsage
        final BroadcastReceiver mReceiver;
@@ -1736,7 +1737,7 @@ public final class LoadedApk {
                    boolean ordered, boolean sticky, int sendingUser) {
                super(resultCode, resultData, resultExtras,
                        mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED, ordered,
                        sticky, mIIntentReceiver.asBinder(), sendingUser, intent.getFlags());
                        sticky, mAppThread.asBinder(), sendingUser, intent.getFlags());
                mCurIntent = intent;
                mOrdered = ordered;
            }
@@ -1811,13 +1812,14 @@ public final class LoadedApk {
            }
        }

        ReceiverDispatcher(BroadcastReceiver receiver, Context context,
                Handler activityThread, Instrumentation instrumentation,
        ReceiverDispatcher(IApplicationThread appThread, BroadcastReceiver receiver,
                Context context, Handler activityThread, Instrumentation instrumentation,
                boolean registered) {
            if (activityThread == null) {
                throw new NullPointerException("Handler must not be null");
            }

            mAppThread = appThread;
            mIIntentReceiver = new InnerReceiver(this, !registered);
            mReceiver = receiver;
            mContext = context;
+20 −10
Original line number Diff line number Diff line
@@ -3263,13 +3263,20 @@ public class ActivityManagerService extends IActivityManager.Stub
        if (thread == null) {
            return null;
        }
        return getRecordForAppLOSP(thread.asBinder());
    }
    @GuardedBy(anyOf = {"this", "mProcLock"})
    ProcessRecord getRecordForAppLOSP(IBinder threadBinder) {
        if (threadBinder == null) {
            return null;
        }
        ProcessRecord record = mProcessList.getLRURecordForAppLOSP(thread);
        ProcessRecord record = mProcessList.getLRURecordForAppLOSP(threadBinder);
        if (record != null) return record;
        // Validation: if it isn't in the LRU list, it shouldn't exist, but let's
        // double-check that.
        final IBinder threadBinder = thread.asBinder();
        final ArrayMap<String, SparseArray<ProcessRecord>> pmap =
                mProcessList.getProcessNamesLOSP().getMap();
        for (int i = pmap.size()-1; i >= 0; i--) {
@@ -13342,7 +13349,7 @@ public class ActivityManagerService extends IActivityManager.Stub
                    final BroadcastRecord r = rl.curBroadcast;
                    if (r != null) {
                        final boolean doNext = r.queue.finishReceiverLocked(
                                receiver.asBinder(), r.resultCode, r.resultData, r.resultExtras,
                                rl.app, r.resultCode, r.resultData, r.resultExtras,
                                r.resultAbort, false);
                        if (doNext) {
                            doTrim = true;
@@ -14510,9 +14517,9 @@ public class ActivityManagerService extends IActivityManager.Stub
        }
    }
    public void finishReceiver(IBinder who, int resultCode, String resultData,
    public void finishReceiver(IBinder caller, int resultCode, String resultData,
            Bundle resultExtras, boolean resultAbort, int flags) {
        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Finish receiver: " + who);
        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Finish receiver: " + caller);
        // Refuse possible leaked file descriptors
        if (resultExtras != null && resultExtras.hasFileDescriptors()) {
@@ -14521,12 +14528,15 @@ public class ActivityManagerService extends IActivityManager.Stub
        final long origId = Binder.clearCallingIdentity();
        try {
            boolean doNext = false;
            BroadcastRecord r;
            BroadcastQueue queue;
            synchronized(this) {
                queue = broadcastQueueForFlags(flags);
                doNext = queue.finishReceiverLocked(who, resultCode,
                final ProcessRecord callerApp = getRecordForAppLOSP(caller);
                if (callerApp == null) {
                    Slog.w(TAG, "finishReceiver: no app for " + caller);
                    return;
                }
                final BroadcastQueue queue = broadcastQueueForFlags(flags);
                queue.finishReceiverLocked(callerApp, resultCode,
                        resultData, resultExtras, resultAbort, true);
                // updateOomAdjLocked() will be done here
                trimApplicationsLocked(false, OomAdjuster.OOM_ADJ_REASON_FINISH_RECEIVER);
+3 −6
Original line number Diff line number Diff line
@@ -83,17 +83,14 @@ public abstract class BroadcastQueue {
    public abstract void enqueueBroadcastLocked(@NonNull BroadcastRecord r);

    /**
     * Signal delivered back from a {@link BroadcastReceiver} to indicate that
     * it's finished processing the current broadcast being dispatched to it.
     * Signal delivered back from the given process to indicate that it's
     * finished processing the current broadcast being dispatched to it.
     * <p>
     * If this signal isn't delivered back in a timely fashion, we assume the
     * receiver has somehow wedged and we trigger an ANR.
     *
     * @param receiver the value to match against
     *            {@link BroadcastRecord#receiver} to identify the caller.
     */
    @GuardedBy("mService")
    public abstract boolean finishReceiverLocked(@NonNull IBinder receiver, int resultCode,
    public abstract boolean finishReceiverLocked(@NonNull ProcessRecord app, int resultCode,
            @Nullable String resultData, @Nullable Bundle resultExtras, boolean resultAbort,
            boolean waitForServices);

+11 −16
Original line number Diff line number Diff line
@@ -370,7 +370,6 @@ public class BroadcastQueueImpl extends BroadcastQueue {
            return;
        }

        r.receiver = thread.asBinder();
        r.curApp = app;
        final ProcessReceiverRecord prr = app.mReceivers;
        prr.addCurReceiver(r);
@@ -408,7 +407,6 @@ public class BroadcastQueueImpl extends BroadcastQueue {
            if (!started) {
                if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                        "Process cur broadcast " + r + ": NOT STARTED!");
                r.receiver = null;
                r.curApp = null;
                prr.removeCurReceiver(r);
            }
@@ -525,16 +523,16 @@ public class BroadcastQueueImpl extends BroadcastQueue {
        mBroadcastsScheduled = true;
    }

    public BroadcastRecord getMatchingOrderedReceiver(IBinder receiver) {
    public BroadcastRecord getMatchingOrderedReceiver(ProcessRecord app) {
        BroadcastRecord br = mDispatcher.getActiveBroadcastLocked();
        if (br == null) {
            Slog.w(TAG_BROADCAST, "getMatchingOrderedReceiver [" + mQueueName
                    + "] no active broadcast");
            return null;
        }
        if (br.receiver != receiver) {
        if (br.curApp != app) {
            Slog.w(TAG_BROADCAST, "getMatchingOrderedReceiver [" + mQueueName
                    + "] active broadcast " + br.receiver + " doesn't match " + receiver);
                    + "] active broadcast " + br.curApp + " doesn't match " + app);
            return null;
        }
        return br;
@@ -565,9 +563,9 @@ public class BroadcastQueueImpl extends BroadcastQueue {
        }, msgToken, (r.receiverTime + mConstants.ALLOW_BG_ACTIVITY_START_TIMEOUT));
    }

    public boolean finishReceiverLocked(IBinder receiver, int resultCode,
    public boolean finishReceiverLocked(ProcessRecord app, int resultCode,
            String resultData, Bundle resultExtras, boolean resultAbort, boolean waitForServices) {
        final BroadcastRecord r = getMatchingOrderedReceiver(receiver);
        final BroadcastRecord r = getMatchingOrderedReceiver(app);
        if (r != null) {
            return finishReceiverLocked(r, resultCode,
                    resultData, resultExtras, resultAbort, waitForServices);
@@ -648,7 +646,6 @@ public class BroadcastQueueImpl extends BroadcastQueue {
            }
        }

        r.receiver = null;
        r.intent.setComponent(null);
        if (r.curApp != null && r.curApp.mReceivers.hasCurReceiver(r)) {
            r.curApp.mReceivers.removeCurReceiver(r);
@@ -806,7 +803,6 @@ public class BroadcastQueueImpl extends BroadcastQueue {
        // don't want to touch the fields that keep track of the current
        // state of ordered broadcasts.
        if (ordered) {
            r.receiver = filter.receiverList.receiver.asBinder();
            r.curFilter = filter;
            filter.receiverList.curBroadcast = r;
            r.state = BroadcastRecord.CALL_IN_RECEIVE;
@@ -870,7 +866,6 @@ public class BroadcastQueueImpl extends BroadcastQueue {
            }
            // And BroadcastRecord state related to ordered delivery, if appropriate
            if (ordered) {
                r.receiver = null;
                r.curFilter = null;
                filter.receiverList.curBroadcast = null;
            }
@@ -1290,12 +1285,13 @@ public class BroadcastQueueImpl extends BroadcastQueue {
                    + filter + ": " + r);
            r.mIsReceiverAppRunning = true;
            deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx);
            if (r.receiver == null || !r.ordered) {
            if ((r.curReceiver == null && r.curFilter == null) || !r.ordered) {
                // The receiver has already finished, so schedule to
                // process the next one.
                if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Quick finishing ["
                        + mQueueName + "]: ordered="
                        + r.ordered + " receiver=" + r.receiver);
                        + mQueueName + "]: ordered=" + r.ordered
                        + " curFilter=" + r.curFilter
                        + " curReceiver=" + r.curReceiver);
                r.state = BroadcastRecord.IDLE;
                scheduleBroadcastsLocked();
            } else {
@@ -1347,7 +1343,6 @@ public class BroadcastQueueImpl extends BroadcastQueue {
                    "Skipping delivery of ordered [" + mQueueName + "] "
                    + r + " for reason described above");
            r.delivery[recIdx] = BroadcastRecord.DELIVERY_SKIPPED;
            r.receiver = null;
            r.curFilter = null;
            r.state = BroadcastRecord.IDLE;
            r.manifestSkipCount++;
@@ -1637,8 +1632,8 @@ public class BroadcastQueueImpl extends BroadcastQueue {
        final boolean debugging = (r.curApp != null && r.curApp.isDebugging());

        long timeoutDurationMs = now - r.receiverTime;
        Slog.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver
                + ", started " + timeoutDurationMs + "ms ago");
        Slog.w(TAG, "Timeout of broadcast " + r + " - curFilter=" + r.curFilter + " curReceiver="
                + r.curReceiver + ", started " + timeoutDurationMs + "ms ago");
        r.receiverTime = now;
        if (!debugging) {
            r.anrCount++;
Loading