From ec665861fed4d519fc5a8c3bf0756bb472e0d47a Mon Sep 17 00:00:00 2001 From: Sudheer Shanka Date: Tue, 13 Jun 2023 15:20:55 -0700 Subject: [PATCH] Ensure resultTo callback is always invoked. Even if the broadcast is not enqueued for any reason, we should ensure that resultTo callback is invoked so that callers don't end up waiting forever for the callback. Bug: 284788269 Bug: 281722957 Test: manual Change-Id: I89f14aec8b194da3ec35b0c9a6d465445ae9badb --- .../server/am/ActivityManagerService.java | 39 +++++++++++++++++++ .../am/ActivityManagerShellCommand.java | 4 +- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 0916960fae13a..a7db663191af0 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -14449,6 +14449,8 @@ public class ActivityManagerService extends IActivityManager.Stub && !Intent.ACTION_SHUTDOWN.equals(intent.getAction())) { Slog.w(TAG, "Skipping broadcast of " + intent + ": user " + userId + " and its parent (if any) are stopped"); + scheduleCanceledResultTo(resultToApp, resultTo, intent, userId, + brOptions, callingUid, callerPackage); return ActivityManager.BROADCAST_FAILED_USER_STOPPED; } } @@ -14520,6 +14522,8 @@ public class ActivityManagerService extends IActivityManager.Stub isProtectedBroadcast = AppGlobals.getPackageManager().isProtectedBroadcast(action); } catch (RemoteException e) { Slog.w(TAG, "Remote exception", e); + scheduleCanceledResultTo(resultToApp, resultTo, intent, + userId, brOptions, callingUid, callerPackage); return ActivityManager.BROADCAST_SUCCESS; } @@ -14753,6 +14757,8 @@ public class ActivityManagerService extends IActivityManager.Stub if (aInfo == null) { Slog.w(TAG, "Dropping ACTION_PACKAGE_REPLACED for non-existent pkg:" + " ssp=" + ssp + " data=" + data); + scheduleCanceledResultTo(resultToApp, resultTo, intent, + userId, brOptions, callingUid, callerPackage); return ActivityManager.BROADCAST_SUCCESS; } updateAssociationForApp(aInfo); @@ -14838,6 +14844,8 @@ public class ActivityManagerService extends IActivityManager.Stub // Apps should now be using ShortcutManager.pinRequestShortcut(). Log.w(TAG, "Broadcast " + action + " no longer supported. It will not be delivered."); + scheduleCanceledResultTo(resultToApp, resultTo, intent, + userId, brOptions, callingUid, callerPackage); return ActivityManager.BROADCAST_SUCCESS; case Intent.ACTION_PRE_BOOT_COMPLETED: timeoutExempt = true; @@ -14845,6 +14853,8 @@ public class ActivityManagerService extends IActivityManager.Stub case Intent.ACTION_CLOSE_SYSTEM_DIALOGS: if (!mAtmInternal.checkCanCloseSystemDialogs(callingPid, callingUid, callerPackage)) { + scheduleCanceledResultTo(resultToApp, resultTo, intent, + userId, brOptions, callingUid, callerPackage); // Returning success seems to be the pattern here return ActivityManager.BROADCAST_SUCCESS; } @@ -14879,6 +14889,8 @@ public class ActivityManagerService extends IActivityManager.Stub if (requiredPermissions != null && requiredPermissions.length > 0) { Slog.w(TAG, "Can't broadcast sticky intent " + intent + " and enforce permissions " + Arrays.toString(requiredPermissions)); + scheduleCanceledResultTo(resultToApp, resultTo, intent, + userId, brOptions, callingUid, callerPackage); return ActivityManager.BROADCAST_STICKY_CANT_HAVE_PERMISSION; } if (intent.getComponent() != null) { @@ -15129,6 +15141,33 @@ public class ActivityManagerService extends IActivityManager.Stub return ActivityManager.BROADCAST_SUCCESS; } + @GuardedBy("this") + private void scheduleCanceledResultTo(ProcessRecord resultToApp, IIntentReceiver resultTo, + Intent intent, int userId, BroadcastOptions options, int callingUid, + String callingPackage) { + if (resultTo == null) { + return; + } + final ProcessRecord app = resultToApp; + final IApplicationThread thread = (app != null) ? app.getOnewayThread() : null; + if (thread != null) { + try { + final boolean shareIdentity = (options != null && options.isShareIdentityEnabled()); + thread.scheduleRegisteredReceiver( + resultTo, intent, Activity.RESULT_CANCELED, null, null, + false, false, true, userId, app.mState.getReportedProcState(), + shareIdentity ? callingUid : Process.INVALID_UID, + shareIdentity ? callingPackage : null); + } catch (RemoteException e) { + final String msg = "Failed to schedule result of " + intent + " via " + + app + ": " + e; + app.killLocked("Can't schedule resultTo", ApplicationExitInfo.REASON_OTHER, + ApplicationExitInfo.SUBREASON_UNDELIVERED_BROADCAST, true); + Slog.d(TAG, msg); + } + } + } + @GuardedBy("this") private int getRealProcessStateLocked(ProcessRecord app, int pid) { if (app == null) { diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index ba8a1b9d4690a..569f55f7890fa 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -928,8 +928,8 @@ final class ActivityManagerShellCommand extends ShellCommand { final int result = mInterface.broadcastIntentWithFeature(null, null, intent, null, receiver, 0, null, null, requiredPermissions, null, null, android.app.AppOpsManager.OP_NONE, bundle, true, false, mUserId); - Slogf.i(TAG, "Broadcasted %s: " + result, intent); - if (!mAsync) { + Slogf.i(TAG, "Enqueued broadcast %s: " + result, intent); + if (result == ActivityManager.BROADCAST_SUCCESS && !mAsync) { receiver.waitForFinish(); } return 0;