Merge changes from topic "oct11"
* changes:
BroadcastQueue: Handle successor ProcessRecords.
More robust ProcessRecord routing for resultTo.
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 81aa6da..b803070 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -420,10 +420,11 @@
public abstract int broadcastIntentInPackage(String packageName, @Nullable String featureId,
int uid, int realCallingUid, int realCallingPid, Intent intent, String resolvedType,
- IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras,
- String requiredPermission, Bundle bOptions, boolean serialized, boolean sticky,
- @UserIdInt int userId, boolean allowBackgroundActivityStarts,
- @Nullable IBinder backgroundActivityStartsToken, @Nullable int[] broadcastAllowList);
+ IApplicationThread resultToThread, IIntentReceiver resultTo, int resultCode,
+ String resultData, Bundle resultExtras, String requiredPermission, Bundle bOptions,
+ boolean serialized, boolean sticky, @UserIdInt int userId,
+ boolean allowBackgroundActivityStarts, @Nullable IBinder backgroundActivityStartsToken,
+ @Nullable int[] broadcastAllowList);
public abstract ComponentName startServiceInPackage(int uid, Intent service,
String resolvedType, boolean fgRequired, String callingPackage,
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 6404a1f..7475ef8 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -556,7 +556,8 @@
void startConfirmDeviceCredentialIntent(in Intent intent, in Bundle options);
@UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
void sendIdleJobTrigger();
- int sendIntentSender(in IIntentSender target, in IBinder whitelistToken, int code,
+ int sendIntentSender(in IApplicationThread caller, in IIntentSender target,
+ in IBinder whitelistToken, int code,
in Intent intent, in String resolvedType, in IIntentReceiver finishedReceiver,
in String requiredPermission, in Bundle options);
boolean isBackgroundRestricted(in String packageName);
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index bc78df5..db47a4c 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -1009,7 +1009,9 @@
options = activityOptions.toBundle();
}
- return ActivityManager.getService().sendIntentSender(
+ final IApplicationThread app = ActivityThread.currentActivityThread()
+ .getApplicationThread();
+ return ActivityManager.getService().sendIntentSender(app,
mTarget, mWhitelistToken, code, intent, resolvedType,
onFinished != null
? new FinishedDispatcher(this, onFinished, handler)
diff --git a/core/java/android/content/IntentSender.java b/core/java/android/content/IntentSender.java
index b1252fd..8853b70 100644
--- a/core/java/android/content/IntentSender.java
+++ b/core/java/android/content/IntentSender.java
@@ -18,6 +18,8 @@
import android.annotation.Nullable;
import android.app.ActivityManager;
+import android.app.ActivityThread;
+import android.app.IApplicationThread;
import android.app.ActivityManager.PendingIntentInfo;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Bundle;
@@ -194,7 +196,9 @@
String resolvedType = intent != null ?
intent.resolveTypeIfNeeded(context.getContentResolver())
: null;
- int res = ActivityManager.getService().sendIntentSender(mTarget, mWhitelistToken,
+ final IApplicationThread app = ActivityThread.currentActivityThread()
+ .getApplicationThread();
+ int res = ActivityManager.getService().sendIntentSender(app, mTarget, mWhitelistToken,
code, intent, resolvedType,
onFinished != null
? new FinishedDispatcher(this, onFinished, handler)
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 1a4da7d..7a09109 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3902,12 +3902,13 @@
if (isInstantApp) {
intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
broadcastIntentInPackage("android", null, SYSTEM_UID, uid, pid, intent,
- null, null, 0, null, null, permission.ACCESS_INSTANT_APPS, null,
- false, false, resolvedUserId, false, null, visibilityAllowList);
+ null, null, null, 0, null, null, permission.ACCESS_INSTANT_APPS,
+ null, false, false, resolvedUserId, false, null,
+ visibilityAllowList);
} else {
broadcastIntentInPackage("android", null, SYSTEM_UID, uid, pid, intent,
- null, null, 0, null, null, null, null, false, false, resolvedUserId,
- false, null, visibilityAllowList);
+ null, null, null, 0, null, null, null, null, false, false,
+ resolvedUserId, false, null, visibilityAllowList);
}
if (observer != null) {
@@ -4444,7 +4445,8 @@
intent.putExtra(Intent.EXTRA_UID, uid);
intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
broadcastIntentLocked(null /* callerApp */, null /* callerPackage */,
- null /* callerFeatureId */, intent, null /* resolvedType */, null /* resultTo */,
+ null /* callerFeatureId */, intent, null /* resolvedType */,
+ null /* resultToApp */, null /* resultTo */,
0 /* resultCode */, null /* resultData */, null /* resultExtras */,
null /* requiredPermissions */, null /* excludedPermissions */,
null /* excludedPackages */, OP_NONE, null /* bOptions */, false /* ordered */,
@@ -5515,12 +5517,12 @@
}
@Override
- public int sendIntentSender(IIntentSender target, IBinder allowlistToken, int code,
- Intent intent, String resolvedType,
+ public int sendIntentSender(IApplicationThread caller, IIntentSender target,
+ IBinder allowlistToken, int code, Intent intent, String resolvedType,
IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
if (target instanceof PendingIntentRecord) {
- return ((PendingIntentRecord)target).sendWithResult(code, intent, resolvedType,
- allowlistToken, finishedReceiver, requiredPermission, options);
+ return ((PendingIntentRecord) target).sendWithResult(caller, code, intent,
+ resolvedType, allowlistToken, finishedReceiver, requiredPermission, options);
} else {
if (intent == null) {
// Weird case: someone has given us their own custom IIntentSender, and now
@@ -13586,8 +13588,8 @@
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, null,
null, null, -1, -1, false, null, null, null, null, OP_NONE, null,
- receivers, null, 0, null, null, false, true, true, -1, false, null,
- false /* only PRE_BOOT_COMPLETED should be exempt, no stickies */,
+ receivers, null, null, 0, null, null, false, true, true, -1, false,
+ null, false /* only PRE_BOOT_COMPLETED should be exempt, no stickies */,
null /* filterExtrasForReceiver */);
queue.enqueueBroadcastLocked(r);
}
@@ -13842,9 +13844,9 @@
boolean sticky, int callingPid,
int callingUid, int realCallingUid, int realCallingPid, int userId) {
return broadcastIntentLocked(callerApp, callerPackage, callerFeatureId, intent,
- resolvedType, resultTo, resultCode, resultData, resultExtras, requiredPermissions,
- excludedPermissions, excludedPackages, appOp, bOptions, ordered, sticky, callingPid,
- callingUid, realCallingUid, realCallingPid, userId,
+ resolvedType, null, resultTo, resultCode, resultData, resultExtras,
+ requiredPermissions, excludedPermissions, excludedPackages, appOp, bOptions,
+ ordered, sticky, callingPid, callingUid, realCallingUid, realCallingPid, userId,
false /* allowBackgroundActivityStarts */,
null /* tokenNeededForBackgroundActivityStarts */,
null /* broadcastAllowList */, null /* filterExtrasForReceiver */);
@@ -13853,7 +13855,7 @@
@GuardedBy("this")
final int broadcastIntentLocked(ProcessRecord callerApp, String callerPackage,
@Nullable String callerFeatureId, Intent intent, String resolvedType,
- IIntentReceiver resultTo, int resultCode, String resultData,
+ 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,
@@ -13862,6 +13864,18 @@
@Nullable IBinder backgroundActivityStartsToken,
@Nullable int[] broadcastAllowList,
@Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver) {
+ if ((resultTo != null) && (resultToApp == null)) {
+ if (resultTo.asBinder() instanceof BinderProxy) {
+ // Warn when requesting results without a way to deliver them
+ Slog.wtf(TAG, "Sending broadcast " + intent.getAction()
+ + " with resultTo requires resultToApp", new Throwable());
+ } else {
+ // If not a BinderProxy above, then resultTo is an in-process
+ // receiver, so splice in system_server process
+ resultToApp = getProcessRecordLocked("system", SYSTEM_UID);
+ }
+ }
+
intent = new Intent(intent);
final boolean callerInstantApp = isInstantApp(callerApp, callerPackage, callingUid);
@@ -14461,8 +14475,8 @@
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, excludedPermissions, excludedPackages, appOp, brOptions,
- registeredReceivers, resultTo, resultCode, resultData, resultExtras, ordered,
- sticky, false, userId, allowBackgroundActivityStarts,
+ registeredReceivers, resultToApp, resultTo, resultCode, resultData,
+ resultExtras, ordered, sticky, false, userId, allowBackgroundActivityStarts,
backgroundActivityStartsToken, timeoutExempt, filterExtrasForReceiver);
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
queue.enqueueBroadcastLocked(r);
@@ -14555,7 +14569,7 @@
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, excludedPermissions, excludedPackages, appOp, brOptions,
- receivers, resultTo, resultCode, resultData, resultExtras,
+ receivers, resultToApp, resultTo, resultCode, resultData, resultExtras,
ordered, sticky, false, userId, allowBackgroundActivityStarts,
backgroundActivityStartsToken, timeoutExempt, filterExtrasForReceiver);
@@ -14680,6 +14694,9 @@
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
+ // We're delivering the result to the caller
+ final ProcessRecord resultToApp = callerApp;
+
// Non-system callers can't declare that a broadcast is alarm-related.
// The PendingIntent invocation case is handled in PendingIntentRecord.
if (bOptions != null && callingUid != SYSTEM_UID) {
@@ -14697,9 +14714,10 @@
try {
return broadcastIntentLocked(callerApp,
callerApp != null ? callerApp.info.packageName : null, callingFeatureId,
- intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
- requiredPermissions, excludedPermissions, excludedPackages, appOp, bOptions,
- serialized, sticky, callingPid, callingUid, callingUid, callingPid, userId);
+ intent, resolvedType, resultToApp, resultTo, resultCode, resultData,
+ resultExtras, requiredPermissions, excludedPermissions, excludedPackages,
+ appOp, bOptions, serialized, sticky, callingPid, callingUid, callingUid,
+ callingPid, userId, false, null, null, null);
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -14709,11 +14727,10 @@
// Not the binder call surface
int broadcastIntentInPackage(String packageName, @Nullable String featureId, int uid,
int realCallingUid, int realCallingPid, Intent intent, String resolvedType,
- IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras,
- String requiredPermission, Bundle bOptions, boolean serialized, boolean sticky,
- int userId, boolean allowBackgroundActivityStarts,
- @Nullable IBinder backgroundActivityStartsToken,
- @Nullable int[] broadcastAllowList) {
+ ProcessRecord resultToApp, IIntentReceiver resultTo, int resultCode,
+ String resultData, Bundle resultExtras, String requiredPermission, Bundle bOptions,
+ boolean serialized, boolean sticky, int userId, boolean allowBackgroundActivityStarts,
+ @Nullable IBinder backgroundActivityStartsToken, @Nullable int[] broadcastAllowList) {
synchronized(this) {
intent = verifyBroadcastLocked(intent);
@@ -14722,9 +14739,9 @@
: new String[] {requiredPermission};
try {
return broadcastIntentLocked(null, packageName, featureId, intent, resolvedType,
- resultTo, resultCode, resultData, resultExtras, requiredPermissions, null,
- null, OP_NONE, bOptions, serialized, sticky, -1, uid, realCallingUid,
- realCallingPid, userId, allowBackgroundActivityStarts,
+ resultToApp, resultTo, resultCode, resultData, resultExtras,
+ requiredPermissions, null, null, OP_NONE, bOptions, serialized, sticky, -1,
+ uid, realCallingUid, realCallingPid, userId, allowBackgroundActivityStarts,
backgroundActivityStartsToken, broadcastAllowList,
null /* filterExtrasForReceiver */);
} finally {
@@ -17253,16 +17270,18 @@
@Override
public int broadcastIntentInPackage(String packageName, @Nullable String featureId, int uid,
int realCallingUid, int realCallingPid, Intent intent, String resolvedType,
- IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras,
- String requiredPermission, Bundle bOptions, boolean serialized, boolean sticky,
- int userId, boolean allowBackgroundActivityStarts,
+ IApplicationThread resultToThread, IIntentReceiver resultTo, int resultCode,
+ String resultData, Bundle resultExtras, String requiredPermission, Bundle bOptions,
+ boolean serialized, boolean sticky, int userId,
+ boolean allowBackgroundActivityStarts,
@Nullable IBinder backgroundActivityStartsToken,
@Nullable int[] broadcastAllowList) {
synchronized (ActivityManagerService.this) {
+ final ProcessRecord resultToApp = getRecordForAppLOSP(resultToThread);
return ActivityManagerService.this.broadcastIntentInPackage(packageName, featureId,
- uid, realCallingUid, realCallingPid, intent, resolvedType, resultTo,
- resultCode, resultData, resultExtras, requiredPermission, bOptions,
- serialized, sticky, userId, allowBackgroundActivityStarts,
+ uid, realCallingUid, realCallingPid, intent, resolvedType, resultToApp,
+ resultTo, resultCode, resultData, resultExtras, requiredPermission,
+ bOptions, serialized, sticky, userId, allowBackgroundActivityStarts,
backgroundActivityStartsToken, broadcastAllowList);
}
}
@@ -17283,8 +17302,9 @@
try {
return ActivityManagerService.this.broadcastIntentLocked(null /*callerApp*/,
null /*callerPackage*/, null /*callingFeatureId*/, intent,
- null /*resolvedType*/, resultTo, 0 /*resultCode*/, null /*resultData*/,
- null /*resultExtras*/, requiredPermissions,
+ null /* resolvedType */, null /* resultToApp */, resultTo,
+ 0 /* resultCode */, null /* resultData */,
+ null /* resultExtras */, requiredPermissions,
null /*excludedPermissions*/, null /*excludedPackages*/,
AppOpsManager.OP_NONE, bOptions /*options*/, serialized,
false /*sticky*/, callingPid, callingUid, callingUid, callingPid,
@@ -17897,7 +17917,7 @@
public int sendIntentSender(IIntentSender target, IBinder allowlistToken, int code,
Intent intent, String resolvedType,
IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
- return ActivityManagerService.this.sendIntentSender(target, allowlistToken, code,
+ return ActivityManagerService.this.sendIntentSender(null, target, allowlistToken, code,
intent, resolvedType, finishedReceiver, requiredPermission, options);
}
diff --git a/services/core/java/com/android/server/am/BroadcastProcessQueue.java b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
index 97635b5..0d6ac1d 100644
--- a/services/core/java/com/android/server/am/BroadcastProcessQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
@@ -114,6 +114,14 @@
private int mActiveIndex;
/**
+ * When defined, the receiver actively being dispatched into this process
+ * was considered "blocked" until at least the given count of other
+ * receivers have reached a terminal state; typically used for ordered
+ * broadcasts and priority traunches.
+ */
+ private int mActiveBlockedUntilTerminalCount;
+
+ /**
* Count of {@link #mActive} broadcasts that have been dispatched since this
* queue was last idle.
*/
@@ -304,6 +312,7 @@
final SomeArgs next = mPending.removeFirst();
mActive = (BroadcastRecord) next.arg1;
mActiveIndex = next.argi1;
+ mActiveBlockedUntilTerminalCount = next.argi2;
mActiveCountSinceIdle++;
mActiveViaColdStart = false;
next.recycle();
@@ -316,6 +325,7 @@
public void makeActiveIdle() {
mActive = null;
mActiveIndex = 0;
+ mActiveBlockedUntilTerminalCount = -1;
mActiveCountSinceIdle = 0;
mActiveViaColdStart = false;
invalidateRunnableAt();
@@ -664,27 +674,14 @@
}
pw.print(" because ");
pw.print(reasonToString(mRunnableAtReason));
- if (mRunnableAtReason == REASON_BLOCKED) {
- final SomeArgs next = mPending.peekFirst();
- if (next != null) {
- final BroadcastRecord r = (BroadcastRecord) next.arg1;
- final int blockedUntilTerminalCount = next.argi2;
- pw.print(" waiting for ");
- pw.print(blockedUntilTerminalCount);
- pw.print(" at ");
- pw.print(r.terminalCount);
- pw.print(" of ");
- pw.print(r.receivers.size());
- }
- }
pw.println();
pw.increaseIndent();
if (mActive != null) {
- dumpRecord(now, pw, mActive, mActiveIndex);
+ dumpRecord(now, pw, mActive, mActiveIndex, mActiveBlockedUntilTerminalCount);
}
for (SomeArgs args : mPending) {
final BroadcastRecord r = (BroadcastRecord) args.arg1;
- dumpRecord(now, pw, r, args.argi1);
+ dumpRecord(now, pw, r, args.argi1, args.argi2);
}
pw.decreaseIndent();
pw.println();
@@ -692,7 +689,7 @@
@NeverCompile
private void dumpRecord(@UptimeMillisLong long now, @NonNull IndentingPrintWriter pw,
- @NonNull BroadcastRecord record, int recordIndex) {
+ @NonNull BroadcastRecord record, int recordIndex, int blockedUntilTerminalCount) {
TimeUtils.formatDuration(record.enqueueTime, now, pw);
pw.print(' ');
pw.println(record.toShortString());
@@ -714,5 +711,13 @@
pw.print(info.activityInfo.name);
}
pw.println();
+ if (blockedUntilTerminalCount != -1) {
+ pw.print(" blocked until ");
+ pw.print(blockedUntilTerminalCount);
+ pw.print(", currently at ");
+ pw.print(record.terminalCount);
+ pw.print(" of ");
+ pw.println(record.receivers.size());
+ }
}
}
diff --git a/services/core/java/com/android/server/am/BroadcastQueueImpl.java b/services/core/java/com/android/server/am/BroadcastQueueImpl.java
index d7a075b..f34565b 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueImpl.java
@@ -262,7 +262,7 @@
if (oldRecord.resultTo != null) {
try {
oldRecord.mIsReceiverAppRunning = true;
- performReceiveLocked(oldRecord.callerApp, oldRecord.resultTo,
+ performReceiveLocked(oldRecord.resultToApp, oldRecord.resultTo,
oldRecord.intent,
Activity.RESULT_CANCELED, null, null,
false, false, oldRecord.userId, oldRecord.callingUid, r.callingUid,
@@ -1120,7 +1120,7 @@
r.dispatchTime = now;
}
r.mIsReceiverAppRunning = true;
- performReceiveLocked(r.callerApp, r.resultTo,
+ performReceiveLocked(r.resultToApp, r.resultTo,
new Intent(r.intent), r.resultCode,
r.resultData, r.resultExtras, false, false, r.userId,
r.callingUid, r.callingUid,
diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
index 89a0283..1e1ebeb 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
@@ -396,17 +396,12 @@
// Emit all trace events for this process into a consistent track
queue.traceTrackName = TAG + ".mRunning[" + queueIndex + "]";
- // If we're already warm, boost OOM adjust now; if cold we'll boost
- // it after the app has been started
- if (processWarm) {
- notifyStartedRunning(queue);
- }
-
// If we're already warm, schedule next pending broadcast now;
// otherwise we'll wait for the cold start to circle back around
queue.makeActiveNextPending();
if (processWarm) {
queue.traceProcessRunningBegin();
+ notifyStartedRunning(queue);
scheduleReceiverWarmLocked(queue);
} else {
queue.traceProcessStartingBegin();
@@ -441,15 +436,22 @@
@Override
public boolean onApplicationAttachedLocked(@NonNull ProcessRecord app) {
+ // Process records can be recycled, so always start by looking up the
+ // relevant per-process queue
+ final BroadcastProcessQueue queue = getProcessQueue(app);
+ if (queue != null) {
+ queue.app = app;
+ }
+
boolean didSomething = false;
- if ((mRunningColdStart != null) && (mRunningColdStart.app == app)) {
+ if ((mRunningColdStart != null) && (mRunningColdStart == queue)) {
// We've been waiting for this app to cold start, and it's ready
// now; dispatch its next broadcast and clear the slot
- final BroadcastProcessQueue queue = mRunningColdStart;
mRunningColdStart = null;
queue.traceProcessEnd();
queue.traceProcessRunningBegin();
+ notifyStartedRunning(queue);
scheduleReceiverWarmLocked(queue);
// We might be willing to kick off another cold start
@@ -471,19 +473,25 @@
@Override
public void onApplicationCleanupLocked(@NonNull ProcessRecord app) {
- if ((mRunningColdStart != null) && (mRunningColdStart.app == app)) {
+ // Process records can be recycled, so always start by looking up the
+ // relevant per-process queue
+ final BroadcastProcessQueue queue = getProcessQueue(app);
+ if (queue != null) {
+ queue.app = null;
+ }
+
+ if ((mRunningColdStart != null) && (mRunningColdStart == queue)) {
// We've been waiting for this app to cold start, and it had
// trouble; clear the slot and fail delivery below
mRunningColdStart = null;
+ queue.traceProcessEnd();
+
// We might be willing to kick off another cold start
enqueueUpdateRunningList();
}
- final BroadcastProcessQueue queue = getProcessQueue(app);
if (queue != null) {
- queue.app = null;
-
// If queue was running a broadcast, fail it
if (queue.isActive()) {
finishReceiverLocked(queue, BroadcastRecord.DELIVERY_FAILURE);
@@ -567,7 +575,7 @@
}
} else {
// Otherwise we don't need to block at all
- blockedUntilTerminalCount = 0;
+ blockedUntilTerminalCount = -1;
}
queue.enqueueOrReplaceBroadcast(r, i, blockedUntilTerminalCount);
@@ -619,9 +627,7 @@
if (DEBUG_BROADCAST) logv("Scheduling " + r + " to cold " + queue);
queue.app = mService.startProcessLocked(queue.processName, info, true, intentFlags,
hostingRecord, zygotePolicyFlags, allowWhileBooting, false);
- if (queue.app != null) {
- notifyStartedRunning(queue);
- } else {
+ if (queue.app == null) {
mRunningColdStart = null;
finishReceiverLocked(queue, BroadcastRecord.DELIVERY_FAILURE);
return;
@@ -749,8 +755,8 @@
* ordered broadcast; assumes the sender is still a warm process.
*/
private void scheduleResultTo(@NonNull BroadcastRecord r) {
- if ((r.callerApp == null) || (r.resultTo == null)) return;
- final ProcessRecord app = r.callerApp;
+ if ((r.resultToApp == null) || (r.resultTo == null)) return;
+ final ProcessRecord app = r.resultToApp;
final IApplicationThread thread = app.getThread();
if (thread != null) {
mService.mOomAdjuster.mCachedAppOptimizer.unfreezeTemporarily(
@@ -1159,6 +1165,12 @@
}
}
+ // Verify that pending cold start hasn't been orphaned
+ if (mRunningColdStart != null) {
+ checkState(getRunningIndexOf(mRunningColdStart) >= 0,
+ "isOrphaned " + mRunningColdStart);
+ }
+
// Verify health of all known process queues
for (int i = 0; i < mProcessQueues.size(); i++) {
BroadcastProcessQueue leaf = mProcessQueues.valueAt(i);
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index bcc76e9..2d82595 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -94,6 +94,7 @@
final @Nullable BroadcastOptions options; // BroadcastOptions supplied by caller
final @NonNull List<Object> receivers; // contains BroadcastFilter and ResolveInfo
final @DeliveryState int[] delivery; // delivery state of each receiver
+ @Nullable ProcessRecord resultToApp; // who receives final result if non-null
@Nullable IIntentReceiver resultTo; // who receives final result if non-null
boolean deferred;
int splitCount; // refcount for result callback, when split
@@ -345,7 +346,8 @@
boolean _callerInstantApp, String _resolvedType,
String[] _requiredPermissions, String[] _excludedPermissions,
String[] _excludedPackages, int _appOp,
- BroadcastOptions _options, List _receivers, IIntentReceiver _resultTo, int _resultCode,
+ BroadcastOptions _options, List _receivers,
+ ProcessRecord _resultToApp, IIntentReceiver _resultTo, int _resultCode,
String _resultData, Bundle _resultExtras, boolean _serialized, boolean _sticky,
boolean _initialSticky, int _userId, boolean allowBackgroundActivityStarts,
@Nullable IBinder backgroundActivityStartsToken, boolean timeoutExempt,
@@ -372,6 +374,7 @@
delivery = new int[_receivers != null ? _receivers.size() : 0];
scheduledTime = new long[delivery.length];
terminalTime = new long[delivery.length];
+ resultToApp = _resultToApp;
resultTo = _resultTo;
resultCode = _resultCode;
resultData = _resultData;
@@ -421,6 +424,7 @@
delivery = from.delivery;
scheduledTime = from.scheduledTime;
terminalTime = from.terminalTime;
+ resultToApp = from.resultToApp;
resultTo = from.resultTo;
enqueueTime = from.enqueueTime;
enqueueRealTime = from.enqueueRealTime;
@@ -480,8 +484,8 @@
BroadcastRecord split = new BroadcastRecord(queue, intent, callerApp, callerPackage,
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, excludedPermissions, excludedPackages, appOp, options,
- splitReceivers, resultTo, resultCode, resultData, resultExtras, ordered, sticky,
- initialSticky, userId, allowBackgroundActivityStarts,
+ splitReceivers, resultToApp, resultTo, resultCode, resultData, resultExtras,
+ ordered, sticky, initialSticky, userId, allowBackgroundActivityStarts,
mBackgroundActivityStartsToken, timeoutExempt, filterExtrasForReceiver);
split.enqueueTime = this.enqueueTime;
split.enqueueRealTime = this.enqueueRealTime;
@@ -559,7 +563,7 @@
final BroadcastRecord br = new BroadcastRecord(queue, intent, callerApp, callerPackage,
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, excludedPermissions, excludedPackages, appOp, options,
- uid2receiverList.valueAt(i), null /* _resultTo */,
+ uid2receiverList.valueAt(i), null /* _resultToApp */, null /* _resultTo */,
resultCode, resultData, resultExtras, ordered, sticky, initialSticky, userId,
allowBackgroundActivityStarts, mBackgroundActivityStartsToken, timeoutExempt,
filterExtrasForReceiver);
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index bda60ff..975619f 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -26,6 +26,7 @@
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.BroadcastOptions;
+import android.app.IApplicationThread;
import android.app.PendingIntent;
import android.content.IIntentReceiver;
import android.content.IIntentSender;
@@ -302,13 +303,21 @@
public void send(int code, Intent intent, String resolvedType, IBinder allowlistToken,
IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
- sendInner(code, intent, resolvedType, allowlistToken, finishedReceiver,
+ sendInner(null, code, intent, resolvedType, allowlistToken, finishedReceiver,
requiredPermission, null, null, 0, 0, 0, options);
}
- public int sendWithResult(int code, Intent intent, String resolvedType, IBinder allowlistToken,
- IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
- return sendInner(code, intent, resolvedType, allowlistToken, finishedReceiver,
+ public void send(IApplicationThread caller, int code, Intent intent, String resolvedType,
+ IBinder allowlistToken, IIntentReceiver finishedReceiver, String requiredPermission,
+ Bundle options) {
+ sendInner(caller, code, intent, resolvedType, allowlistToken, finishedReceiver,
+ requiredPermission, null, null, 0, 0, 0, options);
+ }
+
+ public int sendWithResult(IApplicationThread caller, int code, Intent intent,
+ String resolvedType, IBinder allowlistToken, IIntentReceiver finishedReceiver,
+ String requiredPermission, Bundle options) {
+ return sendInner(caller, code, intent, resolvedType, allowlistToken, finishedReceiver,
requiredPermission, null, null, 0, 0, 0, options);
}
@@ -339,9 +348,19 @@
ActivityOptions.PENDING_INTENT_BAL_ALLOWED_DEFAULT);
}
+ @Deprecated
public int sendInner(int code, Intent intent, String resolvedType, IBinder allowlistToken,
IIntentReceiver finishedReceiver, String requiredPermission, IBinder resultTo,
String resultWho, int requestCode, int flagsMask, int flagsValues, Bundle options) {
+ return sendInner(null, code, intent, resolvedType, allowlistToken, finishedReceiver,
+ requiredPermission, resultTo, resultWho, requestCode, flagsMask, flagsValues,
+ options);
+ }
+
+ public int sendInner(IApplicationThread caller, int code, Intent intent,
+ String resolvedType, IBinder allowlistToken, IIntentReceiver finishedReceiver,
+ String requiredPermission, IBinder resultTo, String resultWho, int requestCode,
+ int flagsMask, int flagsValues, Bundle options) {
if (intent != null) intent.setDefusable(true);
if (options != null) options.setDefusable(true);
@@ -468,6 +487,7 @@
}
}
+ final IApplicationThread finishedReceiverThread = caller;
boolean sendFinish = finishedReceiver != null;
int userId = key.userId;
if (userId == UserHandle.USER_CURRENT) {
@@ -525,9 +545,9 @@
// that the broadcast be delivered synchronously
int sent = controller.mAmInternal.broadcastIntentInPackage(key.packageName,
key.featureId, uid, callingUid, callingPid, finalIntent,
- resolvedType, finishedReceiver, code, null, null,
- requiredPermission, options, (finishedReceiver != null), false,
- userId, allowedByToken || allowTrampoline, bgStartsToken,
+ resolvedType, finishedReceiverThread, finishedReceiver, code, null,
+ null, requiredPermission, options, (finishedReceiver != null),
+ false, userId, allowedByToken || allowTrampoline, bgStartsToken,
null /* broadcastAllowList */);
if (sent == ActivityManager.BROADCAST_SUCCESS) {
sendFinish = false;
diff --git a/services/core/java/com/android/server/am/PreBootBroadcaster.java b/services/core/java/com/android/server/am/PreBootBroadcaster.java
index 9b7c3ac..77fcef6 100644
--- a/services/core/java/com/android/server/am/PreBootBroadcaster.java
+++ b/services/core/java/com/android/server/am/PreBootBroadcaster.java
@@ -57,7 +57,6 @@
private static final String TAG = "PreBootBroadcaster";
private final ActivityManagerService mService;
- private final ProcessRecord mSystemApp;
private final int mUserId;
private final ProgressReporter mProgress;
private final boolean mQuiet;
@@ -70,9 +69,6 @@
public PreBootBroadcaster(ActivityManagerService service, int userId,
ProgressReporter progress, boolean quiet) {
mService = service;
- synchronized (mService) {
- mSystemApp = mService.getProcessRecordLocked("system", android.os.Process.SYSTEM_UID);
- }
mUserId = userId;
mProgress = progress;
mQuiet = quiet;
@@ -127,7 +123,7 @@
TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
REASON_PRE_BOOT_COMPLETED, "");
synchronized (mService) {
- mService.broadcastIntentLocked(mSystemApp, "android", null, mIntent, null, this, 0,
+ mService.broadcastIntentLocked(null, null, null, mIntent, null, this, 0,
null, null, null, null, null, AppOpsManager.OP_NONE, bOptions.toBundle(), true,
false, ActivityManagerService.MY_PID,
Process.SYSTEM_UID, Binder.getCallingUid(), Binder.getCallingPid(), mUserId);
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
index 86915da..90b1f4e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
@@ -140,7 +140,7 @@
private BroadcastRecord makeBroadcastRecord(Intent intent, BroadcastOptions options,
List receivers, boolean ordered) {
return new BroadcastRecord(mImpl, intent, mProcess, PACKAGE_RED, null, 21, 42, false, null,
- null, null, null, AppOpsManager.OP_NONE, options, receivers, null,
+ null, null, null, AppOpsManager.OP_NONE, options, receivers, null, null,
Activity.RESULT_OK, null, null, ordered, false, false, UserHandle.USER_SYSTEM,
false, null, false, null);
}
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 076fce9..c125448 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
@@ -113,6 +113,7 @@
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
import java.util.function.UnaryOperator;
/**
@@ -154,10 +155,11 @@
private BroadcastQueue mQueue;
/**
- * When enabled {@link ActivityManagerService#startProcessLocked} will fail
- * by returning {@code null}; otherwise it will spawn a new mock process.
+ * Desired behavior of the next
+ * {@link ActivityManagerService#startProcessLocked} call.
*/
- private boolean mFailStartProcess;
+ private AtomicReference<ProcessStartBehavior> mNextProcessStartBehavior = new AtomicReference<>(
+ ProcessStartBehavior.SUCCESS);
/**
* Map from PID to registered registered runtime receivers.
@@ -216,16 +218,46 @@
doAnswer((invocation) -> {
Log.v(TAG, "Intercepting startProcessLocked() for "
+ Arrays.toString(invocation.getArguments()));
- if (mFailStartProcess) {
+ final ProcessStartBehavior behavior = mNextProcessStartBehavior
+ .getAndSet(ProcessStartBehavior.SUCCESS);
+ if (behavior == ProcessStartBehavior.FAIL_NULL) {
return null;
}
final String processName = invocation.getArgument(0);
final ApplicationInfo ai = invocation.getArgument(1);
final ProcessRecord res = makeActiveProcessRecord(ai, processName,
ProcessBehavior.NORMAL, UnaryOperator.identity());
+ final ProcessRecord deliverRes;
+ switch (behavior) {
+ case SUCCESS_PREDECESSOR:
+ case FAIL_TIMEOUT_PREDECESSOR:
+ // Create a different process that will be linked to the
+ // returned process via a predecessor/successor relationship
+ mActiveProcesses.remove(res);
+ deliverRes = makeActiveProcessRecord(ai, processName,
+ ProcessBehavior.NORMAL, UnaryOperator.identity());
+ deliverRes.mPredecessor = res;
+ res.mSuccessor = deliverRes;
+ break;
+ default:
+ deliverRes = res;
+ break;
+ }
mHandlerThread.getThreadHandler().post(() -> {
synchronized (mAms) {
- mQueue.onApplicationAttachedLocked(res);
+ switch (behavior) {
+ case SUCCESS:
+ case SUCCESS_PREDECESSOR:
+ mQueue.onApplicationAttachedLocked(deliverRes);
+ break;
+ case FAIL_TIMEOUT:
+ case FAIL_TIMEOUT_PREDECESSOR:
+ mActiveProcesses.remove(deliverRes);
+ mQueue.onApplicationTimeoutLocked(deliverRes);
+ break;
+ default:
+ throw new UnsupportedOperationException();
+ }
}
});
return res;
@@ -281,9 +313,10 @@
// Verify that all processes have finished handling broadcasts
for (ProcessRecord app : mActiveProcesses) {
- assertTrue(app.toShortString(), app.mReceivers.numberOfCurReceivers() == 0);
- assertTrue(app.toShortString(), mQueue.getPreferredSchedulingGroupLocked(app)
- == ProcessList.SCHED_GROUP_UNDEFINED);
+ assertEquals(app.toShortString(), 0,
+ app.mReceivers.numberOfCurReceivers());
+ assertEquals(app.toShortString(), ProcessList.SCHED_GROUP_UNDEFINED,
+ mQueue.getPreferredSchedulingGroupLocked(app));
}
}
@@ -325,6 +358,19 @@
}
}
+ private enum ProcessStartBehavior {
+ /** Process starts successfully */
+ SUCCESS,
+ /** Process starts successfully via predecessor */
+ SUCCESS_PREDECESSOR,
+ /** Process fails by reporting timeout */
+ FAIL_TIMEOUT,
+ /** Process fails by reporting timeout via predecessor */
+ FAIL_TIMEOUT_PREDECESSOR,
+ /** Process fails by immediately returning null */
+ FAIL_NULL,
+ }
+
private enum ProcessBehavior {
/** Process broadcasts normally */
NORMAL,
@@ -520,8 +566,8 @@
IIntentReceiver orderedResultTo, Bundle orderedExtras, int userId) {
return new BroadcastRecord(mQueue, intent, callerApp, callerApp.info.packageName, null,
callerApp.getPid(), callerApp.info.uid, false, null, null, null, null,
- AppOpsManager.OP_NONE, options, receivers, orderedResultTo, Activity.RESULT_OK,
- null, orderedExtras, ordered, false, false, userId, false, null,
+ AppOpsManager.OP_NONE, options, receivers, callerApp, orderedResultTo,
+ Activity.RESULT_OK, null, orderedExtras, ordered, false, false, userId, false, null,
false, null);
}
@@ -956,18 +1002,16 @@
final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED);
// Send broadcast while process starts are failing
- mFailStartProcess = true;
+ mNextProcessStartBehavior.set(ProcessStartBehavior.FAIL_NULL);
final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
enqueueBroadcast(makeBroadcastRecord(airplane, callerApp,
- List.of(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN),
- makeManifestReceiver(PACKAGE_YELLOW, CLASS_YELLOW))));
+ List.of(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN))));
// Confirm that queue goes idle, with no processes
waitForIdle();
assertEquals(1, mActiveProcesses.size());
// Send more broadcasts with working process starts
- mFailStartProcess = false;
final Intent timezone = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
enqueueBroadcast(makeBroadcastRecord(timezone, callerApp,
List.of(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN),
@@ -981,7 +1025,6 @@
final ProcessRecord receiverYellowApp = mAms.getProcessRecordLocked(PACKAGE_YELLOW,
getUidForPackage(PACKAGE_YELLOW));
verifyScheduleReceiver(never(), receiverGreenApp, airplane);
- verifyScheduleReceiver(never(), receiverYellowApp, airplane);
verifyScheduleReceiver(times(1), receiverGreenApp, timezone);
verifyScheduleReceiver(times(1), receiverYellowApp, timezone);
}
@@ -1071,6 +1114,52 @@
new ComponentName(PACKAGE_GREEN, CLASS_GREEN));
}
+ @Test
+ public void testCold_Success() throws Exception {
+ doCold(ProcessStartBehavior.SUCCESS);
+ }
+
+ @Test
+ public void testCold_Success_Predecessor() throws Exception {
+ doCold(ProcessStartBehavior.SUCCESS_PREDECESSOR);
+ }
+
+ @Test
+ public void testCold_Fail_Null() throws Exception {
+ doCold(ProcessStartBehavior.FAIL_NULL);
+ }
+
+ @Test
+ public void testCold_Fail_Timeout() throws Exception {
+ doCold(ProcessStartBehavior.FAIL_TIMEOUT);
+ }
+
+ @Test
+ public void testCold_Fail_Timeout_Predecessor() throws Exception {
+ doCold(ProcessStartBehavior.FAIL_TIMEOUT_PREDECESSOR);
+ }
+
+ private void doCold(ProcessStartBehavior behavior) throws Exception {
+ final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED);
+
+ mNextProcessStartBehavior.set(behavior);
+ final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+ enqueueBroadcast(makeBroadcastRecord(airplane, callerApp,
+ List.of(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN))));
+ waitForIdle();
+
+ // Regardless of success/failure of above, we should always be able to
+ // recover and begin sending future broadcasts
+ final Intent timezone = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
+ enqueueBroadcast(makeBroadcastRecord(timezone, callerApp,
+ List.of(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN))));
+ waitForIdle();
+
+ final ProcessRecord receiverApp = mAms.getProcessRecordLocked(PACKAGE_GREEN,
+ getUidForPackage(PACKAGE_GREEN));
+ verifyScheduleReceiver(receiverApp, timezone);
+ }
+
/**
* Verify that we skip broadcasts to an app being backed up.
*/
@@ -1277,8 +1366,8 @@
final BroadcastRecord r = new BroadcastRecord(mQueue, intent, callerApp,
callerApp.info.packageName, null, callerApp.getPid(), callerApp.info.uid, false,
null, null, null, null, AppOpsManager.OP_NONE, BroadcastOptions.makeBasic(),
- List.of(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN)), null, Activity.RESULT_OK,
- null, null, false, false, false, UserHandle.USER_SYSTEM, true,
+ List.of(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN)), null, null,
+ Activity.RESULT_OK, null, null, false, false, false, UserHandle.USER_SYSTEM, true,
backgroundActivityStartsToken, false, null);
enqueueBroadcast(r);
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastRecordTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastRecordTest.java
index 161dfa0..11573c5 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastRecordTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastRecordTest.java
@@ -525,6 +525,7 @@
0 /* appOp */,
null /* options */,
new ArrayList<>(receivers), // Make a copy to not affect the original list.
+ null /* resultToApp */,
null /* resultTo */,
0 /* resultCode */,
null /* resultData */,