diff options
6 files changed, 199 insertions, 871 deletions
diff --git a/services/core/java/com/android/server/am/BroadcastConstants.java b/services/core/java/com/android/server/am/BroadcastConstants.java index fe5888df238e..f5d1c106705d 100644 --- a/services/core/java/com/android/server/am/BroadcastConstants.java +++ b/services/core/java/com/android/server/am/BroadcastConstants.java @@ -236,15 +236,6 @@ public class BroadcastConstants { private static final int DEFAULT_MAX_HISTORY_SUMMARY_SIZE = ActivityManager.isLowRamDeviceStatic() ? 25 : 300; - /** - * 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(); } diff --git a/services/core/java/com/android/server/am/BroadcastQueueImpl.java b/services/core/java/com/android/server/am/BroadcastQueueImpl.java index c07ef1d12c91..3f4749f169b7 100644 --- a/services/core/java/com/android/server/am/BroadcastQueueImpl.java +++ b/services/core/java/com/android/server/am/BroadcastQueueImpl.java @@ -73,7 +73,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; @@ -187,14 +186,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) { @@ -399,13 +390,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; @@ -746,12 +737,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) { diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java index d4d6eb202c57..a517b4d6857d 100644 --- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java +++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java @@ -143,11 +143,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); } /** @@ -218,15 +213,6 @@ class BroadcastQueueModernImpl extends BroadcastQueue { 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. */ @@ -246,19 +232,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)); } @@ -306,10 +283,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; } @@ -765,7 +740,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue { return; } - if (maybeSkipReceiver(queue, null, r, index)) { + if (maybeSkipReceiver(queue, r, index)) { mRunningColdStart = null; return; } @@ -806,22 +781,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; - } - queue.makeActiveNextPending(); + 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(); + } + + if (maybeSkipReceiver(queue, r, index)) { + return; } - processReceiverList(queue, batch); + dispatchReceivers(queue, r, index); } /** @@ -829,14 +802,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; @@ -879,147 +848,6 @@ class BroadcastQueueModernImpl extends BroadcastQueue { } /** - * 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. */ private boolean isAssumedDelivered(BroadcastRecord r, int index) { @@ -1030,7 +858,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); @@ -1069,6 +897,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"); + } } /** @@ -1088,13 +957,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); @@ -1182,33 +1051,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); } @@ -1216,13 +1072,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 @@ -1970,17 +1819,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); } diff --git a/services/core/java/com/android/server/am/BroadcastReceiverBatch.java b/services/core/java/com/android/server/am/BroadcastReceiverBatch.java deleted file mode 100644 index 63575ba38305..000000000000 --- a/services/core/java/com/android/server/am/BroadcastReceiverBatch.java +++ /dev/null @@ -1,357 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.am; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.app.ReceiverInfo; -import android.content.IIntentReceiver; -import android.content.Intent; -import android.content.pm.ActivityInfo; -import android.content.res.CompatibilityInfo; -import android.os.Bundle; - -import com.android.internal.annotations.VisibleForTesting; - -import java.util.ArrayList; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * A batch of receiver instructions. This includes a list of finish requests and a list of - * receivers. The instructions are for a single queue. It is constructed and consumed in a single - * call to {@link BroadcastQueueModernImpl#scheduleReceiverWarmLocked}. The list size is bounded by - * {@link BroadcastConstants#MAX_BROADCAST_BATCH_SIZE}. Because this class is ephemeral and its use - * is bounded, it is pre-allocated to avoid allocating new objects every time it is used. - * - * The {@link #single} methods support the use of this class in {@link BroadcastQueueImpl}. These - * methods simplify the use of {@link IApplicationThread#scheduleReceiverList} as a replacement - * for scheduleReceiver and scheduleRegisteredReceiver. - * - * This class is designed to be allocated once and constantly reused (call {@link #reset} between - * uses). Objects needed by the instance are kept in a pool - all object allocation occurs when - * the instance is created, and no allocation occurs thereafter. However, if the variable - * mDeepReceiverCopy is set true (it is false by default) then the method {@link #receivers} always - * returns newly allocated objects. This is required for mock testing. - * - * This class is not thread-safe. Instances must be protected by the caller. - * @hide - */ -final class BroadcastReceiverBatch { - - /** - * If this is true then receivers() returns a deep copy of the ReceiveInfo array. If this is - * false, receivers() returns a reference to the array. A deep copy is needed only for the - * broadcast queue mocking tests. - */ - @VisibleForTesting - boolean mDeepReceiverCopy = false; - - /** - * A private pool implementation this class. - */ - private static class Pool<T> { - final int size; - final ArrayList<T> pool; - int next; - Pool(int n, @NonNull Class<T> c) { - size = n; - pool = new ArrayList<>(size); - try { - for (int i = 0; i < size; i++) { - pool.add(c.getDeclaredConstructor().newInstance()); - } - } catch (Exception e) { - // This class is only used locally. Turn any exceptions into something fatal. - throw new RuntimeException(e); - } - } - T next() { - return pool.get(next++); - } - void reset() { - next = 0; - } - } - - /** - * The information needed to finish off a receiver. This is valid only in the context of - * a queue. - */ - static class FinishInfo { - BroadcastRecord r = null; - int index = 0; - int deliveryState = 0; - String reason = null; - FinishInfo set(@Nullable BroadcastRecord r, int index, - int deliveryState, @Nullable String reason) { - this.r = r; - this.index = index; - this.deliveryState = deliveryState; - this.reason = reason; - return this; - } - } - - /** - * The information needed to recreate a receiver info. The broadcast record can be null if the - * caller does not expect to need it later. - */ - static class ReceiverCookie { - BroadcastRecord r = null; - int index = 0; - ReceiverCookie set(@Nullable BroadcastRecord r, int index) { - this.r = r; - this.index = index; - return this; - } - } - - // The object pools. - final int mSize; - private final Pool<ReceiverInfo> receiverPool; - private final Pool<FinishInfo> finishPool; - private final Pool<ReceiverCookie> cookiePool; - - // The accumulated data. The receivers should be an ArrayList to be directly compatible - // with scheduleReceiverList(). The receivers array is not final because a new array must - // be created for every new call to scheduleReceiverList(). - private final ArrayList<ReceiverInfo> mReceivers; - private final ArrayList<ReceiverCookie> mCookies; - private final ArrayList<FinishInfo> mFinished; - // The list of finish records to complete if the binder succeeds or fails. - private final ArrayList<FinishInfo> mSuccess; - - BroadcastReceiverBatch(int size) { - mSize = size; - mReceivers = new ArrayList<>(mSize); - mCookies = new ArrayList<>(mSize); - mFinished = new ArrayList<>(mSize); - mSuccess = new ArrayList<>(mSize); - - receiverPool = new Pool<>(mSize, ReceiverInfo.class); - finishPool = new Pool<>(mSize, FinishInfo.class); - cookiePool = new Pool<>(mSize, ReceiverCookie.class); - mStats = new Statistics(mSize); - reset(); - } - - void reset() { - mReceivers.clear(); - mCookies.clear(); - mFinished.clear(); - mSuccess.clear(); - - receiverPool.reset(); - finishPool.reset(); - cookiePool.reset(); - } - - void finish(@Nullable BroadcastRecord r, int index, - int deliveryState, @Nullable String reason) { - mFinished.add(finishPool.next().set(r, index, deliveryState, reason)); - } - void success(@Nullable BroadcastRecord r, int index, - int deliveryState, @Nullable String reason) { - mSuccess.add(finishPool.next().set(r, index, deliveryState, reason)); - } - // Add a ReceiverInfo for a registered receiver. - void schedule(@Nullable IIntentReceiver receiver, Intent intent, - int resultCode, @Nullable String data, @Nullable Bundle extras, boolean ordered, - boolean sticky, boolean assumeDelivered, int sendingUser, int sendingUid, - @Nullable String sendingPackage, int processState, @Nullable BroadcastRecord r, - int index) { - ReceiverInfo ri = new ReceiverInfo(); - ri.intent = intent; - ri.data = data; - ri.extras = extras; - ri.assumeDelivered = assumeDelivered; - ri.sendingUser = sendingUser; - ri.processState = processState; - ri.resultCode = resultCode; - ri.registered = true; - ri.receiver = receiver; - ri.ordered = ordered; - ri.sticky = sticky; - ri.sendingUid = sendingUid; - ri.sendingPackage = sendingPackage; - - mReceivers.add(ri); - mCookies.add(cookiePool.next().set(r, index)); - } - // Add a ReceiverInfo for a manifest receiver. - void schedule(@Nullable Intent intent, @Nullable ActivityInfo activityInfo, - @Nullable CompatibilityInfo compatInfo, int resultCode, @Nullable String data, - @Nullable Bundle extras, boolean sync, boolean assumeDelivered, int sendingUser, - int sendingUid, @Nullable String sendingPackage, int processState, - @Nullable BroadcastRecord r, int index) { - ReceiverInfo ri = new ReceiverInfo(); - ri.intent = intent; - ri.data = data; - ri.extras = extras; - ri.assumeDelivered = assumeDelivered; - ri.sendingUser = sendingUser; - ri.processState = processState; - ri.resultCode = resultCode; - ri.registered = false; - ri.activityInfo = activityInfo; - ri.compatInfo = compatInfo; - ri.sync = sync; - ri.sendingUid = sendingUid; - ri.sendingPackage = sendingPackage; - mReceivers.add(ri); - mCookies.add(cookiePool.next().set(r, index)); - } - - /** - * Two convenience functions for dispatching a single receiver. The functions start with a - * reset. Then they create the ReceiverInfo array and return it. Statistics are not - * collected. - */ - ArrayList<ReceiverInfo> registeredReceiver(@Nullable IIntentReceiver receiver, - @Nullable Intent intent, int resultCode, @Nullable String data, - @Nullable Bundle extras, boolean ordered, boolean sticky, boolean assumeDelivered, - int sendingUser, int sendingUid, @Nullable String sendingPackage, int processState) { - reset(); - schedule(receiver, intent, resultCode, data, extras, ordered, sticky, assumeDelivered, - sendingUser, sendingUid, sendingPackage, processState, null, 0); - return receivers(); - } - - ArrayList<ReceiverInfo> manifestReceiver(@Nullable Intent intent, - @Nullable ActivityInfo activityInfo, @Nullable CompatibilityInfo compatInfo, - int resultCode, @Nullable String data, @Nullable Bundle extras, boolean sync, - boolean assumeDelivered, int sendingUser, int sendingUid, - @Nullable String sendingPackage, int processState) { - reset(); - schedule(intent, activityInfo, compatInfo, resultCode, data, extras, sync, assumeDelivered, - sendingUser, sendingUid, sendingPackage, processState, null, 0); - return receivers(); - } - - // Return true if the batch is full. Adding any more entries will throw an exception. - boolean isFull() { - return (mFinished.size() + mReceivers.size()) >= mSize; - } - int finishCount() { - return mFinished.size() + mSuccess.size(); - } - int receiverCount() { - return mReceivers.size(); - } - - /** - * Create a deep copy of the receiver list. This is only for testing which is confused when - * objects are reused. - */ - private ArrayList<ReceiverInfo> copyReceiverInfo() { - ArrayList<ReceiverInfo> copy = new ArrayList<>(); - for (int i = 0; i < mReceivers.size(); i++) { - final ReceiverInfo r = mReceivers.get(i); - final ReceiverInfo n = new ReceiverInfo(); - n.intent = r.intent; - n.data = r.data; - n.extras = r.extras; - n.assumeDelivered = r.assumeDelivered; - n.sendingUser = r.sendingUser; - n.processState = r.processState; - n.resultCode = r.resultCode; - n.registered = r.registered; - n.receiver = r.receiver; - n.ordered = r.ordered; - n.sticky = r.sticky; - n.activityInfo = r.activityInfo; - n.compatInfo = r.compatInfo; - n.sync = r.sync; - copy.add(n); - } - return copy; - } - - /** - * Accessors for the accumulated instructions. The important accessor is receivers(), since - * it can be modified to return a deep copy of the mReceivers array. - */ - @NonNull - ArrayList<ReceiverInfo> receivers() { - if (!mDeepReceiverCopy) { - return mReceivers; - } else { - return copyReceiverInfo(); - } - } - @NonNull - ArrayList<ReceiverCookie> cookies() { - return mCookies; - } - @NonNull - ArrayList<FinishInfo> finished() { - return mFinished; - } - @NonNull - ArrayList<FinishInfo> success() { - return mSuccess; - } - - /** - * A simple POD for statistics. The parameter is the size of the BroadcastReceiverBatch. - */ - static class Statistics { - final int[] finish; - final int[] local; - final int[] remote; - Statistics(int size) { - finish = new int[size+1]; - local = new int[size+1]; - remote = new int[size+1]; - } - } - - private final Statistics mStats; - - /** - * A unique counter that identifies individual transmission groups. This is only used for - * debugging. It is used to determine which receivers were sent in the same batch, and in - * which order. This is static to distinguish between batches across all queues in the - * system. - */ - private static final AtomicInteger sTransmitGroup = new AtomicInteger(0); - - /** - * Record statistics for this batch of instructions. This updates the local statistics and it - * updates the transmitGroup and transmitOrder fields of the BroadcastRecords being - * dispatched. - */ - void recordBatch(boolean local) { - final int group = sTransmitGroup.addAndGet(1); - for (int i = 0; i < cookies().size(); i++) { - final var cookie = cookies().get(i); - cookie.r.transmitGroup[cookie.index] = group; - cookie.r.transmitOrder[cookie.index] = i; - } - mStats.finish[finishCount()]++; - if (local) { - mStats.local[receiverCount()]++; - } else { - mStats.remote[receiverCount()]++; - } - } - - @NonNull - Statistics getStatistics() { - return mStats; - } -} diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java index 6035ad9ca50e..4e2dcd599b72 100644 --- a/services/core/java/com/android/server/am/BroadcastRecord.java +++ b/services/core/java/com/android/server/am/BroadcastRecord.java @@ -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. @@ -398,8 +396,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; @@ -455,8 +451,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; diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java index 6bc2d1f11405..e7b3dd985053 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java @@ -53,7 +53,6 @@ import android.app.AppOpsManager; import android.app.BackgroundStartPrivileges; import android.app.BroadcastOptions; import android.app.IApplicationThread; -import android.app.ReceiverInfo; import android.app.usage.UsageEvents.Event; import android.app.usage.UsageStatsManagerInternal; import android.content.ComponentName; @@ -66,7 +65,6 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.ResolveInfo; -import android.content.res.CompatibilityInfo; import android.os.Binder; import android.os.Bundle; import android.os.DeadObjectException; @@ -298,16 +296,12 @@ public class BroadcastQueueTest { }; if (mImpl == Impl.DEFAULT) { - var q = new BroadcastQueueImpl(mAms, mHandlerThread.getThreadHandler(), TAG, + mQueue = new BroadcastQueueImpl(mAms, mHandlerThread.getThreadHandler(), TAG, mConstants, mSkipPolicy, emptyHistory, false, ProcessList.SCHED_GROUP_DEFAULT); - q.mReceiverBatch.mDeepReceiverCopy = true; - mQueue = q; } else if (mImpl == Impl.MODERN) { - var q = new BroadcastQueueModernImpl(mAms, mHandlerThread.getThreadHandler(), + mQueue = new BroadcastQueueModernImpl(mAms, mHandlerThread.getThreadHandler(), mConstants, mConstants, mSkipPolicy, emptyHistory); - q.mReceiverBatch.mDeepReceiverCopy = true; - mQueue = q; } else { throw new UnsupportedOperationException(); } @@ -406,43 +400,6 @@ public class BroadcastQueueTest { UnaryOperator.identity()); } - private void doRegisteredReceiver(ProcessRecord r, boolean wedge, boolean abort, - UnaryOperator<Bundle> extrasOperator, ReceiverInfo info) { - final Intent intent = info.intent; - final Bundle extras = info.extras; - final boolean assumeDelivered = info.assumeDelivered; - mScheduledBroadcasts.add(makeScheduledBroadcast(r, intent)); - if (!wedge && !assumeDelivered) { - assertTrue(r.mReceivers.numberOfCurReceivers() > 0); - assertNotEquals(ProcessList.SCHED_GROUP_UNDEFINED, - mQueue.getPreferredSchedulingGroupLocked(r)); - mHandlerThread.getThreadHandler().post(() -> { - synchronized (mAms) { - mQueue.finishReceiverLocked(r, Activity.RESULT_OK, - null, extrasOperator.apply(extras), abort, false); - } - }); - } - } - - private void doManifestReceiver(ProcessRecord r, boolean wedge, boolean abort, - UnaryOperator<Bundle> extrasOperator, ReceiverInfo info) { - final Intent intent = info.intent; - final Bundle extras = info.extras; - mScheduledBroadcasts.add(makeScheduledBroadcast(r, intent)); - if (!wedge) { - assertTrue(r.mReceivers.numberOfCurReceivers() > 0); - assertNotEquals(ProcessList.SCHED_GROUP_UNDEFINED, - mQueue.getPreferredSchedulingGroupLocked(r)); - mHandlerThread.getThreadHandler().post(() -> { - synchronized (mAms) { - mQueue.finishReceiverLocked(r, Activity.RESULT_OK, null, - extrasOperator.apply(extras), abort, false); - } - }); - } - } - private ProcessRecord makeActiveProcessRecord(ApplicationInfo ai, String processName, ProcessBehavior behavior, UnaryOperator<Bundle> extrasOperator) throws Exception { final boolean wedge = (behavior == ProcessBehavior.WEDGE); @@ -486,22 +443,47 @@ public class BroadcastQueueTest { if (dead) return r; doAnswer((invocation) -> { - Log.v(TAG, "Intercepting scheduleReceiverList() for " + Log.v(TAG, "Intercepting scheduleReceiver() for " + Arrays.toString(invocation.getArguments())); - final List<ReceiverInfo> data = invocation.getArgument(0); - for (int i = 0; i < data.size(); i++) { - ReceiverInfo info = data.get(i); - // The logic here mimics the logic in ActivityThread: elements of the list are - // forwarded to a handler for manifest receivers or to a handler for registered - // receivers. - if (info.registered) { - doRegisteredReceiver(r, wedge, abort, extrasOperator, info); - } else { - doManifestReceiver(r, wedge, abort, extrasOperator, info); - } + final Intent intent = invocation.getArgument(0); + final Bundle extras = invocation.getArgument(5); + mScheduledBroadcasts.add(makeScheduledBroadcast(r, intent)); + if (!wedge) { + assertTrue(r.mReceivers.numberOfCurReceivers() > 0); + assertNotEquals(ProcessList.SCHED_GROUP_UNDEFINED, + mQueue.getPreferredSchedulingGroupLocked(r)); + mHandlerThread.getThreadHandler().post(() -> { + synchronized (mAms) { + mQueue.finishReceiverLocked(r, Activity.RESULT_OK, null, + extrasOperator.apply(extras), abort, false); + } + }); + } + return null; + }).when(thread).scheduleReceiver(any(), any(), any(), anyInt(), any(), any(), anyBoolean(), + anyBoolean(), anyInt(), anyInt(), anyInt(), any()); + + doAnswer((invocation) -> { + Log.v(TAG, "Intercepting scheduleRegisteredReceiver() for " + + Arrays.toString(invocation.getArguments())); + final Intent intent = invocation.getArgument(1); + final Bundle extras = invocation.getArgument(4); + final boolean ordered = invocation.getArgument(5); + mScheduledBroadcasts.add(makeScheduledBroadcast(r, intent)); + if (!wedge && ordered) { + assertTrue(r.mReceivers.numberOfCurReceivers() > 0); + assertNotEquals(ProcessList.SCHED_GROUP_UNDEFINED, + mQueue.getPreferredSchedulingGroupLocked(r)); + mHandlerThread.getThreadHandler().post(() -> { + synchronized (mAms) { + mQueue.finishReceiverLocked(r, Activity.RESULT_OK, + null, extrasOperator.apply(extras), abort, false); + } + }); } return null; - }).when(thread).scheduleReceiverList(any()); + }).when(thread).scheduleRegisteredReceiver(any(), any(), anyInt(), any(), any(), + anyBoolean(), anyBoolean(), anyBoolean(), anyInt(), anyInt(), anyInt(), any()); return r; } @@ -643,131 +625,6 @@ public class BroadcastQueueTest { }; } - private static <T> boolean matchElement(T a, T b) { - return a == null || a.equals(b); - } - private static <T> boolean matchObject(ArgumentMatcher<T> m, T b) { - return m == null || m.matches(b); - } - - /** - * Create an ArgumentMatcher for a manifest receiver. The parameters are in the order of - * {@link IApplicationThread#scheduleReceiver} but the names correspond to the field names in - * {@link ReceiverInfo}. For every parameter, a null means "don't care". - */ - private ArgumentMatcher<ReceiverInfo> manifestReceiverMatcher( - ArgumentMatcher<Intent> intent, - ArgumentMatcher<ActivityInfo> activityInfo, - ArgumentMatcher<CompatibilityInfo> compatInfo, - Integer resultCode, - ArgumentMatcher<String> data, - ArgumentMatcher<Bundle> extras, - Boolean sync, - Boolean assumeDelivered, - Integer sendingUser, - Integer processState) { - return (test) -> { - return test.registered == false - && matchObject(intent, test.intent) - && matchObject(activityInfo, test.activityInfo) - && matchObject(compatInfo, test.compatInfo) - && matchElement(resultCode, test.resultCode) - && matchObject(data, test.data) - && matchObject(extras, test.extras) - && matchElement(sync, test.sync) - && matchElement(assumeDelivered, test.assumeDelivered) - && matchElement(sendingUser, test.sendingUser) - && matchElement(processState, test.processState); - }; - } - - - /** - * Create an argument suitable for the verify() mock methods, when the goal is to find a call - * containing a manifest receiver. - */ - private List<ReceiverInfo> manifestReceiver( - ArgumentMatcher<Intent> intent, - ArgumentMatcher<ActivityInfo> activityInfo, - ArgumentMatcher<CompatibilityInfo> compatInfo, - Integer resultCode, - ArgumentMatcher<String> data, - ArgumentMatcher<Bundle> extras, - Boolean sync, - Boolean assumeDelivered, - Integer sendingUser, - Integer processState) { - return argThat(receiverList(manifestReceiverMatcher(intent, activityInfo, compatInfo, - resultCode, data, extras, sync, assumeDelivered, - sendingUser, processState))); - } - - /** - * Create an ArgumentMatcher for a registered receiver. The parameters are in the order of - * {@link IApplicationThread#scheduleRegisteredReceiver} but the names correspond to the field - * names in {@link ReceiverInfo}. For every parameter, a null means "don't care". - */ - private ArgumentMatcher<ReceiverInfo> registeredReceiverMatcher( - ArgumentMatcher<IIntentReceiver> receiver, - ArgumentMatcher<Intent> intent, - Integer resultCode, - ArgumentMatcher<String> data, - ArgumentMatcher<Bundle> extras, - Boolean ordered, - Boolean sticky, - Boolean assumeDelivered, - Integer sendingUser, - Integer processState) { - return (test) -> { - return test.registered == true - && matchObject(receiver, test.receiver) - && matchObject(intent, test.intent) - && matchElement(resultCode, test.resultCode) - && matchObject(data, test.data) - && matchObject(extras, test.extras) - && matchElement(ordered, test.ordered) - && matchElement(sticky, test.sticky) - && matchElement(assumeDelivered, test.assumeDelivered) - && matchElement(sendingUser, test.sendingUser) - && matchElement(processState, test.processState); - }; - } - - /** - * Create an argument suitable for the verify() mock methods, when the goal is to find a call - * containing a registered receiver. - */ - private List<ReceiverInfo> registeredReceiver( - ArgumentMatcher<IIntentReceiver> receiver, - ArgumentMatcher<Intent> intent, - Integer resultCode, - ArgumentMatcher<String> data, - ArgumentMatcher<Bundle> extras, - Boolean ordered, - Boolean sticky, - Boolean assumeDelivered, - Integer sendingUser, - Integer processState) { - return argThat(receiverList(registeredReceiverMatcher(receiver, intent, resultCode, - data, extras, ordered, sticky, assumeDelivered, - sendingUser, processState))); - } - - /** - * Apply a matcher to every element in a ReceiverInfo list. - */ - private ArgumentMatcher<List<ReceiverInfo>> receiverList(ArgumentMatcher<ReceiverInfo> a) { - return (test) -> { - for (int i = 0; i < test.size(); i++) { - ReceiverInfo r = test.get(i); - if (a.matches(r)) { - return true; - } - } - return false; - }; - } - private ArgumentMatcher<Bundle> bundleEquals(Bundle bundle) { return (test) -> { // TODO: check values in addition to keys @@ -802,37 +659,42 @@ public class BroadcastQueueTest { ComponentName component) throws Exception { final Intent targetedIntent = new Intent(intent); targetedIntent.setComponent(component); - verify(app.getThread(), mode).scheduleReceiverList( - manifestReceiver(filterEquals(targetedIntent), - null, null, null, null, null, null, null, UserHandle.USER_SYSTEM, null)); + verify(app.getThread(), mode).scheduleReceiver( + argThat(filterEquals(targetedIntent)), any(), any(), + anyInt(), any(), any(), eq(false), anyBoolean(), eq(UserHandle.USER_SYSTEM), + anyInt(), anyInt(), any()); } private void verifyScheduleReceiver(VerificationMode mode, ProcessRecord app, Intent intent, int userId) throws Exception { - verify(app.getThread(), mode).scheduleReceiverList( - manifestReceiver(filterEqualsIgnoringComponent(intent), - null, null, null, null, null, null, null, userId, null)); + verify(app.getThread(), mode).scheduleReceiver( + argThat(filterEqualsIgnoringComponent(intent)), any(), any(), + anyInt(), any(), any(), anyBoolean(), anyBoolean(), eq(userId), + anyInt(), anyInt(), any()); } private void verifyScheduleReceiver(VerificationMode mode, ProcessRecord app, int userId) throws Exception { - verify(app.getThread(), mode).scheduleReceiverList( - manifestReceiver(null, - null, null, null, null, null, null, null, userId, null)); + verify(app.getThread(), mode).scheduleReceiver( + any(), any(), any(), + anyInt(), any(), any(), anyBoolean(), anyBoolean(), eq(userId), + anyInt(), anyInt(), any()); } private void verifyScheduleRegisteredReceiver(ProcessRecord app, Intent intent) throws Exception { - verify(app.getThread()).scheduleReceiverList( - registeredReceiver(null, filterEqualsIgnoringComponent(intent), - null, null, null, null, null, null, UserHandle.USER_SYSTEM, null)); + verify(app.getThread()).scheduleRegisteredReceiver( + any(), argThat(filterEqualsIgnoringComponent(intent)), + anyInt(), any(), any(), anyBoolean(), anyBoolean(), anyBoolean(), + eq(UserHandle.USER_SYSTEM), anyInt(), anyInt(), any()); } private void verifyScheduleRegisteredReceiver(VerificationMode mode, ProcessRecord app, int userId) throws Exception { - verify(app.getThread(), mode).scheduleReceiverList( - registeredReceiver(null, null, - null, null, null, null, null, null, userId, null)); + verify(app.getThread(), mode).scheduleRegisteredReceiver( + any(), any(), + anyInt(), any(), any(), anyBoolean(), anyBoolean(), anyBoolean(), + eq(userId), anyInt(), anyInt(), any()); } static final int USER_GUEST = 11; @@ -1485,24 +1347,25 @@ public class BroadcastQueueTest { final InOrder inOrder = inOrder(greenThread, blueThread, yellowThread, redThread); final Bundle expectedExtras = new Bundle(); expectedExtras.putBoolean(PACKAGE_RED, true); - inOrder.verify(greenThread).scheduleReceiverList(manifestReceiver( - filterEqualsIgnoringComponent(airplane), null, null, - Activity.RESULT_OK, null, bundleEquals(expectedExtras), true, false, - UserHandle.USER_SYSTEM, null)); - inOrder.verify(blueThread).scheduleReceiverList(manifestReceiver( - filterEqualsIgnoringComponent(airplane), null, null, - Activity.RESULT_OK, null, bundleEquals(expectedExtras), true, false, - UserHandle.USER_SYSTEM, null)); + inOrder.verify(greenThread).scheduleReceiver( + argThat(filterEqualsIgnoringComponent(airplane)), any(), any(), + eq(Activity.RESULT_OK), any(), argThat(bundleEquals(expectedExtras)), + eq(true), eq(false), eq(UserHandle.USER_SYSTEM), anyInt(), anyInt(), any()); + inOrder.verify(blueThread).scheduleReceiver( + argThat(filterEqualsIgnoringComponent(airplane)), any(), any(), + eq(Activity.RESULT_OK), any(), argThat(bundleEquals(expectedExtras)), + eq(true), eq(false), eq(UserHandle.USER_SYSTEM), anyInt(), anyInt(), any()); expectedExtras.putBoolean(PACKAGE_BLUE, true); - inOrder.verify(yellowThread).scheduleReceiverList(manifestReceiver( - filterEqualsIgnoringComponent(airplane), null, null, - Activity.RESULT_OK, null, bundleEquals(expectedExtras), true, false, - UserHandle.USER_SYSTEM, null)); + inOrder.verify(yellowThread).scheduleReceiver( + argThat(filterEqualsIgnoringComponent(airplane)), any(), any(), + eq(Activity.RESULT_OK), any(), argThat(bundleEquals(expectedExtras)), + eq(true), eq(false), eq(UserHandle.USER_SYSTEM), anyInt(), anyInt(), any()); expectedExtras.putBoolean(PACKAGE_YELLOW, true); - inOrder.verify(redThread).scheduleReceiverList(registeredReceiver( - null, filterEquals(airplane), - Activity.RESULT_OK, null, bundleEquals(expectedExtras), false, - null, true, UserHandle.USER_SYSTEM, null)); + inOrder.verify(redThread).scheduleRegisteredReceiver( + any(), argThat(filterEquals(airplane)), + eq(Activity.RESULT_OK), any(), argThat(bundleEquals(expectedExtras)), + eq(false), anyBoolean(), eq(true), eq(UserHandle.USER_SYSTEM), anyInt(), + anyInt(), any()); // Finally, verify that we thawed the final receiver verify(mAms.mOomAdjuster.mCachedAppOptimizer).unfreezeTemporarily(eq(callerApp), @@ -1565,24 +1428,25 @@ public class BroadcastQueueTest { // have invoked or skipped the second receiver depending on the intent // flag policy; we always deliver to final receiver regardless of abort final InOrder inOrder = inOrder(greenThread, blueThread, redThread); - inOrder.verify(greenThread).scheduleReceiverList(manifestReceiver( - filterEqualsIgnoringComponent(intent), null, null, - Activity.RESULT_OK, null, null, true, false, UserHandle.USER_SYSTEM, - null)); + inOrder.verify(greenThread).scheduleReceiver( + argThat(filterEqualsIgnoringComponent(intent)), any(), any(), + eq(Activity.RESULT_OK), any(), any(), eq(true), eq(false), + eq(UserHandle.USER_SYSTEM), anyInt(), anyInt(), any()); if ((intent.getFlags() & Intent.FLAG_RECEIVER_NO_ABORT) != 0) { - inOrder.verify(blueThread).scheduleReceiverList(manifestReceiver( - filterEqualsIgnoringComponent(intent), null, null, - Activity.RESULT_OK, null, null, true, false, UserHandle.USER_SYSTEM, - null)); + inOrder.verify(blueThread).scheduleReceiver( + argThat(filterEqualsIgnoringComponent(intent)), any(), any(), + eq(Activity.RESULT_OK), any(), any(), eq(true), eq(false), + eq(UserHandle.USER_SYSTEM), anyInt(), anyInt(), any()); } else { - inOrder.verify(blueThread, never()).scheduleReceiverList(manifestReceiver( - null, null, null, null, null, - null, null, null, null, null)); + inOrder.verify(blueThread, never()).scheduleReceiver( + any(), any(), any(), anyInt(), any(), any(), + anyBoolean(), anyBoolean(), anyInt(), anyInt(), anyInt(), any()); } - inOrder.verify(redThread).scheduleReceiverList(registeredReceiver( - null, filterEquals(intent), - Activity.RESULT_OK, null, bundleEquals(expectedExtras), - false, null, true, UserHandle.USER_SYSTEM, null)); + inOrder.verify(redThread).scheduleRegisteredReceiver( + any(), argThat(filterEquals(intent)), + eq(Activity.RESULT_OK), any(), argThat(bundleEquals(expectedExtras)), + eq(false), anyBoolean(), eq(true), eq(UserHandle.USER_SYSTEM), + anyInt(), anyInt(), any()); } /** @@ -1602,10 +1466,11 @@ public class BroadcastQueueTest { orderedResultTo, orderedExtras)); waitForIdle(); - verify(callerThread).scheduleReceiverList(registeredReceiver( - null, filterEquals(airplane), - Activity.RESULT_OK, null, bundleEquals(orderedExtras), false, - null, true, UserHandle.USER_SYSTEM, null)); + verify(callerThread).scheduleRegisteredReceiver( + any(), argThat(filterEquals(airplane)), + eq(Activity.RESULT_OK), any(), argThat(bundleEquals(orderedExtras)), + eq(false), anyBoolean(), eq(true), eq(UserHandle.USER_SYSTEM), + anyInt(), anyInt(), any()); } /** @@ -1623,10 +1488,11 @@ public class BroadcastQueueTest { makeManifestReceiver(PACKAGE_BLUE, CLASS_BLUE)), resultTo)); waitForIdle(); - verify(callerThread).scheduleReceiverList(registeredReceiver( - null, filterEquals(airplane), - Activity.RESULT_OK, null, null, false, - null, true, UserHandle.USER_SYSTEM, null)); + verify(callerThread).scheduleRegisteredReceiver( + any(), argThat(filterEquals(airplane)), + eq(Activity.RESULT_OK), any(), any(), + eq(false), anyBoolean(), eq(true), eq(UserHandle.USER_SYSTEM), + anyInt(), anyInt(), any()); } /** @@ -1790,28 +1656,34 @@ public class BroadcastQueueTest { final InOrder inOrder = inOrder(callerThread, blueThread); // First broadcast is canceled - inOrder.verify(callerThread).scheduleReceiverList(registeredReceiver(null, - filterAndExtrasEquals(timezoneFirst), Activity.RESULT_CANCELED, null, - null, false, null, true, UserHandle.USER_SYSTEM, null)); + inOrder.verify(callerThread).scheduleRegisteredReceiver( + any(), argThat(filterAndExtrasEquals(timezoneFirst)), + eq(Activity.RESULT_CANCELED), any(), any(), + eq(false), anyBoolean(), eq(true), eq(UserHandle.USER_SYSTEM), + anyInt(), anyInt(), any()); // We deliver second broadcast to app timezoneSecond.setClassName(PACKAGE_BLUE, CLASS_GREEN); - inOrder.verify(blueThread).scheduleReceiverList(manifestReceiver( - filterAndExtrasEquals(timezoneSecond), - null, null, null, null, null, true, false, null, null)); + inOrder.verify(blueThread).scheduleReceiver( + argThat(filterAndExtrasEquals(timezoneSecond)), any(), any(), + anyInt(), any(), any(), eq(true), eq(false), anyInt(), + anyInt(), anyInt(), any()); // Second broadcast is finished timezoneSecond.setComponent(null); - inOrder.verify(callerThread).scheduleReceiverList(registeredReceiver(null, - filterAndExtrasEquals(timezoneSecond), Activity.RESULT_OK, null, - null, false, null, true, UserHandle.USER_SYSTEM, null)); + inOrder.verify(callerThread).scheduleRegisteredReceiver( + any(), argThat(filterAndExtrasEquals(timezoneSecond)), + eq(Activity.RESULT_OK), any(), any(), + eq(false), anyBoolean(), eq(true), eq(UserHandle.USER_SYSTEM), + anyInt(), anyInt(), any()); // Since we "replaced" the first broadcast in its original position, // only now do we see the airplane broadcast airplane.setClassName(PACKAGE_BLUE, CLASS_RED); - inOrder.verify(blueThread).scheduleReceiverList(manifestReceiver( - filterEquals(airplane), - null, null, null, null, null, false, false, null, null)); + inOrder.verify(blueThread).scheduleReceiver( + argThat(filterEquals(airplane)), any(), any(), + anyInt(), any(), any(), eq(false), eq(false), anyInt(), + anyInt(), anyInt(), any()); } @Test @@ -1873,15 +1745,17 @@ public class BroadcastQueueTest { // First broadcast is delivered. timeTickFirst.setClassName(PACKAGE_BLUE, CLASS_BLUE); - inOrder.verify(blueThread).scheduleReceiverList(manifestReceiver( - filterAndExtrasEquals(timeTickFirst), - null, null, null, null, null, false, false, null, null)); + inOrder.verify(blueThread).scheduleReceiver( + argThat(filterAndExtrasEquals(timeTickFirst)), any(), any(), + anyInt(), any(), any(), eq(false), eq(false), anyInt(), + anyInt(), anyInt(), any()); // Second broadcast should be replaced by third broadcast. timeTickThird.setClassName(PACKAGE_BLUE, CLASS_BLUE); - inOrder.verify(blueThread).scheduleReceiverList(manifestReceiver( - filterAndExtrasEquals(timeTickThird), - null, null, null, null, null, false, false, null, null)); + inOrder.verify(blueThread).scheduleReceiver( + argThat(filterAndExtrasEquals(timeTickThird)), any(), any(), + anyInt(), any(), any(), eq(false), eq(false), anyInt(), + anyInt(), anyInt(), any()); } @Test |