Merge "BroadcastQueue: blocked registered receivers."
This commit is contained in:
committed by
Android (Google) Code Review
commit
7ad565016d
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ parcelable ReceiverInfo {
|
||||
Intent intent;
|
||||
String data;
|
||||
Bundle extras;
|
||||
boolean assumeDelivered;
|
||||
int sendingUser;
|
||||
int processState;
|
||||
int resultCode;
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user