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

Commit a6471a74 authored by Jeff Sharkey's avatar Jeff Sharkey Committed by Android (Google) Code Review
Browse files

Merge "Revert the batching code from the modern queue"

parents 432a04f4 0c76f06e
Loading
Loading
Loading
Loading
+0 −12
Original line number Diff line number Diff line
@@ -236,15 +236,6 @@ public class BroadcastConstants {
    private static final int DEFAULT_MAX_HISTORY_SUMMARY_SIZE =
            ActivityManager.isLowRamDeviceStatic() ? 256 : 1024;

    /**
     * For {@link BroadcastQueueModernImpl}: Maximum number of broadcast receivers to process in a
     * single synchronized block.  Up to this many messages may be dispatched in a single binder
     * call.  Set this to 1 (or zero) for pre-batch behavior.
     */
    public int MAX_BROADCAST_BATCH_SIZE = DEFAULT_MAX_BROADCAST_BATCH_SIZE;
    private static final String KEY_MAX_BROADCAST_BATCH_SIZE = "bcast_max_batch_size";
    private static final int DEFAULT_MAX_BROADCAST_BATCH_SIZE = 1;

    // Settings override tracking for this instance
    private String mSettingsKey;
    private SettingsObserver mSettingsObserver;
@@ -382,8 +373,6 @@ public class BroadcastConstants {
                    DEFAULT_MAX_HISTORY_COMPLETE_SIZE);
            MAX_HISTORY_SUMMARY_SIZE = getDeviceConfigInt(KEY_MAX_HISTORY_SUMMARY_SIZE,
                    DEFAULT_MAX_HISTORY_SUMMARY_SIZE);
            MAX_BROADCAST_BATCH_SIZE = getDeviceConfigInt(KEY_MAX_BROADCAST_BATCH_SIZE,
                    DEFAULT_MAX_BROADCAST_BATCH_SIZE);
        }
    }

@@ -429,7 +418,6 @@ public class BroadcastConstants {
                    MAX_CONSECUTIVE_URGENT_DISPATCHES).println();
            pw.print(KEY_MAX_CONSECUTIVE_NORMAL_DISPATCHES,
                    MAX_CONSECUTIVE_NORMAL_DISPATCHES).println();
            pw.print(KEY_MAX_BROADCAST_BATCH_SIZE, MAX_BROADCAST_BATCH_SIZE).println();
            pw.decreaseIndent();
            pw.println();
        }
+6 −15
Original line number Diff line number Diff line
@@ -76,7 +76,6 @@ import android.util.Slog;
import android.util.SparseIntArray;
import android.util.proto.ProtoOutputStream;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.TimeoutRecord;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.LocalServices;
@@ -190,14 +189,6 @@ public class BroadcastQueueImpl extends BroadcastQueue {
        }
    }

    /**
     * This single object allows the queue to dispatch receivers using scheduleReceiverList
     * without constantly allocating new ReceiverInfo objects or ArrayLists.  This queue
     * implementation is known to have a maximum size of one entry.
     */
    @VisibleForTesting
    final BroadcastReceiverBatch mReceiverBatch = new BroadcastReceiverBatch(1);

    BroadcastQueueImpl(ActivityManagerService service, Handler handler,
            String name, BroadcastConstants constants, boolean allowDelayBehindServices,
            int schedGroup) {
@@ -402,13 +393,13 @@ public class BroadcastQueueImpl extends BroadcastQueue {
            mService.notifyPackageUse(r.intent.getComponent().getPackageName(),
                                      PackageManager.NOTIFY_PACKAGE_USE_BROADCAST_RECEIVER);
            final boolean assumeDelivered = false;
            thread.scheduleReceiverList(mReceiverBatch.manifestReceiver(
            thread.scheduleReceiver(
                    prepareReceiverIntent(r.intent, r.curFilteredExtras),
                    r.curReceiver, null /* compatInfo (unused but need to keep method signature) */,
                    r.resultCode, r.resultData, r.resultExtras, r.ordered, assumeDelivered,
                    r.userId, r.shareIdentity ? r.callingUid : Process.INVALID_UID,
                    r.shareIdentity ? r.callerPackage : null,
                    app.mState.getReportedProcState()));
                    app.mState.getReportedProcState(),
                    r.shareIdentity ? r.callerPackage : null);
            if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                    "Process cur broadcast " + r + " DELIVERED for app " + app);
            started = true;
@@ -756,12 +747,12 @@ public class BroadcastQueueImpl extends BroadcastQueue {
                // correctly ordered with other one-way calls.
                try {
                    final boolean assumeDelivered = !ordered;
                    thread.scheduleReceiverList(mReceiverBatch.registeredReceiver(
                    thread.scheduleRegisteredReceiver(
                            receiver, intent, resultCode,
                            data, extras, ordered, sticky, assumeDelivered, sendingUser,
                            app.mState.getReportedProcState(),
                            shareIdentity ? callingUid : Process.INVALID_UID,
                            shareIdentity ? callingPackage : null,
                            app.mState.getReportedProcState()));
                            shareIdentity ? callingPackage : null);
                } catch (RemoteException ex) {
                    // Failed to call into the process. It's either dying or wedged. Kill it gently.
                    synchronized (mService) {
+64 −226
Original line number Diff line number Diff line
@@ -145,11 +145,6 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
        // We configure runnable size only once at boot; it'd be too complex to
        // try resizing dynamically at runtime
        mRunning = new BroadcastProcessQueue[mConstants.getMaxRunningQueues()];

        // Set up the statistics for batched broadcasts.
        final int batchSize = mConstants.MAX_BROADCAST_BATCH_SIZE;
        mReceiverBatch = new BroadcastReceiverBatch(batchSize);
        Slog.i(TAG, "maximum broadcast batch size " + batchSize);
    }

    /**
@@ -219,15 +214,6 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
    private final BroadcastConstants mFgConstants;
    private final BroadcastConstants mBgConstants;

    /**
     * The sole instance of BroadcastReceiverBatch that is used by scheduleReceiverWarmLocked().
     * The class is not a true singleton but only one instance is needed for the broadcast queue.
     * Although this is guarded by mService, it should never be accessed by any other function.
     */
    @VisibleForTesting
    @GuardedBy("mService")
    final BroadcastReceiverBatch mReceiverBatch;

    /**
     * Timestamp when last {@link #testAllProcessQueues} failure was observed;
     * used for throttling log messages.
@@ -248,19 +234,10 @@ class BroadcastQueueModernImpl extends BroadcastQueue {

    private void enqueueFinishReceiver(@NonNull BroadcastProcessQueue queue,
            @DeliveryState int deliveryState, @NonNull String reason) {
        enqueueFinishReceiver(queue, queue.getActive(), queue.getActiveIndex(),
                deliveryState, reason);
    }

    private void enqueueFinishReceiver(@NonNull BroadcastProcessQueue queue,
            @NonNull BroadcastRecord r, int index,
            @DeliveryState int deliveryState, @NonNull String reason) {
        final SomeArgs args = SomeArgs.obtain();
        args.arg1 = queue;
        args.argi1 = deliveryState;
        args.arg2 = reason;
        args.arg3 = r;
        args.argi2 = index;
        mLocalHandler.sendMessage(Message.obtain(mLocalHandler, MSG_FINISH_RECEIVER, args));
    }

@@ -308,10 +285,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
                    final BroadcastProcessQueue queue = (BroadcastProcessQueue) args.arg1;
                    final int deliveryState = args.argi1;
                    final String reason = (String) args.arg2;
                    final BroadcastRecord r = (BroadcastRecord) args.arg3;
                    final int index = args.argi2;
                    args.recycle();
                    finishReceiverLocked(queue, deliveryState, reason, r, index);
                    finishReceiverActiveLocked(queue, deliveryState, reason);
                }
                return true;
            }
@@ -767,7 +742,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
            return;
        }

        if (maybeSkipReceiver(queue, null, r, index)) {
        if (maybeSkipReceiver(queue, r, index)) {
            mRunningColdStart = null;
            return;
        }
@@ -811,22 +786,20 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
    @GuardedBy("mService")
    private void scheduleReceiverWarmLocked(@NonNull BroadcastProcessQueue queue) {
        checkState(queue.isActive(), "isActive");
        BroadcastReceiverBatch batch = mReceiverBatch;
        batch.reset();

        while (collectReceiverList(queue, batch)) {
            if (batch.isFull()) {
                break;
            }
            if (!shouldContinueScheduling(queue)) {
                break;
             }
            if (queue.isEmpty()) {
                break;
        final BroadcastRecord r = queue.getActive();
        final int index = queue.getActiveIndex();

        if (r.terminalCount == 0) {
            r.dispatchTime = SystemClock.uptimeMillis();
            r.dispatchRealTime = SystemClock.elapsedRealtime();
            r.dispatchClockTime = System.currentTimeMillis();
        }
            queue.makeActiveNextPending();

        if (maybeSkipReceiver(queue, r, index)) {
            return;
        }
        processReceiverList(queue, batch);
        dispatchReceivers(queue, r, index);
    }

    /**
@@ -834,14 +807,10 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
     * skipped (and therefore no more work is required).
     */
    private boolean maybeSkipReceiver(@NonNull BroadcastProcessQueue queue,
            @Nullable BroadcastReceiverBatch batch, @NonNull BroadcastRecord r, int index) {
            @NonNull BroadcastRecord r, int index) {
        final String reason = shouldSkipReceiver(queue, r, index);
        if (reason != null) {
            if (batch == null) {
                enqueueFinishReceiver(queue, r, index, BroadcastRecord.DELIVERY_SKIPPED, reason);
            } else {
                batch.finish(r, index, BroadcastRecord.DELIVERY_SKIPPED, reason);
            }
            enqueueFinishReceiver(queue, BroadcastRecord.DELIVERY_SKIPPED, reason);
            return true;
        }
        return false;
@@ -883,147 +852,6 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
        return null;
    }

    /**
     * Collect receivers into a list, to be dispatched in a single receiver list call.  Return
     * true if remaining receivers in the queue should be examined, and false if the current list
     * is complete.
     */
    private boolean collectReceiverList(@NonNull BroadcastProcessQueue queue,
            @NonNull BroadcastReceiverBatch batch) {
        final ProcessRecord app = queue.app;
        final BroadcastRecord r = queue.getActive();
        final int index = queue.getActiveIndex();
        final Object receiver = r.receivers.get(index);
        final Intent receiverIntent = r.getReceiverIntent(receiver);

        if (r.terminalCount == 0) {
            r.dispatchTime = SystemClock.uptimeMillis();
            r.dispatchRealTime = SystemClock.elapsedRealtime();
            r.dispatchClockTime = System.currentTimeMillis();
        }
        if (maybeSkipReceiver(queue, batch, r, index)) {
            return true;
        }

        final IApplicationThread thread = app.getOnewayThread();
        if (thread == null) {
            batch.finish(r, index, BroadcastRecord.DELIVERY_FAILURE, "missing IApplicationThread");
            return true;
        }

        final boolean assumeDelivered = isAssumedDelivered(r, index);
        if (receiver instanceof BroadcastFilter) {
            batch.schedule(((BroadcastFilter) receiver).receiverList.receiver,
                    receiverIntent, r.resultCode, r.resultData, r.resultExtras,
                    r.ordered, r.initialSticky, assumeDelivered, r.userId,
                    r.shareIdentity ? r.callingUid : Process.INVALID_UID,
                    r.shareIdentity ? r.callerPackage : null,
                    app.mState.getReportedProcState(), r, index);
            // TODO: consider making registered receivers of unordered
            // broadcasts report results to detect ANRs
            if (assumeDelivered) {
                batch.success(r, index, BroadcastRecord.DELIVERY_DELIVERED, "assuming delivered");
                return true;
            }
        } else {
            batch.schedule(receiverIntent, ((ResolveInfo) receiver).activityInfo,
                    null, r.resultCode, r.resultData, r.resultExtras, r.ordered, assumeDelivered,
                    r.userId, r.shareIdentity ? r.callingUid : Process.INVALID_UID,
                    r.shareIdentity ? r.callerPackage : null,
                    app.mState.getReportedProcState(), r, index);
            if (assumeDelivered) {
                batch.success(r, index, BroadcastRecord.DELIVERY_DELIVERED, "assuming delivered");
                return true;
            }
        }

        return false;
    }

    /**
     * Process the information in a BroadcastReceiverBatch.  Elements in the finish and success
     * lists are sent to enqueueFinishReceiver().  Elements in the receivers list are transmitted
     * to the target in a single binder call.
     */
    private void processReceiverList(@NonNull BroadcastProcessQueue queue,
            @NonNull BroadcastReceiverBatch batch) {
        // Transmit the receiver list.
        final ProcessRecord app = queue.app;
        final IApplicationThread thread = app.getOnewayThread();

        batch.recordBatch(thread instanceof SameProcessApplicationThread);

        // Mark all the receivers that were discarded.  None of these have actually been scheduled.
        for (int i = 0; i < batch.finished().size(); i++) {
            final var finish = batch.finished().get(i);
            enqueueFinishReceiver(queue, finish.r, finish.index, finish.deliveryState,
                    finish.reason);
        }
        // Prepare for delivery of all receivers that are about to be scheduled.
        for (int i = 0; i < batch.cookies().size(); i++) {
            final var cookie = batch.cookies().get(i);
            prepareToDispatch(queue, cookie.r, cookie.index);
        }

        // Notify on dispatch.  Note that receiver/cookies are recorded only if the thread is
        // non-null and the list will therefore be sent.
        for (int i = 0; i < batch.cookies().size(); i++) {
            // Cookies and receivers are 1:1
            final var cookie = batch.cookies().get(i);
            final BroadcastRecord r = cookie.r;
            final int index = cookie.index;
            final Object receiver = r.receivers.get(index);

            if (r.shareIdentity) {
                mService.mPackageManagerInt.grantImplicitAccess(r.userId, r.intent,
                        UserHandle.getAppId(app.uid), r.callingUid, true);
            }
            if (receiver instanceof BroadcastFilter) {
                notifyScheduleRegisteredReceiver(queue.app, r, (BroadcastFilter) receiver);
            } else {
                notifyScheduleReceiver(queue.app, r, (ResolveInfo) receiver);
            }
        }

        // Transmit the enqueued receivers.  The thread cannot be null because the lock has been
        // held since collectReceiverList(), which will not add any receivers if the thread is null.
        boolean remoteFailed = false;
        if (batch.receivers().size()  > 0) {
            try {
                thread.scheduleReceiverList(batch.receivers());
            } catch (RemoteException e) {
                // Log the failure of the first receiver in the list.  Note that there must be at
                // least one receiver/cookie to reach this point in the code, which means
                // cookie[0] is a valid element.
                final var info = batch.cookies().get(0);
                final BroadcastRecord r = info.r;
                final int index = info.index;
                final Object receiver = r.receivers.get(index);
                final String msg = "Failed to schedule " + r + " to " + receiver
                                   + " via " + app + ": " + e;
                logw(msg);
                app.killLocked("Can't deliver broadcast", ApplicationExitInfo.REASON_OTHER, true);
                remoteFailed = true;
            }
        }

        if (!remoteFailed) {
            // If transmission succeed, report all receivers that are assumed to be delivered.
            for (int i = 0; i < batch.success().size(); i++) {
                final var finish = batch.success().get(i);
                enqueueFinishReceiver(queue, finish.r, finish.index, finish.deliveryState,
                        finish.reason);
            }
        } else {
            // If transmission failed, fail all receivers in the list.
            for (int i = 0; i < batch.cookies().size(); i++) {
                final var cookie = batch.cookies().get(i);
                enqueueFinishReceiver(queue, cookie.r, cookie.index,
                        BroadcastRecord.DELIVERY_FAILURE, "remote app");
            }
        }
    }

    /**
     * Return true if this receiver should be assumed to have been delivered.
     */
@@ -1035,7 +863,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
    /**
     * A receiver is about to be dispatched.  Start ANR timers, if necessary.
     */
    private void prepareToDispatch(@NonNull BroadcastProcessQueue queue,
    private void dispatchReceivers(@NonNull BroadcastProcessQueue queue,
            @NonNull BroadcastRecord r, int index) {
        final ProcessRecord app = queue.app;
        final Object receiver = r.receivers.get(index);
@@ -1074,6 +902,47 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
        if (DEBUG_BROADCAST) logv("Scheduling " + r + " to warm " + app);
        setDeliveryState(queue, app, r, index, receiver, BroadcastRecord.DELIVERY_SCHEDULED,
                "scheduleReceiverWarmLocked");

        final Intent receiverIntent = r.getReceiverIntent(receiver);
        final IApplicationThread thread = app.getOnewayThread();
        if (thread != null) {
            try {
                if (receiver instanceof BroadcastFilter) {
                    notifyScheduleRegisteredReceiver(app, r, (BroadcastFilter) receiver);
                    thread.scheduleRegisteredReceiver(
                        ((BroadcastFilter) receiver).receiverList.receiver,
                        receiverIntent, r.resultCode, r.resultData, r.resultExtras,
                        r.ordered, r.initialSticky, assumeDelivered, r.userId,
                        app.mState.getReportedProcState(),
                        r.shareIdentity ? r.callingUid : Process.INVALID_UID,
                        r.shareIdentity ? r.callerPackage : null);
                    // TODO: consider making registered receivers of unordered
                    // broadcasts report results to detect ANRs
                    if (assumeDelivered) {
                        enqueueFinishReceiver(queue, BroadcastRecord.DELIVERY_DELIVERED,
                                "assuming delivered");
                    }
                } else {
                    notifyScheduleReceiver(app, r, (ResolveInfo) receiver);
                    thread.scheduleReceiver(receiverIntent, ((ResolveInfo) receiver).activityInfo,
                            null, r.resultCode, r.resultData, r.resultExtras, r.ordered,
                            assumeDelivered, r.userId,
                            app.mState.getReportedProcState(),
                            r.shareIdentity ? r.callingUid : Process.INVALID_UID,
                            r.shareIdentity ? r.callerPackage : null);
                }
            } catch (RemoteException e) {
                final String msg = "Failed to schedule " + r + " to " + receiver
                        + " via " + app + ": " + e;
                logw(msg);
                app.killLocked("Can't deliver broadcast", ApplicationExitInfo.REASON_OTHER,
                        ApplicationExitInfo.SUBREASON_UNDELIVERED_BROADCAST, true);
                enqueueFinishReceiver(queue, BroadcastRecord.DELIVERY_FAILURE, "remote app");
            }
        } else {
            enqueueFinishReceiver(queue, BroadcastRecord.DELIVERY_FAILURE,
                    "missing IApplicationThread");
        }
    }

    /**
@@ -1093,13 +962,13 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
            }
            try {
                final boolean assumeDelivered = true;
                thread.scheduleReceiverList(mReceiverBatch.registeredReceiver(
                thread.scheduleRegisteredReceiver(
                        r.resultTo, r.intent,
                        r.resultCode, r.resultData, r.resultExtras, false, r.initialSticky,
                        assumeDelivered, r.userId,
                        app.mState.getReportedProcState(),
                        r.shareIdentity ? r.callingUid : Process.INVALID_UID,
                        r.shareIdentity ? r.callerPackage : null,
                        app.mState.getReportedProcState()));
                        r.shareIdentity ? r.callerPackage : null);
            } catch (RemoteException e) {
                final String msg = "Failed to schedule result of " + r + " via " + app + ": " + e;
                logw(msg);
@@ -1187,33 +1056,20 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
            return false;
        }

        final BroadcastRecord r = queue.getActive();
        final int index = queue.getActiveIndex();
        return finishReceiverLocked(queue, deliveryState, reason, r, index);
    }

    private boolean finishReceiverLocked(@NonNull BroadcastProcessQueue queue,
            @DeliveryState int deliveryState, @NonNull String reason,
            BroadcastRecord r, int index) {
        if (!queue.isActive()) {
            logw("Ignoring finish; no active broadcast for " + queue);
            return false;
        }

        final int cookie = traceBegin("finishReceiver");
        final ProcessRecord app = queue.app;
        final BroadcastRecord r = queue.getActive();
        final int index = queue.getActiveIndex();
        final Object receiver = r.receivers.get(index);

        setDeliveryState(queue, app, r, index, receiver, deliveryState, reason);

        final boolean early = r != queue.getActive() || index != queue.getActiveIndex();

        if (deliveryState == BroadcastRecord.DELIVERY_TIMEOUT) {
            r.anrCount++;
            if (app != null && !app.isDebugging()) {
                mService.appNotResponding(queue.app, TimeoutRecord.forBroadcastReceiver(r.intent));
            }
        } else if (!early) {
        } else {
            mLocalHandler.removeMessages(MSG_DELIVERY_TIMEOUT_SOFT, queue);
            mLocalHandler.removeMessages(MSG_DELIVERY_TIMEOUT_HARD, queue);
        }
@@ -1221,13 +1077,6 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
        // Given that a receiver just finished, check if the "waitingFor" conditions are met.
        checkAndRemoveWaitingFor();

        if (early) {
            // This is an early receiver that was transmitted as part of a group.  The delivery
            // state has been updated but don't make any further decisions.
            traceEnd(cookie);
            return false;
        }

        final boolean res = shouldContinueScheduling(queue);
        if (res) {
            // We're on a roll; move onto the next broadcast for this process
@@ -1980,17 +1829,6 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
        ipw.decreaseIndent();
        ipw.println();

        ipw.println("Batch statistics:");
        ipw.increaseIndent();
        {
            final var stats = mReceiverBatch.getStatistics();
            ipw.println("Finished         " + Arrays.toString(stats.finish));
            ipw.println("DispatchedLocal  " + Arrays.toString(stats.local));
            ipw.println("DispatchedRemote " + Arrays.toString(stats.remote));
        }
        ipw.decreaseIndent();
        ipw.println();

        if (dumpConstants) {
            mConstants.dump(ipw);
        }
+0 −357

File deleted.

Preview size limit exceeded, changes collapsed.

+0 −6
Original line number Diff line number Diff line
@@ -120,8 +120,6 @@ final class BroadcastRecord extends Binder {
    @UptimeMillisLong       long finishTime;         // when broadcast finished
    final @UptimeMillisLong long[] scheduledTime;    // when each receiver was scheduled
    final @UptimeMillisLong long[] terminalTime;     // when each receiver was terminal
    final                   int[] transmitGroup;     // the batch group for each receiver
    final                   int[] transmitOrder;     // the position of the receiver in the group
    final boolean timeoutExempt;  // true if this broadcast is not subject to receiver timeouts
    int resultCode;         // current result code value.
    @Nullable String resultData;      // current result data value.
@@ -400,8 +398,6 @@ final class BroadcastRecord extends Binder {
        blockedUntilTerminalCount = calculateBlockedUntilTerminalCount(receivers, _serialized);
        scheduledTime = new long[delivery.length];
        terminalTime = new long[delivery.length];
        transmitGroup = new int[delivery.length];
        transmitOrder = new int[delivery.length];
        resultToApp = _resultToApp;
        resultTo = _resultTo;
        resultCode = _resultCode;
@@ -457,8 +453,6 @@ final class BroadcastRecord extends Binder {
        blockedUntilTerminalCount = from.blockedUntilTerminalCount;
        scheduledTime = from.scheduledTime;
        terminalTime = from.terminalTime;
        transmitGroup = from.transmitGroup;
        transmitOrder = from.transmitOrder;
        resultToApp = from.resultToApp;
        resultTo = from.resultTo;
        enqueueTime = from.enqueueTime;
Loading