diff options
14 files changed, 270 insertions, 115 deletions
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index 81aa6da3d6a2..b8030702c244 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -420,10 +420,11 @@ public abstract class ActivityManagerInternal { 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 6404a1f59135..7475ef8ec577 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -556,7 +556,8 @@ interface IActivityManager { 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 bc78df59ff12..db47a4cdefc0 100644 --- a/core/java/android/app/PendingIntent.java +++ b/core/java/android/app/PendingIntent.java @@ -1009,7 +1009,9 @@ public final class PendingIntent implements Parcelable { 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 b1252fd0b21f..8853b705d67e 100644 --- a/core/java/android/content/IntentSender.java +++ b/core/java/android/content/IntentSender.java @@ -18,6 +18,8 @@ package android.content; 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 @@ public class IntentSender implements Parcelable { 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 1a4da7db54e9..7a09109e377b 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub } @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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub @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 @@ public class ActivityManagerService extends IActivityManager.Stub @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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub // 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 @@ public class ActivityManagerService extends IActivityManager.Stub : 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 @@ public class ActivityManagerService extends IActivityManager.Stub @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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 class ActivityManagerService extends IActivityManager.Stub 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 97635b53a6d4..0d6ac1d57387 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 @@ class BroadcastProcessQueue { 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 @@ class BroadcastProcessQueue { final SomeArgs next = mPending.removeFirst(); mActive = (BroadcastRecord) next.arg1; mActiveIndex = next.argi1; + mActiveBlockedUntilTerminalCount = next.argi2; mActiveCountSinceIdle++; mActiveViaColdStart = false; next.recycle(); @@ -316,6 +325,7 @@ class BroadcastProcessQueue { public void makeActiveIdle() { mActive = null; mActiveIndex = 0; + mActiveBlockedUntilTerminalCount = -1; mActiveCountSinceIdle = 0; mActiveViaColdStart = false; invalidateRunnableAt(); @@ -664,27 +674,14 @@ class BroadcastProcessQueue { } 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 @@ class BroadcastProcessQueue { @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 @@ class BroadcastProcessQueue { 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 d7a075b3b966..f34565b2ee9c 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 @@ public class BroadcastQueueImpl extends BroadcastQueue { 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 @@ public class BroadcastQueueImpl extends BroadcastQueue { 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 89a0283a4264..1e1ebeba5c23 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 @@ class BroadcastQueueModernImpl extends BroadcastQueue { // 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 @@ class BroadcastQueueModernImpl extends BroadcastQueue { @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 @@ class BroadcastQueueModernImpl extends BroadcastQueue { @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 @@ class BroadcastQueueModernImpl extends BroadcastQueue { } } else { // Otherwise we don't need to block at all - blockedUntilTerminalCount = 0; + blockedUntilTerminalCount = -1; } queue.enqueueOrReplaceBroadcast(r, i, blockedUntilTerminalCount); @@ -619,9 +627,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue { 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 @@ class BroadcastQueueModernImpl extends BroadcastQueue { * 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 @@ class BroadcastQueueModernImpl extends BroadcastQueue { } } + // 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 bcc76e949e5f..2d825955ed6c 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 class BroadcastRecord extends Binder { 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 @@ final class BroadcastRecord extends Binder { 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 @@ final class BroadcastRecord extends Binder { 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 @@ final class BroadcastRecord extends Binder { 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 @@ final class BroadcastRecord extends Binder { 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 class BroadcastRecord extends Binder { 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 bda60ff2172b..975619feaea0 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.annotation.Nullable; 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 final class PendingIntentRecord extends IIntentSender.Stub { 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 @@ public final class PendingIntentRecord extends IIntentSender.Stub { 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 @@ public final class PendingIntentRecord extends IIntentSender.Stub { } } + final IApplicationThread finishedReceiverThread = caller; boolean sendFinish = finishedReceiver != null; int userId = key.userId; if (userId == UserHandle.USER_CURRENT) { @@ -525,9 +545,9 @@ public final class PendingIntentRecord extends IIntentSender.Stub { // 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 9b7c3acb71d8..77fcef677dad 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 @@ public abstract class PreBootBroadcaster extends IIntentReceiver.Stub { 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 abstract class PreBootBroadcaster extends IIntentReceiver.Stub { 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 @@ public abstract class PreBootBroadcaster extends IIntentReceiver.Stub { 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 86915da75467..90b1f4ecdcb3 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 @@ public class BroadcastQueueModernImplTest { 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 076fce959a77..c12544897941 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.Map; 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 @@ public class BroadcastQueueTest { 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 @@ public class BroadcastQueueTest { 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 @@ public class BroadcastQueueTest { // 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 @@ public class BroadcastQueueTest { } } + 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 @@ public class BroadcastQueueTest { 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 @@ public class BroadcastQueueTest { 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 @@ public class BroadcastQueueTest { 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 @@ public class BroadcastQueueTest { 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 @@ public class BroadcastQueueTest { 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 161dfa0566fd..11573c57b382 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 @@ public class BroadcastRecordTest { 0 /* appOp */, null /* options */, new ArrayList<>(receivers), // Make a copy to not affect the original list. + null /* resultToApp */, null /* resultTo */, 0 /* resultCode */, null /* resultData */, |