Merge "BroadcastQueue: blocked registered receivers."

This commit is contained in:
Sudheer Shanka
2023-01-13 22:36:23 +00:00
committed by Android (Google) Code Review
10 changed files with 241 additions and 105 deletions

View File

@@ -784,9 +784,10 @@ public final class ActivityThread extends ClientTransactionHandler
static final class ReceiverData extends BroadcastReceiver.PendingResult {
public ReceiverData(Intent intent, int resultCode, String resultData, Bundle resultExtras,
boolean ordered, boolean sticky, IBinder token, int sendingUser) {
boolean ordered, boolean sticky, boolean assumeDelivered, IBinder token,
int sendingUser) {
super(resultCode, resultData, resultExtras, TYPE_COMPONENT, ordered, sticky,
token, sendingUser, intent.getFlags());
assumeDelivered, token, sendingUser, intent.getFlags());
this.intent = intent;
}
@@ -1040,10 +1041,10 @@ public final class ActivityThread extends ClientTransactionHandler
public final void scheduleReceiver(Intent intent, ActivityInfo info,
CompatibilityInfo compatInfo, int resultCode, String data, Bundle extras,
boolean sync, int sendingUser, int processState) {
boolean ordered, boolean assumeDelivered, int sendingUser, int processState) {
updateProcessState(processState, false);
ReceiverData r = new ReceiverData(intent, resultCode, data, extras,
sync, false, mAppThread.asBinder(), sendingUser);
ordered, false, assumeDelivered, mAppThread.asBinder(), sendingUser);
r.info = info;
sendMessage(H.RECEIVER, r);
}
@@ -1054,11 +1055,11 @@ public final class ActivityThread extends ClientTransactionHandler
if (r.registered) {
scheduleRegisteredReceiver(r.receiver, r.intent,
r.resultCode, r.data, r.extras, r.ordered, r.sticky,
r.sendingUser, r.processState);
r.assumeDelivered, r.sendingUser, r.processState);
} else {
scheduleReceiver(r.intent, r.activityInfo, r.compatInfo,
r.resultCode, r.data, r.extras, r.sync,
r.sendingUser, r.processState);
r.assumeDelivered, r.sendingUser, r.processState);
}
}
}
@@ -1288,10 +1289,25 @@ public final class ActivityThread extends ClientTransactionHandler
// applies transaction ordering per object for such calls.
public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
int resultCode, String dataStr, Bundle extras, boolean ordered,
boolean sticky, int sendingUser, int processState) throws RemoteException {
boolean sticky, boolean assumeDelivered, int sendingUser, int processState)
throws RemoteException {
updateProcessState(processState, false);
receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
sticky, sendingUser);
// We can't modify IIntentReceiver due to UnsupportedAppUsage, so
// try our best to shortcut to known subclasses, and alert if
// registered using a custom IIntentReceiver that isn't able to
// report an expected delivery event
if (receiver instanceof LoadedApk.ReceiverDispatcher.InnerReceiver) {
((LoadedApk.ReceiverDispatcher.InnerReceiver) receiver).performReceive(intent,
resultCode, dataStr, extras, ordered, sticky, assumeDelivered, sendingUser);
} else {
if (!assumeDelivered) {
Log.wtf(TAG, "scheduleRegisteredReceiver() called for " + receiver
+ " and " + intent + " without mechanism to finish delivery");
}
receiver.performReceive(intent, resultCode, dataStr, extras, ordered, sticky,
sendingUser);
}
}
@Override

View File

@@ -65,8 +65,8 @@ import java.util.Map;
oneway interface IApplicationThread {
void scheduleReceiver(in Intent intent, in ActivityInfo info,
in CompatibilityInfo compatInfo,
int resultCode, in String data, in Bundle extras, boolean sync,
int sendingUser, int processState);
int resultCode, in String data, in Bundle extras, boolean ordered,
boolean assumeDelivered, int sendingUser, int processState);
void scheduleReceiverList(in List<ReceiverInfo> info);
@@ -102,7 +102,7 @@ oneway interface IApplicationThread {
in String[] args);
void scheduleRegisteredReceiver(IIntentReceiver receiver, in Intent intent,
int resultCode, in String data, in Bundle extras, boolean ordered,
boolean sticky, int sendingUser, int processState);
boolean sticky, boolean assumeDelivered, int sendingUser, int processState);
void scheduleLowMemory();
void profilerControl(boolean start, in ProfilerInfo profilerInfo, int profileType);
void setSchedulingGroup(int group);

View File

@@ -1679,6 +1679,16 @@ public final class LoadedApk {
@Override
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
Log.wtf(TAG, "performReceive() called targeting raw IIntentReceiver for " + intent);
performReceive(intent, resultCode, data, extras, ordered, sticky,
BroadcastReceiver.PendingResult.guessAssumeDelivered(
BroadcastReceiver.PendingResult.TYPE_REGISTERED, ordered),
sendingUser);
}
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, boolean assumeDelivered,
int sendingUser) {
final LoadedApk.ReceiverDispatcher rd;
if (intent == null) {
Log.wtf(TAG, "Null intent received");
@@ -1693,8 +1703,8 @@ public final class LoadedApk {
}
if (rd != null) {
rd.performReceive(intent, resultCode, data, extras,
ordered, sticky, sendingUser);
} else {
ordered, sticky, assumeDelivered, sendingUser);
} else if (!assumeDelivered) {
// The activity manager dispatched a broadcast to a registered
// receiver in this process, but before it could be delivered the
// receiver was unregistered. Acknowledge the broadcast on its
@@ -1729,30 +1739,26 @@ public final class LoadedApk {
final class Args extends BroadcastReceiver.PendingResult {
private Intent mCurIntent;
private final boolean mOrdered;
private boolean mDispatched;
private boolean mRunCalled;
public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras,
boolean ordered, boolean sticky, int sendingUser) {
boolean ordered, boolean sticky, boolean assumeDelivered, int sendingUser) {
super(resultCode, resultData, resultExtras,
mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED, ordered,
sticky, mAppThread.asBinder(), sendingUser, intent.getFlags());
sticky, assumeDelivered, mAppThread.asBinder(), sendingUser,
intent.getFlags());
mCurIntent = intent;
mOrdered = ordered;
}
public final Runnable getRunnable() {
return () -> {
final BroadcastReceiver receiver = mReceiver;
final boolean ordered = mOrdered;
if (ActivityThread.DEBUG_BROADCAST) {
int seq = mCurIntent.getIntExtra("seq", -1);
Slog.i(ActivityThread.TAG, "Dispatching broadcast " + mCurIntent.getAction()
+ " seq=" + seq + " to " + mReceiver);
Slog.i(ActivityThread.TAG, " mRegistered=" + mRegistered
+ " mOrderedHint=" + ordered);
}
final IActivityManager mgr = ActivityManager.getService();
@@ -1766,11 +1772,9 @@ public final class LoadedApk {
mDispatched = true;
mRunCalled = true;
if (receiver == null || intent == null || mForgotten) {
if (mRegistered && ordered) {
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing null broadcast to " + mReceiver);
sendFinished(mgr);
}
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing null broadcast to " + mReceiver);
sendFinished(mgr);
return;
}
@@ -1790,11 +1794,9 @@ public final class LoadedApk {
receiver.setPendingResult(this);
receiver.onReceive(mContext, intent);
} catch (Exception e) {
if (mRegistered && ordered) {
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing failed broadcast to " + mReceiver);
sendFinished(mgr);
}
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing failed broadcast to " + mReceiver);
sendFinished(mgr);
if (mInstrumentation == null ||
!mInstrumentation.onException(mReceiver, e)) {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
@@ -1868,9 +1870,10 @@ public final class LoadedApk {
}
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
Bundle extras, boolean ordered, boolean sticky, boolean assumeDelivered,
int sendingUser) {
final Args args = new Args(intent, resultCode, data, extras, ordered,
sticky, sendingUser);
sticky, assumeDelivered, sendingUser);
if (intent == null) {
Log.wtf(TAG, "Null intent received");
} else {
@@ -1881,12 +1884,10 @@ public final class LoadedApk {
}
}
if (intent == null || !mActivityThread.post(args.getRunnable())) {
if (mRegistered && ordered) {
IActivityManager mgr = ActivityManager.getService();
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing sync broadcast to " + mReceiver);
args.sendFinished(mgr);
}
IActivityManager mgr = ActivityManager.getService();
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing sync broadcast to " + mReceiver);
args.sendFinished(mgr);
}
}

View File

@@ -34,6 +34,7 @@ parcelable ReceiverInfo {
Intent intent;
String data;
Bundle extras;
boolean assumeDelivered;
int sendingUser;
int processState;
int resultCode;

View File

@@ -82,6 +82,7 @@ public abstract class BroadcastReceiver {
final boolean mOrderedHint;
@UnsupportedAppUsage
final boolean mInitialStickyHint;
final boolean mAssumeDeliveredHint;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
final IBinder mToken;
@UnsupportedAppUsage
@@ -105,17 +106,38 @@ public abstract class BroadcastReceiver {
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public PendingResult(int resultCode, String resultData, Bundle resultExtras, int type,
boolean ordered, boolean sticky, IBinder token, int userId, int flags) {
this(resultCode, resultData, resultExtras, type, ordered, sticky,
guessAssumeDelivered(type, ordered), token, userId, flags);
}
/** @hide */
public PendingResult(int resultCode, String resultData, Bundle resultExtras, int type,
boolean ordered, boolean sticky, boolean assumeDelivered, IBinder token,
int userId, int flags) {
mResultCode = resultCode;
mResultData = resultData;
mResultExtras = resultExtras;
mType = type;
mOrderedHint = ordered;
mInitialStickyHint = sticky;
mAssumeDeliveredHint = assumeDelivered;
mToken = token;
mSendingUser = userId;
mFlags = flags;
}
/** @hide */
public static boolean guessAssumeDelivered(int type, boolean ordered) {
// When a caller didn't provide a concrete way of knowing if we need
// to report delivery, make a best-effort guess
if (type == TYPE_COMPONENT) {
return false;
} else if (ordered && type != TYPE_UNREGISTERED) {
return false;
}
return true;
}
/**
* Version of {@link BroadcastReceiver#setResultCode(int)
* BroadcastReceiver.setResultCode(int)} for
@@ -252,7 +274,7 @@ public abstract class BroadcastReceiver {
"Finishing broadcast to component " + mToken);
sendFinished(mgr);
}
} else if (mOrderedHint && mType != TYPE_UNREGISTERED) {
} else {
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing broadcast to " + mToken);
final IActivityManager mgr = ActivityManager.getService();
@@ -279,13 +301,16 @@ public abstract class BroadcastReceiver {
if (mResultExtras != null) {
mResultExtras.setAllowFds(false);
}
if (mOrderedHint) {
am.finishReceiver(mToken, mResultCode, mResultData, mResultExtras,
mAbortBroadcast, mFlags);
} else {
// This broadcast was sent to a component; it is not ordered,
// but we still need to tell the activity manager we are done.
am.finishReceiver(mToken, 0, null, null, false, mFlags);
// When the OS didn't assume delivery, we need to inform
// it that we've actually finished the delivery
if (!mAssumeDeliveredHint) {
if (mOrderedHint) {
am.finishReceiver(mToken, mResultCode, mResultData, mResultExtras,
mAbortBroadcast, mFlags);
} else {
am.finishReceiver(mToken, 0, null, null, false, mFlags);
}
}
} catch (RemoteException ex) {
}

View File

@@ -397,11 +397,12 @@ public class BroadcastQueueImpl extends BroadcastQueue {
+ ": " + r);
mService.notifyPackageUse(r.intent.getComponent().getPackageName(),
PackageManager.NOTIFY_PACKAGE_USE_BROADCAST_RECEIVER);
final boolean assumeDelivered = false;
thread.scheduleReceiverList(mReceiverBatch.manifestReceiver(
prepareReceiverIntent(r.intent, r.curFilteredExtras),
r.curReceiver, null /* compatInfo (unused but need to keep method signature) */,
r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId,
app.mState.getReportedProcState()));
r.resultCode, r.resultData, r.resultExtras, r.ordered, assumeDelivered,
r.userId, app.mState.getReportedProcState()));
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Process cur broadcast " + r + " DELIVERED for app " + app);
started = true;
@@ -735,9 +736,10 @@ public class BroadcastQueueImpl extends BroadcastQueue {
// If we have an app thread, do the call through that so it is
// correctly ordered with other one-way calls.
try {
final boolean assumeDelivered = !ordered;
thread.scheduleReceiverList(mReceiverBatch.registeredReceiver(
receiver, intent, resultCode,
data, extras, ordered, sticky, sendingUser,
data, extras, ordered, sticky, assumeDelivered, sendingUser,
app.mState.getReportedProcState()));
} catch (RemoteException ex) {
// Failed to call into the process. It's either dying or wedged. Kill it gently.

View File

@@ -888,21 +888,26 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
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, r.userId,
r.ordered, r.initialSticky, assumeDelivered, r.userId,
app.mState.getReportedProcState(), r, index);
// TODO: consider making registered receivers of unordered
// broadcasts report results to detect ANRs
if (!r.ordered) {
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, r.userId,
app.mState.getReportedProcState(), r, index);
null, r.resultCode, r.resultData, r.resultExtras, r.ordered, assumeDelivered,
r.userId, app.mState.getReportedProcState(), r, index);
if (assumeDelivered) {
batch.success(r, index, BroadcastRecord.DELIVERY_DELIVERED, "assuming delivered");
return true;
}
}
return false;
@@ -991,7 +996,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
* Return true if this receiver should be assumed to have been delivered.
*/
private boolean isAssumedDelivered(BroadcastRecord r, int index) {
return (r.receivers.get(index) instanceof BroadcastFilter) && !r.ordered;
return (r.receivers.get(index) instanceof BroadcastFilter) && !r.ordered
&& (r.resultTo == null);
}
/**
@@ -1050,10 +1056,11 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
mService.mOomAdjuster.mCachedAppOptimizer.unfreezeTemporarily(
app, OOM_ADJ_REASON_FINISH_RECEIVER);
try {
final boolean assumeDelivered = true;
thread.scheduleReceiverList(mReceiverBatch.registeredReceiver(
r.resultTo, r.intent,
r.resultCode, r.resultData, r.resultExtras, false, r.initialSticky,
r.userId, app.mState.getReportedProcState()));
assumeDelivered, r.userId, app.mState.getReportedProcState()));
} catch (RemoteException e) {
final String msg = "Failed to schedule result of " + r + " via " + app + ": " + e;
logw(msg);

View File

@@ -19,8 +19,8 @@ package com.android.server.am;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ReceiverInfo;
import android.content.Intent;
import android.content.IIntentReceiver;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.res.CompatibilityInfo;
import android.os.Bundle;
@@ -171,12 +171,13 @@ final class BroadcastReceiverBatch {
// 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, int sendingUser, int processState,
boolean sticky, boolean assumeDelivered, int sendingUser, 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;
@@ -190,12 +191,13 @@ final class BroadcastReceiverBatch {
// 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, int sendingUser, int processState,
@Nullable BroadcastRecord r, int index) {
@Nullable Bundle extras, boolean sync, boolean assumeDelivered, int sendingUser,
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;
@@ -214,10 +216,10 @@ final class BroadcastReceiverBatch {
*/
ArrayList<ReceiverInfo> registeredReceiver(@Nullable IIntentReceiver receiver,
@Nullable Intent intent, int resultCode, @Nullable String data,
@Nullable Bundle extras, boolean ordered, boolean sticky,
@Nullable Bundle extras, boolean ordered, boolean sticky, boolean assumeDelivered,
int sendingUser, int processState) {
reset();
schedule(receiver, intent, resultCode, data, extras, ordered, sticky,
schedule(receiver, intent, resultCode, data, extras, ordered, sticky, assumeDelivered,
sendingUser, processState, null, 0);
return receivers();
}
@@ -225,9 +227,9 @@ final class BroadcastReceiverBatch {
ArrayList<ReceiverInfo> manifestReceiver(@Nullable Intent intent,
@Nullable ActivityInfo activityInfo, @Nullable CompatibilityInfo compatInfo,
int resultCode, @Nullable String data, @Nullable Bundle extras, boolean sync,
int sendingUser, int processState) {
boolean assumeDelivered, int sendingUser, int processState) {
reset();
schedule(intent, activityInfo, compatInfo, resultCode, data, extras, sync,
schedule(intent, activityInfo, compatInfo, resultCode, data, extras, sync, assumeDelivered,
sendingUser, processState, null, 0);
return receivers();
}
@@ -255,6 +257,7 @@ final class BroadcastReceiverBatch {
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;

View File

@@ -47,12 +47,12 @@ public class SameProcessApplicationThread extends IApplicationThread.Default {
@Override
public void scheduleReceiver(Intent intent, ActivityInfo info, CompatibilityInfo compatInfo,
int resultCode, String data, Bundle extras, boolean sync, int sendingUser,
int processState) {
int resultCode, String data, Bundle extras, boolean ordered, boolean assumeDelivered,
int sendingUser, int processState) {
mHandler.post(() -> {
try {
mWrapped.scheduleReceiver(intent, info, compatInfo, resultCode, data, extras, sync,
sendingUser, processState);
mWrapped.scheduleReceiver(intent, info, compatInfo, resultCode, data, extras,
ordered, assumeDelivered, sendingUser, processState);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
@@ -61,12 +61,12 @@ public class SameProcessApplicationThread extends IApplicationThread.Default {
@Override
public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent, int resultCode,
String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser,
int processState) {
String data, Bundle extras, boolean ordered, boolean sticky, boolean assumeDelivered,
int sendingUser, int processState) {
mHandler.post(() -> {
try {
mWrapped.scheduleRegisteredReceiver(receiver, intent, resultCode, data, extras,
ordered, sticky, sendingUser, processState);
ordered, sticky, assumeDelivered, sendingUser, processState);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
@@ -79,11 +79,11 @@ public class SameProcessApplicationThread extends IApplicationThread.Default {
ReceiverInfo r = info.get(i);
if (r.registered) {
scheduleRegisteredReceiver(r.receiver, r.intent,
r.resultCode, r.data, r.extras, r.ordered, r.sticky,
r.resultCode, r.data, r.extras, r.ordered, r.sticky, r.assumeDelivered,
r.sendingUser, r.processState);
} else {
scheduleReceiver(r.intent, r.activityInfo, r.compatInfo,
r.resultCode, r.data, r.extras, r.sync,
r.resultCode, r.data, r.extras, r.sync, r.assumeDelivered,
r.sendingUser, r.processState);
}
}

View File

@@ -92,6 +92,7 @@ import com.android.server.appop.AppOpsService;
import com.android.server.wm.ActivityTaskManagerService;
import org.junit.After;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -447,9 +448,9 @@ public class BroadcastQueueTest {
UnaryOperator<Bundle> extrasOperator, ReceiverInfo info) {
final Intent intent = info.intent;
final Bundle extras = info.extras;
final boolean ordered = info.ordered;
final boolean assumeDelivered = info.assumeDelivered;
mScheduledBroadcasts.add(makeScheduledBroadcast(r, intent));
if (!wedge && ordered) {
if (!wedge && !assumeDelivered) {
assertTrue(r.mReceivers.numberOfCurReceivers() > 0);
assertNotEquals(ProcessList.SCHED_GROUP_UNDEFINED,
mQueue.getPreferredSchedulingGroupLocked(r));
@@ -700,6 +701,7 @@ public class BroadcastQueueTest {
ArgumentMatcher<String> data,
ArgumentMatcher<Bundle> extras,
Boolean sync,
Boolean assumeDelivered,
Integer sendingUser,
Integer processState) {
return (test) -> {
@@ -711,6 +713,7 @@ public class BroadcastQueueTest {
&& matchObject(data, test.data)
&& matchObject(extras, test.extras)
&& matchElement(sync, test.sync)
&& matchElement(assumeDelivered, test.assumeDelivered)
&& matchElement(sendingUser, test.sendingUser)
&& matchElement(processState, test.processState);
};
@@ -729,10 +732,12 @@ public class BroadcastQueueTest {
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, sendingUser, processState)));
resultCode, data, extras, sync, assumeDelivered,
sendingUser, processState)));
}
/**
@@ -748,6 +753,7 @@ public class BroadcastQueueTest {
ArgumentMatcher<Bundle> extras,
Boolean ordered,
Boolean sticky,
Boolean assumeDelivered,
Integer sendingUser,
Integer processState) {
return (test) -> {
@@ -759,6 +765,7 @@ public class BroadcastQueueTest {
&& matchObject(extras, test.extras)
&& matchElement(ordered, test.ordered)
&& matchElement(sticky, test.sticky)
&& matchElement(assumeDelivered, test.assumeDelivered)
&& matchElement(sendingUser, test.sendingUser)
&& matchElement(processState, test.processState);
};
@@ -776,10 +783,12 @@ public class BroadcastQueueTest {
ArgumentMatcher<Bundle> extras,
Boolean ordered,
Boolean sticky,
Boolean assumeDelivered,
Integer sendingUser,
Integer processState) {
return argThat(receiverList(registeredReceiverMatcher(receiver, intent, resultCode,
data, extras, ordered, sticky, sendingUser, processState)));
data, extras, ordered, sticky, assumeDelivered,
sendingUser, processState)));
}
/**
@@ -832,36 +841,36 @@ public class BroadcastQueueTest {
final Intent targetedIntent = new Intent(intent);
targetedIntent.setComponent(component);
verify(app.getThread(), mode).scheduleReceiverList(
manifestReceiver(filterEquals(targetedIntent),
null, null, null, null, null, null, UserHandle.USER_SYSTEM, null));
manifestReceiver(filterEquals(targetedIntent),
null, null, null, null, null, null, null, UserHandle.USER_SYSTEM, null));
}
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, userId, null));
manifestReceiver(filterEqualsIgnoringComponent(intent),
null, null, null, null, null, null, null, userId, null));
}
private void verifyScheduleReceiver(VerificationMode mode, ProcessRecord app,
int userId) throws Exception {
verify(app.getThread(), mode).scheduleReceiverList(
manifestReceiver(null,
null, null, null, null, null, null, userId, null));
null, null, null, null, null, null, null, userId, null));
}
private void verifyScheduleRegisteredReceiver(ProcessRecord app,
Intent intent) throws Exception {
verify(app.getThread()).scheduleReceiverList(
registeredReceiver(null, filterEqualsIgnoringComponent(intent),
null, null, null, null, null, UserHandle.USER_SYSTEM, null));
registeredReceiver(null, filterEqualsIgnoringComponent(intent),
null, null, null, null, null, null, UserHandle.USER_SYSTEM, null));
}
private void verifyScheduleRegisteredReceiver(VerificationMode mode, ProcessRecord app,
int userId) throws Exception {
verify(app.getThread(), mode).scheduleReceiverList(
registeredReceiver(null, null,
null, null, null, null, null, userId, null));
null, null, null, null, null, null, userId, null));
}
static final int USER_GUEST = 11;
@@ -1117,10 +1126,11 @@ public class BroadcastQueueTest {
}
/**
* Verify that we detect and ANR a wedged process.
* Verify that we detect and ANR a wedged process when delivering to a
* manifest receiver.
*/
@Test
public void testWedged() throws Exception {
public void testWedged_Manifest() throws Exception {
final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED);
final ProcessRecord receiverApp = makeActiveProcessRecord(PACKAGE_GREEN,
ProcessBehavior.WEDGE);
@@ -1133,6 +1143,77 @@ public class BroadcastQueueTest {
verify(mAms).appNotResponding(eq(receiverApp), any());
}
/**
* Verify that we detect and ANR a wedged process when delivering an ordered
* broadcast, and that we deliver final result.
*/
@Test
public void testWedged_Registered_Ordered() throws Exception {
// Legacy stack doesn't detect these ANRs; likely an oversight
Assume.assumeTrue(mImpl == Impl.MODERN);
final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED);
final ProcessRecord receiverApp = makeActiveProcessRecord(PACKAGE_GREEN,
ProcessBehavior.WEDGE);
final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
final IIntentReceiver resultTo = mock(IIntentReceiver.class);
enqueueBroadcast(makeOrderedBroadcastRecord(airplane, callerApp,
List.of(makeRegisteredReceiver(receiverApp)), resultTo, null));
waitForIdle();
verify(mAms).appNotResponding(eq(receiverApp), any());
verifyScheduleRegisteredReceiver(callerApp, airplane);
}
/**
* Verify that we detect and ANR a wedged process when delivering an
* unordered broadcast with a {@code resultTo}.
*/
@Test
public void testWedged_Registered_ResultTo() throws Exception {
// Legacy stack doesn't detect these ANRs; likely an oversight
Assume.assumeTrue(mImpl == Impl.MODERN);
final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED);
final ProcessRecord receiverApp = makeActiveProcessRecord(PACKAGE_GREEN,
ProcessBehavior.WEDGE);
final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
final IIntentReceiver resultTo = mock(IIntentReceiver.class);
enqueueBroadcast(makeBroadcastRecord(airplane, callerApp,
List.of(makeRegisteredReceiver(receiverApp)), resultTo));
waitForIdle();
verify(mAms).appNotResponding(eq(receiverApp), any());
verifyScheduleRegisteredReceiver(callerApp, airplane);
}
/**
* Verify that we detect and ANR a wedged process when delivering a
* broadcast with more than one priority tranche.
*/
@Test
public void testWedged_Registered_Prioritized() throws Exception {
// Legacy stack doesn't detect these ANRs; likely an oversight
Assume.assumeTrue(mImpl == Impl.MODERN);
final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED);
final ProcessRecord receiverGreenApp = makeActiveProcessRecord(PACKAGE_GREEN,
ProcessBehavior.WEDGE);
final ProcessRecord receiverBlueApp = makeActiveProcessRecord(PACKAGE_BLUE,
ProcessBehavior.NORMAL);
final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
enqueueBroadcast(makeBroadcastRecord(airplane, callerApp,
List.of(makeRegisteredReceiver(receiverGreenApp, 10),
makeRegisteredReceiver(receiverBlueApp, 5))));
waitForIdle();
verify(mAms).appNotResponding(eq(receiverGreenApp), any());
verifyScheduleRegisteredReceiver(receiverBlueApp, airplane);
}
/**
* Verify that we handle registered receivers in a process that always
* responds with {@link DeadObjectException}, recovering to restart the
@@ -1343,11 +1424,11 @@ public class BroadcastQueueTest {
// Confirm that we saw no registered receiver traffic
final IApplicationThread oldThread = oldApp.getThread();
verify(oldThread, never()).scheduleRegisteredReceiver(any(),
any(), anyInt(), any(), any(), anyBoolean(), anyBoolean(), anyInt(), anyInt());
verify(oldThread, never()).scheduleRegisteredReceiver(any(), any(), anyInt(), any(), any(),
anyBoolean(), anyBoolean(), anyBoolean(), anyInt(), anyInt());
final IApplicationThread newThread = newApp.getThread();
verify(newThread, never()).scheduleRegisteredReceiver(any(),
any(), anyInt(), any(), any(), anyBoolean(), anyBoolean(), anyInt(), anyInt());
verify(newThread, never()).scheduleRegisteredReceiver(any(), any(), anyInt(), any(), any(),
anyBoolean(), anyBoolean(), anyBoolean(), anyInt(), anyInt());
// Confirm that we saw final manifest broadcast
verifyScheduleReceiver(times(1), newApp, airplane,
@@ -1469,22 +1550,22 @@ public class BroadcastQueueTest {
expectedExtras.putBoolean(PACKAGE_RED, true);
inOrder.verify(greenThread).scheduleReceiverList(manifestReceiver(
filterEqualsIgnoringComponent(airplane), null, null,
Activity.RESULT_OK, null, bundleEquals(expectedExtras), true,
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,
Activity.RESULT_OK, null, bundleEquals(expectedExtras), true, false,
UserHandle.USER_SYSTEM, null));
expectedExtras.putBoolean(PACKAGE_BLUE, true);
inOrder.verify(yellowThread).scheduleReceiverList(manifestReceiver(
filterEqualsIgnoringComponent(airplane), null, null,
Activity.RESULT_OK, null, bundleEquals(expectedExtras), true,
Activity.RESULT_OK, null, bundleEquals(expectedExtras), true, false,
UserHandle.USER_SYSTEM, null));
expectedExtras.putBoolean(PACKAGE_YELLOW, true);
inOrder.verify(redThread).scheduleReceiverList(registeredReceiver(
null, filterEquals(airplane),
Activity.RESULT_OK, null, bundleEquals(expectedExtras), false,
null, UserHandle.USER_SYSTEM, null));
null, true, UserHandle.USER_SYSTEM, null));
// Finally, verify that we thawed the final receiver
verify(mAms.mOomAdjuster.mCachedAppOptimizer).unfreezeTemporarily(eq(callerApp),
@@ -1549,22 +1630,22 @@ public class BroadcastQueueTest {
final InOrder inOrder = inOrder(greenThread, blueThread, redThread);
inOrder.verify(greenThread).scheduleReceiverList(manifestReceiver(
filterEqualsIgnoringComponent(intent), null, null,
Activity.RESULT_OK, null, null, true, UserHandle.USER_SYSTEM,
Activity.RESULT_OK, null, null, true, false, UserHandle.USER_SYSTEM,
null));
if ((intent.getFlags() & Intent.FLAG_RECEIVER_NO_ABORT) != 0) {
inOrder.verify(blueThread).scheduleReceiverList(manifestReceiver(
filterEqualsIgnoringComponent(intent), null, null,
Activity.RESULT_OK, null, null, true, UserHandle.USER_SYSTEM,
Activity.RESULT_OK, null, null, true, false, UserHandle.USER_SYSTEM,
null));
} else {
inOrder.verify(blueThread, never()).scheduleReceiverList(manifestReceiver(
null, null, null, null,
null, null, null, null, null,
null, null, null, null, null));
}
inOrder.verify(redThread).scheduleReceiverList(registeredReceiver(
null, filterEquals(intent),
Activity.RESULT_OK, null, bundleEquals(expectedExtras),
false, null, UserHandle.USER_SYSTEM, null));
false, null, true, UserHandle.USER_SYSTEM, null));
}
/**
@@ -1587,7 +1668,7 @@ public class BroadcastQueueTest {
verify(callerThread).scheduleReceiverList(registeredReceiver(
null, filterEquals(airplane),
Activity.RESULT_OK, null, bundleEquals(orderedExtras), false,
null, UserHandle.USER_SYSTEM, null));
null, true, UserHandle.USER_SYSTEM, null));
}
/**
@@ -1608,7 +1689,7 @@ public class BroadcastQueueTest {
verify(callerThread).scheduleReceiverList(registeredReceiver(
null, filterEquals(airplane),
Activity.RESULT_OK, null, null, false,
null, UserHandle.USER_SYSTEM, null));
null, true, UserHandle.USER_SYSTEM, null));
}
/**
@@ -1773,26 +1854,26 @@ public class BroadcastQueueTest {
// First broadcast is canceled
inOrder.verify(callerThread).scheduleReceiverList(registeredReceiver(null,
filterAndExtrasEquals(timezoneFirst), Activity.RESULT_CANCELED, null,
null, false, null, UserHandle.USER_SYSTEM, null));
null, false, null, true, UserHandle.USER_SYSTEM, null));
// 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, null, null));
null, null, null, null, null, true, false, null, null));
// Second broadcast is finished
timezoneSecond.setComponent(null);
inOrder.verify(callerThread).scheduleReceiverList(registeredReceiver(null,
filterAndExtrasEquals(timezoneSecond), Activity.RESULT_OK, null,
null, false, null, UserHandle.USER_SYSTEM, null));
null, false, null, true, UserHandle.USER_SYSTEM, null));
// 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, null, null));
null, null, null, null, null, false, false, null, null));
}
@Test