summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Jeff Sharkey <jsharkey@google.com> 2022-11-01 20:41:56 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2022-11-01 20:41:56 +0000
commit9a4dc78e7e32b4e7216daafb1886d0edd55fe30c (patch)
treee135b4d9b0854ef6e3d43fc4074b0d6e7d953bf6
parenta5f5864381d993686e6f456b35b67549fa766631 (diff)
parentc16955aa41551009ea8e70fd0b73114f3de6bf0c (diff)
Merge changes from topic "nov1"
* changes: BroadcastQueue: add more performance tracing. BroadcastQueue: post finishReceiver() as async. BroadcastQueue: better state transition logging. BroadcastQueue: return reasons from skip policy. BroadcastQueue: skip ANRs when assuming success.
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java25
-rw-r--r--services/core/java/com/android/server/am/BroadcastLoopers.java3
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueue.java13
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueueModernImpl.java122
-rw-r--r--services/core/java/com/android/server/am/BroadcastSkipPolicy.java234
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java6
6 files changed, 233 insertions, 170 deletions
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2eaddb1c37f1..062afe93e63d 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -13874,6 +13874,29 @@ public class ActivityManagerService extends IActivityManager.Stub
@Nullable IBinder backgroundActivityStartsToken,
@Nullable int[] broadcastAllowList,
@Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver) {
+ final int cookie = BroadcastQueue.traceBegin("broadcastIntentLockedTraced");
+ final int res = broadcastIntentLockedTraced(callerApp, callerPackage, callerFeatureId,
+ intent, resolvedType, resultToApp, resultTo, resultCode, resultData, resultExtras,
+ requiredPermissions, excludedPermissions, excludedPackages, appOp, bOptions,
+ ordered, sticky, callingPid, callingUid, realCallingUid, realCallingPid, userId,
+ allowBackgroundActivityStarts, backgroundActivityStartsToken, broadcastAllowList,
+ filterExtrasForReceiver);
+ BroadcastQueue.traceEnd(cookie);
+ return res;
+ }
+
+ @GuardedBy("this")
+ final int broadcastIntentLockedTraced(ProcessRecord callerApp, String callerPackage,
+ @Nullable String callerFeatureId, Intent intent, String resolvedType,
+ ProcessRecord resultToApp, IIntentReceiver resultTo, int resultCode, String resultData,
+ Bundle resultExtras, String[] requiredPermissions,
+ String[] excludedPermissions, String[] excludedPackages, int appOp, Bundle bOptions,
+ boolean ordered, boolean sticky, int callingPid, int callingUid,
+ int realCallingUid, int realCallingPid, int userId,
+ boolean allowBackgroundActivityStarts,
+ @Nullable IBinder backgroundActivityStartsToken,
+ @Nullable int[] broadcastAllowList,
+ @Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver) {
// Ensure all internal loopers are registered for idle checks
BroadcastLoopers.addMyLooper();
@@ -14425,6 +14448,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
// Figure out who all will receive this broadcast.
+ final int cookie = BroadcastQueue.traceBegin("queryReceivers");
List receivers = null;
List<BroadcastFilter> registeredReceivers = null;
// Need to resolve the intent to interested receivers...
@@ -14455,6 +14479,7 @@ public class ActivityManagerService extends IActivityManager.Stub
resolvedType, false /*defaultOnly*/, userId);
}
}
+ BroadcastQueue.traceEnd(cookie);
final boolean replacePending =
(intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
diff --git a/services/core/java/com/android/server/am/BroadcastLoopers.java b/services/core/java/com/android/server/am/BroadcastLoopers.java
index bebb48473fc3..b828720c9162 100644
--- a/services/core/java/com/android/server/am/BroadcastLoopers.java
+++ b/services/core/java/com/android/server/am/BroadcastLoopers.java
@@ -25,6 +25,8 @@ import android.os.SystemClock;
import android.util.ArraySet;
import android.util.Slog;
+import com.android.internal.annotations.GuardedBy;
+
import java.io.PrintWriter;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
@@ -37,6 +39,7 @@ import java.util.concurrent.CountDownLatch;
public class BroadcastLoopers {
private static final String TAG = "BroadcastLoopers";
+ @GuardedBy("sLoopers")
private static final ArraySet<Looper> sLoopers = new ArraySet<>();
/**
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 1e172fc92f40..e0fab2cfec21 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -24,6 +24,7 @@ import android.content.Intent;
import android.os.Bundle;
import android.os.DropBoxManager;
import android.os.Handler;
+import android.os.Trace;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
@@ -76,6 +77,18 @@ public abstract class BroadcastQueue {
}
}
+ static int traceBegin(@NonNull String methodName) {
+ final int cookie = methodName.hashCode();
+ Trace.asyncTraceForTrackBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
+ TAG, methodName, cookie);
+ return cookie;
+ }
+
+ static void traceEnd(int cookie) {
+ Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER,
+ TAG, cookie);
+ }
+
@Override
public String toString() {
return mQueueName;
diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
index 57506199f0e1..af2a97e62617 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
@@ -64,7 +64,6 @@ import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
-import android.os.Trace;
import android.os.UserHandle;
import android.text.format.DateUtils;
import android.util.IndentingPrintWriter;
@@ -144,14 +143,6 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
mRunning = new BroadcastProcessQueue[mConstants.MAX_RUNNING_PROCESS_QUEUES];
}
- // TODO: add support for replacing pending broadcasts
- // TODO: add support for merging pending broadcasts
-
- // TODO: consider reordering foreground broadcasts within queue
-
- // TODO: pause queues when background services are running
- // TODO: pause queues when processes are frozen
-
/**
* Map from UID to per-process broadcast queues. If a UID hosts more than
* one process, each additional process is stored as a linked list using
@@ -222,12 +213,22 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
private static final int MSG_DELIVERY_TIMEOUT_HARD = 3;
private static final int MSG_BG_ACTIVITY_START_TIMEOUT = 4;
private static final int MSG_CHECK_HEALTH = 5;
+ private static final int MSG_FINISH_RECEIVER = 6;
private void enqueueUpdateRunningList() {
mLocalHandler.removeMessages(MSG_UPDATE_RUNNING_LIST);
mLocalHandler.sendEmptyMessage(MSG_UPDATE_RUNNING_LIST);
}
+ private void enqueueFinishReceiver(@NonNull BroadcastProcessQueue queue,
+ @DeliveryState int deliveryState, @NonNull String reason) {
+ final SomeArgs args = SomeArgs.obtain();
+ args.arg1 = queue;
+ args.argi1 = deliveryState;
+ args.arg2 = reason;
+ mLocalHandler.sendMessage(Message.obtain(mLocalHandler, MSG_FINISH_RECEIVER, args));
+ }
+
private final Handler mLocalHandler;
private final Handler.Callback mLocalCallback = (msg) -> {
@@ -266,6 +267,17 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
}
return true;
}
+ case MSG_FINISH_RECEIVER: {
+ synchronized (mService) {
+ final SomeArgs args = (SomeArgs) msg.obj;
+ final BroadcastProcessQueue queue = (BroadcastProcessQueue) args.arg1;
+ final int deliveryState = args.argi1;
+ final String reason = (String) args.arg2;
+ args.recycle();
+ finishReceiverLocked(queue, deliveryState, reason);
+ }
+ return true;
+ }
}
return false;
};
@@ -309,6 +321,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
return;
}
+ final int cookie = traceBegin("updateRunnableList");
final boolean wantQueue = queue.isRunnable();
final boolean inQueue = (queue == mRunnableHead) || (queue.runnableAtPrev != null)
|| (queue.runnableAtNext != null);
@@ -335,6 +348,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
if (queue.isEmpty() && !queue.isActive() && !queue.isProcessWarm()) {
removeProcessQueue(queue.processName, queue.uid);
}
+
+ traceEnd(cookie);
}
/**
@@ -349,7 +364,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
int avail = mRunning.length - getRunningSize();
if (avail == 0) return;
- final int cookie = traceBegin(TAG, "updateRunningList");
+ final int cookie = traceBegin("updateRunningList");
final long now = SystemClock.uptimeMillis();
// If someone is waiting for a state, everything is runnable now
@@ -449,7 +464,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
});
}
- traceEnd(TAG, cookie);
+ traceEnd(cookie);
}
@Override
@@ -516,7 +531,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
if (queue != null) {
// If queue was running a broadcast, fail it
if (queue.isActive()) {
- finishReceiverLocked(queue, BroadcastRecord.DELIVERY_FAILURE);
+ finishReceiverLocked(queue, BroadcastRecord.DELIVERY_FAILURE,
+ "onApplicationCleanupLocked");
}
// Skip any pending registered receivers, since the old process
@@ -544,6 +560,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
public void enqueueBroadcastLocked(@NonNull BroadcastRecord r) {
if (DEBUG_BROADCAST) logv("Enqueuing " + r + " for " + r.receivers.size() + " receivers");
+ final int cookie = traceBegin("enqueueBroadcast");
r.applySingletonPolicy(mService);
final IntentFilter removeMatchingFilter = (r.options != null)
@@ -613,6 +630,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
if (r.receivers.isEmpty()) {
scheduleResultTo(r);
}
+
+ traceEnd(cookie);
}
private void applyDeliveryGroupPolicy(@NonNull BroadcastRecord r) {
@@ -668,7 +687,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
// Ignore registered receivers from a previous PID
if (receiver instanceof BroadcastFilter) {
mRunningColdStart = null;
- finishReceiverLocked(queue, BroadcastRecord.DELIVERY_SKIPPED);
+ enqueueFinishReceiver(queue, BroadcastRecord.DELIVERY_SKIPPED,
+ "BroadcastFilter for cold app");
return;
}
@@ -690,7 +710,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
hostingRecord, zygotePolicyFlags, allowWhileBooting, false);
if (queue.app == null) {
mRunningColdStart = null;
- finishReceiverLocked(queue, BroadcastRecord.DELIVERY_FAILURE);
+ enqueueFinishReceiver(queue, BroadcastRecord.DELIVERY_FAILURE,
+ "startProcessLocked failed");
return;
}
}
@@ -721,33 +742,37 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
// If someone already finished this broadcast, finish immediately
final int oldDeliveryState = getDeliveryState(r, index);
if (isDeliveryStateTerminal(oldDeliveryState)) {
- finishReceiverLocked(queue, oldDeliveryState);
+ enqueueFinishReceiver(queue, oldDeliveryState, "already terminal state");
return;
}
// Consider additional cases where we'd want to finish immediately
if (app.isInFullBackup()) {
- finishReceiverLocked(queue, BroadcastRecord.DELIVERY_SKIPPED);
+ enqueueFinishReceiver(queue, BroadcastRecord.DELIVERY_SKIPPED, "isInFullBackup");
return;
}
if (mSkipPolicy.shouldSkip(r, receiver)) {
- finishReceiverLocked(queue, BroadcastRecord.DELIVERY_SKIPPED);
+ enqueueFinishReceiver(queue, BroadcastRecord.DELIVERY_SKIPPED, "mSkipPolicy");
return;
}
final Intent receiverIntent = r.getReceiverIntent(receiver);
if (receiverIntent == null) {
- finishReceiverLocked(queue, BroadcastRecord.DELIVERY_SKIPPED);
+ enqueueFinishReceiver(queue, BroadcastRecord.DELIVERY_SKIPPED, "isInFullBackup");
return;
}
// Ignore registered receivers from a previous PID
if ((receiver instanceof BroadcastFilter)
&& ((BroadcastFilter) receiver).receiverList.pid != app.getPid()) {
- finishReceiverLocked(queue, BroadcastRecord.DELIVERY_SKIPPED);
+ enqueueFinishReceiver(queue, BroadcastRecord.DELIVERY_SKIPPED,
+ "BroadcastFilter for mismatched PID");
return;
}
- if (mService.mProcessesReady && !r.timeoutExempt) {
+ // Skip ANR tracking early during boot, when requested, or when we
+ // immediately assume delivery success
+ final boolean assumeDelivered = (receiver instanceof BroadcastFilter) && !r.ordered;
+ if (mService.mProcessesReady && !r.timeoutExempt && !assumeDelivered) {
queue.lastCpuDelayTime = queue.app.getCpuDelayTime();
final long timeout = r.isForeground() ? mFgConstants.TIMEOUT : mBgConstants.TIMEOUT;
@@ -775,7 +800,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
}
if (DEBUG_BROADCAST) logv("Scheduling " + r + " to warm " + app);
- setDeliveryState(queue, app, r, index, receiver, BroadcastRecord.DELIVERY_SCHEDULED);
+ setDeliveryState(queue, app, r, index, receiver, BroadcastRecord.DELIVERY_SCHEDULED,
+ "scheduleReceiverWarmLocked");
final IApplicationThread thread = app.getOnewayThread();
if (thread != null) {
@@ -789,8 +815,9 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
// TODO: consider making registered receivers of unordered
// broadcasts report results to detect ANRs
- if (!r.ordered) {
- finishReceiverLocked(queue, BroadcastRecord.DELIVERY_DELIVERED);
+ if (assumeDelivered) {
+ enqueueFinishReceiver(queue, BroadcastRecord.DELIVERY_DELIVERED,
+ "assuming delivered");
}
} else {
notifyScheduleReceiver(app, r, (ResolveInfo) receiver);
@@ -804,10 +831,11 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
logw(msg);
app.scheduleCrashLocked(msg, CannotDeliverBroadcastException.TYPE_ID, null);
app.setKilled(true);
- finishReceiverLocked(queue, BroadcastRecord.DELIVERY_FAILURE);
+ enqueueFinishReceiver(queue, BroadcastRecord.DELIVERY_FAILURE, "remote app");
}
} else {
- finishReceiverLocked(queue, BroadcastRecord.DELIVERY_FAILURE);
+ enqueueFinishReceiver(queue, BroadcastRecord.DELIVERY_FAILURE,
+ "missing IApplicationThread");
}
}
@@ -851,7 +879,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
}
private void deliveryTimeoutHardLocked(@NonNull BroadcastProcessQueue queue) {
- finishReceiverLocked(queue, BroadcastRecord.DELIVERY_TIMEOUT);
+ finishReceiverLocked(queue, BroadcastRecord.DELIVERY_TIMEOUT,
+ "deliveryTimeoutHardLocked");
}
@Override
@@ -878,16 +907,17 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
if (r.resultAbort) {
for (int i = r.terminalCount + 1; i < r.receivers.size(); i++) {
setDeliveryState(null, null, r, i, r.receivers.get(i),
- BroadcastRecord.DELIVERY_SKIPPED);
+ BroadcastRecord.DELIVERY_SKIPPED, "resultAbort");
}
}
}
- return finishReceiverLocked(queue, BroadcastRecord.DELIVERY_DELIVERED);
+ return finishReceiverLocked(queue, BroadcastRecord.DELIVERY_DELIVERED, "remote app");
}
private boolean finishReceiverLocked(@NonNull BroadcastProcessQueue queue,
- @DeliveryState int deliveryState) {
+ @DeliveryState int deliveryState, @NonNull String reason) {
+ final int cookie = traceBegin("finishReceiver");
checkState(queue.isActive(), "isActive");
final ProcessRecord app = queue.app;
@@ -895,7 +925,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
final int index = queue.getActiveIndex();
final Object receiver = r.receivers.get(index);
- setDeliveryState(queue, app, r, index, receiver, deliveryState);
+ setDeliveryState(queue, app, r, index, receiver, deliveryState, reason);
if (deliveryState == BroadcastRecord.DELIVERY_TIMEOUT) {
r.anrCount++;
@@ -914,11 +944,12 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
final boolean shouldRetire =
(queue.getActiveCountSinceIdle() >= mConstants.MAX_RUNNING_ACTIVE_BROADCASTS);
+ final boolean res;
if (queue.isRunnable() && queue.isProcessWarm() && !shouldRetire) {
// We're on a roll; move onto the next broadcast for this process
queue.makeActiveNextPending();
scheduleReceiverWarmLocked(queue);
- return true;
+ res = true;
} else {
// We've drained running broadcasts; maybe move back to runnable
queue.makeActiveIdle();
@@ -932,8 +963,10 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
// Tell other OS components that app is not actively running, giving
// a chance to update OOM adjustment
notifyStoppedRunning(queue);
- return false;
+ res = false;
}
+ traceEnd(cookie);
+ return res;
}
/**
@@ -942,7 +975,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
*/
private void setDeliveryState(@Nullable BroadcastProcessQueue queue,
@Nullable ProcessRecord app, @NonNull BroadcastRecord r, int index,
- @NonNull Object receiver, @DeliveryState int newDeliveryState) {
+ @NonNull Object receiver, @DeliveryState int newDeliveryState, String reason) {
+ final int cookie = traceBegin("setDeliveryState");
final int oldDeliveryState = getDeliveryState(r, index);
// Only apply state when we haven't already reached a terminal state;
@@ -970,7 +1004,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
logw("Delivery state of " + r + " to " + receiver
+ " via " + app + " changed from "
+ deliveryStateToString(oldDeliveryState) + " to "
- + deliveryStateToString(newDeliveryState));
+ + deliveryStateToString(newDeliveryState) + " because " + reason);
}
r.terminalCount++;
@@ -1000,6 +1034,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
enqueueUpdateRunningList();
}
}
+
+ traceEnd(cookie);
}
private @DeliveryState int getDeliveryState(@NonNull BroadcastRecord r, int index) {
@@ -1060,7 +1096,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
* of it matching a predicate.
*/
private final BroadcastConsumer mBroadcastConsumerSkip = (r, i) -> {
- setDeliveryState(null, null, r, i, r.receivers.get(i), BroadcastRecord.DELIVERY_SKIPPED);
+ setDeliveryState(null, null, r, i, r.receivers.get(i), BroadcastRecord.DELIVERY_SKIPPED,
+ "mBroadcastConsumerSkip");
};
/**
@@ -1068,7 +1105,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
* cancelled, usually as a result of it matching a predicate.
*/
private final BroadcastConsumer mBroadcastConsumerSkipAndCanceled = (r, i) -> {
- setDeliveryState(null, null, r, i, r.receivers.get(i), BroadcastRecord.DELIVERY_SKIPPED);
+ setDeliveryState(null, null, r, i, r.receivers.get(i), BroadcastRecord.DELIVERY_SKIPPED,
+ "mBroadcastConsumerSkipAndCanceled");
r.resultCode = Activity.RESULT_CANCELED;
r.resultData = null;
r.resultExtras = null;
@@ -1260,18 +1298,6 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
}
}
- private int traceBegin(String trackName, String methodName) {
- final int cookie = methodName.hashCode();
- Trace.asyncTraceForTrackBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
- trackName, methodName, cookie);
- return cookie;
- }
-
- private void traceEnd(String trackName, int cookie) {
- Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER,
- trackName, cookie);
- }
-
private void updateWarmProcess(@NonNull BroadcastProcessQueue queue) {
if (!queue.isProcessWarm()) {
queue.setProcess(mService.getProcessRecordLocked(queue.processName, queue.uid));
diff --git a/services/core/java/com/android/server/am/BroadcastSkipPolicy.java b/services/core/java/com/android/server/am/BroadcastSkipPolicy.java
index 60fddf0c7f22..481ab17b609e 100644
--- a/services/core/java/com/android/server/am/BroadcastSkipPolicy.java
+++ b/services/core/java/com/android/server/am/BroadcastSkipPolicy.java
@@ -21,6 +21,7 @@ import static com.android.server.am.ActivityManagerService.checkComponentPermiss
import static com.android.server.am.BroadcastQueue.TAG;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.AppGlobals;
import android.app.AppOpsManager;
@@ -42,6 +43,8 @@ import android.util.Slog;
import com.android.internal.util.ArrayUtils;
+import java.util.Objects;
+
/**
* Policy logic that decides if delivery of a particular {@link BroadcastRecord}
* should be skipped for a given {@link ResolveInfo} or {@link BroadcastFilter}.
@@ -51,8 +54,8 @@ import com.android.internal.util.ArrayUtils;
public class BroadcastSkipPolicy {
private final ActivityManagerService mService;
- public BroadcastSkipPolicy(ActivityManagerService service) {
- mService = service;
+ public BroadcastSkipPolicy(@NonNull ActivityManagerService service) {
+ mService = Objects.requireNonNull(service);
}
/**
@@ -60,18 +63,39 @@ public class BroadcastSkipPolicy {
* the given {@link BroadcastFilter} or {@link ResolveInfo}.
*/
public boolean shouldSkip(@NonNull BroadcastRecord r, @NonNull Object target) {
+ final String msg = shouldSkipMessage(r, target);
+ if (msg != null) {
+ Slog.w(TAG, msg);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Determine if the given {@link BroadcastRecord} is eligible to be sent to
+ * the given {@link BroadcastFilter} or {@link ResolveInfo}.
+ *
+ * @return message indicating why the argument should be skipped, otherwise
+ * {@code null} if it can proceed.
+ */
+ public @Nullable String shouldSkipMessage(@NonNull BroadcastRecord r, @NonNull Object target) {
if (target instanceof BroadcastFilter) {
- return shouldSkip(r, (BroadcastFilter) target);
+ return shouldSkipMessage(r, (BroadcastFilter) target);
} else {
- return shouldSkip(r, (ResolveInfo) target);
+ return shouldSkipMessage(r, (ResolveInfo) target);
}
}
/**
* Determine if the given {@link BroadcastRecord} is eligible to be sent to
* the given {@link ResolveInfo}.
+ *
+ * @return message indicating why the argument should be skipped, otherwise
+ * {@code null} if it can proceed.
*/
- public boolean shouldSkip(@NonNull BroadcastRecord r, @NonNull ResolveInfo info) {
+ private @Nullable String shouldSkipMessage(@NonNull BroadcastRecord r,
+ @NonNull ResolveInfo info) {
final BroadcastOptions brOptions = r.options;
final ComponentName component = new ComponentName(
info.activityInfo.applicationInfo.packageName,
@@ -82,58 +106,52 @@ public class BroadcastSkipPolicy {
< brOptions.getMinManifestReceiverApiLevel() ||
info.activityInfo.applicationInfo.targetSdkVersion
> brOptions.getMaxManifestReceiverApiLevel())) {
- Slog.w(TAG, "Target SDK mismatch: receiver " + info.activityInfo
+ return "Target SDK mismatch: receiver " + info.activityInfo
+ " targets " + info.activityInfo.applicationInfo.targetSdkVersion
+ " but delivery restricted to ["
+ brOptions.getMinManifestReceiverApiLevel() + ", "
+ brOptions.getMaxManifestReceiverApiLevel()
- + "] broadcasting " + broadcastDescription(r, component));
- return true;
+ + "] broadcasting " + broadcastDescription(r, component);
}
if (brOptions != null &&
!brOptions.testRequireCompatChange(info.activityInfo.applicationInfo.uid)) {
- Slog.w(TAG, "Compat change filtered: broadcasting " + broadcastDescription(r, component)
+ return "Compat change filtered: broadcasting " + broadcastDescription(r, component)
+ " to uid " + info.activityInfo.applicationInfo.uid + " due to compat change "
- + r.options.getRequireCompatChangeId());
- return true;
+ + r.options.getRequireCompatChangeId();
}
if (!mService.validateAssociationAllowedLocked(r.callerPackage, r.callingUid,
component.getPackageName(), info.activityInfo.applicationInfo.uid)) {
- Slog.w(TAG, "Association not allowed: broadcasting "
- + broadcastDescription(r, component));
- return true;
+ return "Association not allowed: broadcasting "
+ + broadcastDescription(r, component);
}
if (!mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid,
r.callingPid, r.resolvedType, info.activityInfo.applicationInfo.uid)) {
- Slog.w(TAG, "Firewall blocked: broadcasting "
- + broadcastDescription(r, component));
- return true;
+ return "Firewall blocked: broadcasting "
+ + broadcastDescription(r, component);
}
int perm = checkComponentPermission(info.activityInfo.permission,
r.callingPid, r.callingUid, info.activityInfo.applicationInfo.uid,
info.activityInfo.exported);
if (perm != PackageManager.PERMISSION_GRANTED) {
if (!info.activityInfo.exported) {
- Slog.w(TAG, "Permission Denial: broadcasting "
+ return "Permission Denial: broadcasting "
+ broadcastDescription(r, component)
- + " is not exported from uid " + info.activityInfo.applicationInfo.uid);
+ + " is not exported from uid " + info.activityInfo.applicationInfo.uid;
} else {
- Slog.w(TAG, "Permission Denial: broadcasting "
+ return "Permission Denial: broadcasting "
+ broadcastDescription(r, component)
- + " requires " + info.activityInfo.permission);
+ + " requires " + info.activityInfo.permission;
}
- return true;
} else if (info.activityInfo.permission != null) {
final int opCode = AppOpsManager.permissionToOpCode(info.activityInfo.permission);
if (opCode != AppOpsManager.OP_NONE && mService.getAppOpsManager().noteOpNoThrow(opCode,
r.callingUid, r.callerPackage, r.callerFeatureId,
"Broadcast delivered to " + info.activityInfo.name)
!= AppOpsManager.MODE_ALLOWED) {
- Slog.w(TAG, "Appop Denial: broadcasting "
+ return "Appop Denial: broadcasting "
+ broadcastDescription(r, component)
+ " requires appop " + AppOpsManager.permissionToOp(
- info.activityInfo.permission));
- return true;
+ info.activityInfo.permission);
}
}
@@ -142,38 +160,34 @@ public class BroadcastSkipPolicy {
android.Manifest.permission.INTERACT_ACROSS_USERS,
info.activityInfo.applicationInfo.uid)
!= PackageManager.PERMISSION_GRANTED) {
- Slog.w(TAG, "Permission Denial: Receiver " + component.flattenToShortString()
+ return "Permission Denial: Receiver " + component.flattenToShortString()
+ " requests FLAG_SINGLE_USER, but app does not hold "
- + android.Manifest.permission.INTERACT_ACROSS_USERS);
- return true;
+ + android.Manifest.permission.INTERACT_ACROSS_USERS;
}
}
if (info.activityInfo.applicationInfo.isInstantApp()
&& r.callingUid != info.activityInfo.applicationInfo.uid) {
- Slog.w(TAG, "Instant App Denial: receiving "
+ return "Instant App Denial: receiving "
+ r.intent
+ " to " + component.flattenToShortString()
+ " due to sender " + r.callerPackage
+ " (uid " + r.callingUid + ")"
- + " Instant Apps do not support manifest receivers");
- return true;
+ + " Instant Apps do not support manifest receivers";
}
if (r.callerInstantApp
&& (info.activityInfo.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) == 0
&& r.callingUid != info.activityInfo.applicationInfo.uid) {
- Slog.w(TAG, "Instant App Denial: receiving "
+ return "Instant App Denial: receiving "
+ r.intent
+ " to " + component.flattenToShortString()
+ " requires receiver have visibleToInstantApps set"
+ " due to sender " + r.callerPackage
- + " (uid " + r.callingUid + ")");
- return true;
+ + " (uid " + r.callingUid + ")";
}
if (r.curApp != null && r.curApp.mErrorState.isCrashing()) {
// If the target process is crashing, just skip it.
- Slog.w(TAG, "Skipping deliver ordered [" + r.queue.toString() + "] " + r
- + " to " + r.curApp + ": process crashing");
- return true;
+ return "Skipping deliver ordered [" + r.queue.toString() + "] " + r
+ + " to " + r.curApp + ": process crashing";
}
boolean isAvailable = false;
@@ -183,15 +197,13 @@ public class BroadcastSkipPolicy {
UserHandle.getUserId(info.activityInfo.applicationInfo.uid));
} catch (Exception e) {
// all such failures mean we skip this receiver
- Slog.w(TAG, "Exception getting recipient info for "
- + info.activityInfo.packageName, e);
+ return "Exception getting recipient info for "
+ + info.activityInfo.packageName;
}
if (!isAvailable) {
- Slog.w(TAG,
- "Skipping delivery to " + info.activityInfo.packageName + " / "
+ return "Skipping delivery to " + info.activityInfo.packageName + " / "
+ info.activityInfo.applicationInfo.uid
- + " : package no longer available");
- return true;
+ + " : package no longer available";
}
// If permissions need a review before any of the app components can run, we drop
@@ -201,10 +213,8 @@ public class BroadcastSkipPolicy {
if (!requestStartTargetPermissionsReviewIfNeededLocked(r,
info.activityInfo.packageName, UserHandle.getUserId(
info.activityInfo.applicationInfo.uid))) {
- Slog.w(TAG,
- "Skipping delivery: permission review required for "
- + broadcastDescription(r, component));
- return true;
+ return "Skipping delivery: permission review required for "
+ + broadcastDescription(r, component);
}
final int allowed = mService.getAppStartModeLOSP(
@@ -216,10 +226,9 @@ public class BroadcastSkipPolicy {
// to it and the app is in a state that should not receive it
// (depending on how getAppStartModeLOSP has determined that).
if (allowed == ActivityManager.APP_START_MODE_DISABLED) {
- Slog.w(TAG, "Background execution disabled: receiving "
+ return "Background execution disabled: receiving "
+ r.intent + " to "
- + component.flattenToShortString());
- return true;
+ + component.flattenToShortString();
} else if (((r.intent.getFlags()&Intent.FLAG_RECEIVER_EXCLUDE_BACKGROUND) != 0)
|| (r.intent.getComponent() == null
&& r.intent.getPackage() == null
@@ -228,10 +237,9 @@ public class BroadcastSkipPolicy {
&& !isSignaturePerm(r.requiredPermissions))) {
mService.addBackgroundCheckViolationLocked(r.intent.getAction(),
component.getPackageName());
- Slog.w(TAG, "Background execution not allowed: receiving "
+ return "Background execution not allowed: receiving "
+ r.intent + " to "
- + component.flattenToShortString());
- return true;
+ + component.flattenToShortString();
}
}
@@ -239,10 +247,8 @@ public class BroadcastSkipPolicy {
&& !mService.mUserController
.isUserRunning(UserHandle.getUserId(info.activityInfo.applicationInfo.uid),
0 /* flags */)) {
- Slog.w(TAG,
- "Skipping delivery to " + info.activityInfo.packageName + " / "
- + info.activityInfo.applicationInfo.uid + " : user is not running");
- return true;
+ return "Skipping delivery to " + info.activityInfo.packageName + " / "
+ + info.activityInfo.applicationInfo.uid + " : user is not running";
}
if (r.excludedPermissions != null && r.excludedPermissions.length > 0) {
@@ -268,13 +274,15 @@ public class BroadcastSkipPolicy {
info.activityInfo.applicationInfo.uid,
info.activityInfo.packageName)
== AppOpsManager.MODE_ALLOWED)) {
- return true;
+ return "Skipping delivery to " + info.activityInfo.packageName
+ + " due to excluded permission " + excludedPermission;
}
} else {
// When there is no app op associated with the permission,
// skip when permission is granted.
if (perm == PackageManager.PERMISSION_GRANTED) {
- return true;
+ return "Skipping delivery to " + info.activityInfo.packageName
+ + " due to excluded permission " + excludedPermission;
}
}
}
@@ -283,13 +291,12 @@ public class BroadcastSkipPolicy {
// Check that the receiver does *not* belong to any of the excluded packages
if (r.excludedPackages != null && r.excludedPackages.length > 0) {
if (ArrayUtils.contains(r.excludedPackages, component.getPackageName())) {
- Slog.w(TAG, "Skipping delivery of excluded package "
+ return "Skipping delivery of excluded package "
+ r.intent + " to "
+ component.flattenToShortString()
+ " excludes package " + component.getPackageName()
+ " due to sender " + r.callerPackage
- + " (uid " + r.callingUid + ")");
- return true;
+ + " (uid " + r.callingUid + ")";
}
}
@@ -307,95 +314,94 @@ public class BroadcastSkipPolicy {
perm = PackageManager.PERMISSION_DENIED;
}
if (perm != PackageManager.PERMISSION_GRANTED) {
- Slog.w(TAG, "Permission Denial: receiving "
+ return "Permission Denial: receiving "
+ r.intent + " to "
+ component.flattenToShortString()
+ " requires " + requiredPermission
+ " due to sender " + r.callerPackage
- + " (uid " + r.callingUid + ")");
- return true;
+ + " (uid " + r.callingUid + ")";
}
int appOp = AppOpsManager.permissionToOpCode(requiredPermission);
if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp) {
if (!noteOpForManifestReceiver(appOp, r, info, component)) {
- return true;
+ return "Skipping delivery to " + info.activityInfo.packageName
+ + " due to required appop " + appOp;
}
}
}
}
if (r.appOp != AppOpsManager.OP_NONE) {
if (!noteOpForManifestReceiver(r.appOp, r, info, component)) {
- return true;
+ return "Skipping delivery to " + info.activityInfo.packageName
+ + " due to required appop " + r.appOp;
}
}
- return false;
+ return null;
}
/**
* Determine if the given {@link BroadcastRecord} is eligible to be sent to
* the given {@link BroadcastFilter}.
+ *
+ * @return message indicating why the argument should be skipped, otherwise
+ * {@code null} if it can proceed.
*/
- public boolean shouldSkip(@NonNull BroadcastRecord r, @NonNull BroadcastFilter filter) {
+ private @Nullable String shouldSkipMessage(@NonNull BroadcastRecord r,
+ @NonNull BroadcastFilter filter) {
if (r.options != null && !r.options.testRequireCompatChange(filter.owningUid)) {
- Slog.w(TAG, "Compat change filtered: broadcasting " + r.intent.toString()
+ return "Compat change filtered: broadcasting " + r.intent.toString()
+ " to uid " + filter.owningUid + " due to compat change "
- + r.options.getRequireCompatChangeId());
- return true;
+ + r.options.getRequireCompatChangeId();
}
if (!mService.validateAssociationAllowedLocked(r.callerPackage, r.callingUid,
filter.packageName, filter.owningUid)) {
- Slog.w(TAG, "Association not allowed: broadcasting "
+ return "Association not allowed: broadcasting "
+ r.intent.toString()
+ " from " + r.callerPackage + " (pid=" + r.callingPid
+ ", uid=" + r.callingUid + ") to " + filter.packageName + " through "
- + filter);
- return true;
+ + filter;
}
if (!mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid,
r.callingPid, r.resolvedType, filter.receiverList.uid)) {
- Slog.w(TAG, "Firewall blocked: broadcasting "
+ return "Firewall blocked: broadcasting "
+ r.intent.toString()
+ " from " + r.callerPackage + " (pid=" + r.callingPid
+ ", uid=" + r.callingUid + ") to " + filter.packageName + " through "
- + filter);
- return true;
+ + filter;
}
// Check that the sender has permission to send to this receiver
if (filter.requiredPermission != null) {
int perm = checkComponentPermission(filter.requiredPermission,
r.callingPid, r.callingUid, -1, true);
if (perm != PackageManager.PERMISSION_GRANTED) {
- Slog.w(TAG, "Permission Denial: broadcasting "
+ return "Permission Denial: broadcasting "
+ r.intent.toString()
+ " from " + r.callerPackage + " (pid="
+ r.callingPid + ", uid=" + r.callingUid + ")"
+ " requires " + filter.requiredPermission
- + " due to registered receiver " + filter);
- return true;
+ + " due to registered receiver " + filter;
} else {
final int opCode = AppOpsManager.permissionToOpCode(filter.requiredPermission);
if (opCode != AppOpsManager.OP_NONE
&& mService.getAppOpsManager().noteOpNoThrow(opCode, r.callingUid,
r.callerPackage, r.callerFeatureId, "Broadcast sent to protected receiver")
!= AppOpsManager.MODE_ALLOWED) {
- Slog.w(TAG, "Appop Denial: broadcasting "
+ return "Appop Denial: broadcasting "
+ r.intent.toString()
+ " from " + r.callerPackage + " (pid="
+ r.callingPid + ", uid=" + r.callingUid + ")"
+ " requires appop " + AppOpsManager.permissionToOp(
filter.requiredPermission)
- + " due to registered receiver " + filter);
- return true;
+ + " due to registered receiver " + filter;
}
}
}
if ((filter.receiverList.app == null || filter.receiverList.app.isKilled()
|| filter.receiverList.app.mErrorState.isCrashing())) {
- Slog.w(TAG, "Skipping deliver [" + r.queue.toString() + "] " + r
- + " to " + filter.receiverList + ": process gone or crashing");
- return true;
+ return "Skipping deliver [" + r.queue.toString() + "] " + r
+ + " to " + filter.receiverList + ": process gone or crashing";
}
// Ensure that broadcasts are only sent to other Instant Apps if they are marked as
@@ -405,28 +411,26 @@ public class BroadcastSkipPolicy {
if (!visibleToInstantApps && filter.instantApp
&& filter.receiverList.uid != r.callingUid) {
- Slog.w(TAG, "Instant App Denial: receiving "
+ return "Instant App Denial: receiving "
+ r.intent.toString()
+ " to " + filter.receiverList.app
+ " (pid=" + filter.receiverList.pid
+ ", uid=" + filter.receiverList.uid + ")"
+ " due to sender " + r.callerPackage
+ " (uid " + r.callingUid + ")"
- + " not specifying FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS");
- return true;
+ + " not specifying FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS";
}
if (!filter.visibleToInstantApp && r.callerInstantApp
&& filter.receiverList.uid != r.callingUid) {
- Slog.w(TAG, "Instant App Denial: receiving "
+ return "Instant App Denial: receiving "
+ r.intent.toString()
+ " to " + filter.receiverList.app
+ " (pid=" + filter.receiverList.pid
+ ", uid=" + filter.receiverList.uid + ")"
+ " requires receiver be visible to instant apps"
+ " due to sender " + r.callerPackage
- + " (uid " + r.callingUid + ")");
- return true;
+ + " (uid " + r.callingUid + ")";
}
// Check that the receiver has the required permission(s) to receive this broadcast.
@@ -436,15 +440,14 @@ public class BroadcastSkipPolicy {
int perm = checkComponentPermission(requiredPermission,
filter.receiverList.pid, filter.receiverList.uid, -1, true);
if (perm != PackageManager.PERMISSION_GRANTED) {
- Slog.w(TAG, "Permission Denial: receiving "
+ return "Permission Denial: receiving "
+ r.intent.toString()
+ " to " + filter.receiverList.app
+ " (pid=" + filter.receiverList.pid
+ ", uid=" + filter.receiverList.uid + ")"
+ " requires " + requiredPermission
+ " due to sender " + r.callerPackage
- + " (uid " + r.callingUid + ")");
- return true;
+ + " (uid " + r.callingUid + ")";
}
int appOp = AppOpsManager.permissionToOpCode(requiredPermission);
if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp
@@ -452,7 +455,7 @@ public class BroadcastSkipPolicy {
filter.receiverList.uid, filter.packageName, filter.featureId,
"Broadcast delivered to registered receiver " + filter.receiverId)
!= AppOpsManager.MODE_ALLOWED) {
- Slog.w(TAG, "Appop Denial: receiving "
+ return "Appop Denial: receiving "
+ r.intent.toString()
+ " to " + filter.receiverList.app
+ " (pid=" + filter.receiverList.pid
@@ -460,8 +463,7 @@ public class BroadcastSkipPolicy {
+ " requires appop " + AppOpsManager.permissionToOp(
requiredPermission)
+ " due to sender " + r.callerPackage
- + " (uid " + r.callingUid + ")");
- return true;
+ + " (uid " + r.callingUid + ")";
}
}
}
@@ -469,14 +471,13 @@ public class BroadcastSkipPolicy {
int perm = checkComponentPermission(null,
filter.receiverList.pid, filter.receiverList.uid, -1, true);
if (perm != PackageManager.PERMISSION_GRANTED) {
- Slog.w(TAG, "Permission Denial: security check failed when receiving "
+ return "Permission Denial: security check failed when receiving "
+ r.intent.toString()
+ " to " + filter.receiverList.app
+ " (pid=" + filter.receiverList.pid
+ ", uid=" + filter.receiverList.uid + ")"
+ " due to sender " + r.callerPackage
- + " (uid " + r.callingUid + ")");
- return true;
+ + " (uid " + r.callingUid + ")";
}
}
// Check that the receiver does *not* have any excluded permissions
@@ -496,7 +497,7 @@ public class BroadcastSkipPolicy {
filter.receiverList.uid,
filter.packageName)
== AppOpsManager.MODE_ALLOWED)) {
- Slog.w(TAG, "Appop Denial: receiving "
+ return "Appop Denial: receiving "
+ r.intent.toString()
+ " to " + filter.receiverList.app
+ " (pid=" + filter.receiverList.pid
@@ -504,22 +505,20 @@ public class BroadcastSkipPolicy {
+ " excludes appop " + AppOpsManager.permissionToOp(
excludedPermission)
+ " due to sender " + r.callerPackage
- + " (uid " + r.callingUid + ")");
- return true;
+ + " (uid " + r.callingUid + ")";
}
} else {
// When there is no app op associated with the permission,
// skip when permission is granted.
if (perm == PackageManager.PERMISSION_GRANTED) {
- Slog.w(TAG, "Permission Denial: receiving "
+ return "Permission Denial: receiving "
+ r.intent.toString()
+ " to " + filter.receiverList.app
+ " (pid=" + filter.receiverList.pid
+ ", uid=" + filter.receiverList.uid + ")"
+ " excludes " + excludedPermission
+ " due to sender " + r.callerPackage
- + " (uid " + r.callingUid + ")");
- return true;
+ + " (uid " + r.callingUid + ")";
}
}
}
@@ -528,15 +527,14 @@ public class BroadcastSkipPolicy {
// Check that the receiver does *not* belong to any of the excluded packages
if (r.excludedPackages != null && r.excludedPackages.length > 0) {
if (ArrayUtils.contains(r.excludedPackages, filter.packageName)) {
- Slog.w(TAG, "Skipping delivery of excluded package "
+ return "Skipping delivery of excluded package "
+ r.intent.toString()
+ " to " + filter.receiverList.app
+ " (pid=" + filter.receiverList.pid
+ ", uid=" + filter.receiverList.uid + ")"
+ " excludes package " + filter.packageName
+ " due to sender " + r.callerPackage
- + " (uid " + r.callingUid + ")");
- return true;
+ + " (uid " + r.callingUid + ")";
}
}
@@ -546,15 +544,14 @@ public class BroadcastSkipPolicy {
filter.receiverList.uid, filter.packageName, filter.featureId,
"Broadcast delivered to registered receiver " + filter.receiverId)
!= AppOpsManager.MODE_ALLOWED) {
- Slog.w(TAG, "Appop Denial: receiving "
+ return "Appop Denial: receiving "
+ r.intent.toString()
+ " to " + filter.receiverList.app
+ " (pid=" + filter.receiverList.pid
+ ", uid=" + filter.receiverList.uid + ")"
+ " requires appop " + AppOpsManager.opToName(r.appOp)
+ " due to sender " + r.callerPackage
- + " (uid " + r.callingUid + ")");
- return true;
+ + " (uid " + r.callingUid + ")";
}
// Ensure that broadcasts are only sent to other apps if they are explicitly marked as
@@ -562,15 +559,14 @@ public class BroadcastSkipPolicy {
if (!filter.exported && checkComponentPermission(null, r.callingPid,
r.callingUid, filter.receiverList.uid, filter.exported)
!= PackageManager.PERMISSION_GRANTED) {
- Slog.w(TAG, "Exported Denial: sending "
+ return "Exported Denial: sending "
+ r.intent.toString()
+ ", action: " + r.intent.getAction()
+ " from " + r.callerPackage
+ " (uid=" + r.callingUid + ")"
+ " due to receiver " + filter.receiverList.app
+ " (uid " + filter.receiverList.uid + ")"
- + " not specifying RECEIVER_EXPORTED");
- return true;
+ + " not specifying RECEIVER_EXPORTED";
}
// If permissions need a review before any of the app components can run, we drop
@@ -579,10 +575,10 @@ public class BroadcastSkipPolicy {
// broadcast.
if (!requestStartTargetPermissionsReviewIfNeededLocked(r, filter.packageName,
filter.owningUserId)) {
- return true;
+ return "Skipping delivery to " + filter.packageName + " due to permissions review";
}
- return false;
+ return null;
}
private static String broadcastDescription(BroadcastRecord r, ComponentName component) {
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 e1a4c1dd7256..de5960363fa5 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
@@ -280,13 +280,13 @@ public class BroadcastQueueTest {
constants.TIMEOUT = 100;
constants.ALLOW_BG_ACTIVITY_START_TIMEOUT = 0;
final BroadcastSkipPolicy emptySkipPolicy = new BroadcastSkipPolicy(mAms) {
- public boolean shouldSkip(BroadcastRecord r, ResolveInfo info) {
+ public boolean shouldSkip(BroadcastRecord r, Object o) {
// Ignored
return false;
}
- public boolean shouldSkip(BroadcastRecord r, BroadcastFilter filter) {
+ public String shouldSkipMessage(BroadcastRecord r, Object o) {
// Ignored
- return false;
+ return null;
}
};
final BroadcastHistory emptyHistory = new BroadcastHistory(constants) {