diff options
4 files changed, 55 insertions, 21 deletions
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 48957dcd7970..8acdc8c1255f 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -11946,6 +11946,7 @@ public final class Settings { * bcast_deferral (long) * bcast_deferral_decay_factor (float) * bcast_deferral_floor (long) + * bcast_allow_bg_activity_start_timeout (long) * </pre> * * @hide diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index bbef6c51f01c..f2902b172502 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -15039,7 +15039,7 @@ public class ActivityManagerService extends IActivityManager.Stub oldQueue.performReceiveLocked(oldRecord.callerApp, oldRecord.resultTo, oldRecord.intent, Activity.RESULT_CANCELED, null, null, - false, false, oldRecord.userId, oldRecord); + false, false, oldRecord.userId); } catch (RemoteException e) { Slog.w(TAG, "Failure [" + queue.mQueueName + "] sending broadcast result of " diff --git a/services/core/java/com/android/server/am/BroadcastConstants.java b/services/core/java/com/android/server/am/BroadcastConstants.java index 820caf12ac84..be17b1bc600c 100644 --- a/services/core/java/com/android/server/am/BroadcastConstants.java +++ b/services/core/java/com/android/server/am/BroadcastConstants.java @@ -38,6 +38,8 @@ public class BroadcastConstants { static final String KEY_DEFERRAL = "bcast_deferral"; static final String KEY_DEFERRAL_DECAY_FACTOR = "bcast_deferral_decay_factor"; static final String KEY_DEFERRAL_FLOOR = "bcast_deferral_floor"; + static final String KEY_ALLOW_BG_ACTIVITY_START_TIMEOUT = + "bcast_allow_bg_activity_start_timeout"; // All time intervals are in milliseconds private static final long DEFAULT_TIMEOUT = 10_000; @@ -45,6 +47,7 @@ public class BroadcastConstants { private static final long DEFAULT_DEFERRAL = 5_000; private static final float DEFAULT_DEFERRAL_DECAY_FACTOR = 0.75f; private static final long DEFAULT_DEFERRAL_FLOOR = 0; + private static final long DEFAULT_ALLOW_BG_ACTIVITY_START_TIMEOUT = 10_000; // All time constants are in milliseconds @@ -59,6 +62,8 @@ public class BroadcastConstants { public float DEFERRAL_DECAY_FACTOR = DEFAULT_DEFERRAL_DECAY_FACTOR; // Minimum that the deferral time can decay to until the backlog fully clears public long DEFERRAL_FLOOR = DEFAULT_DEFERRAL_FLOOR; + // For how long after a whitelisted receiver's start its process can start a background activity + public long ALLOW_BG_ACTIVITY_START_TIMEOUT = DEFAULT_ALLOW_BG_ACTIVITY_START_TIMEOUT; // Settings override tracking for this instance private String mSettingsKey; @@ -113,6 +118,8 @@ public class BroadcastConstants { DEFERRAL_DECAY_FACTOR = mParser.getFloat(KEY_DEFERRAL_DECAY_FACTOR, DEFERRAL_DECAY_FACTOR); DEFERRAL_FLOOR = mParser.getLong(KEY_DEFERRAL_FLOOR, DEFERRAL_FLOOR); + ALLOW_BG_ACTIVITY_START_TIMEOUT = mParser.getLong(KEY_ALLOW_BG_ACTIVITY_START_TIMEOUT, + ALLOW_BG_ACTIVITY_START_TIMEOUT); } } @@ -145,6 +152,9 @@ public class BroadcastConstants { pw.print(" "); pw.print(KEY_DEFERRAL_FLOOR); pw.print(" = "); TimeUtils.formatDuration(DEFERRAL_FLOOR, pw); + + pw.print(" "); pw.print(KEY_ALLOW_BG_ACTIVITY_START_TIMEOUT); pw.print(" = "); + TimeUtils.formatDuration(ALLOW_BG_ACTIVITY_START_TIMEOUT, pw); pw.println(); } } diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index d9ea1da79f56..efb1c445925f 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -74,9 +74,6 @@ public final class BroadcastQueue { static final int MAX_BROADCAST_SUMMARY_HISTORY = ActivityManager.isLowRamDeviceStatic() ? 25 : 300; - // For how long after a whitelisted receiver's start its process can start a background activity - private static final int RECEIVER_BG_ACTIVITY_START_TIMEOUT_MS = 10_000; - final ActivityManagerService mService; /** @@ -310,9 +307,6 @@ public final class BroadcastQueue { r.curApp = app; app.curReceivers.add(r); app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER); - if (r.allowBackgroundActivityStarts) { - app.addAllowBackgroundActivityStartsToken(r); - } mService.mProcessList.updateLruProcessLocked(app, false, null); if (!skipOomAdj) { mService.updateOomAdjLocked(); @@ -454,8 +448,25 @@ public final class BroadcastQueue { Slog.w(TAG, "finishReceiver [" + mQueueName + "] called but state is IDLE"); } if (r.allowBackgroundActivityStarts && r.curApp != null) { - r.curApp.removeAllowBackgroundActivityStartsToken(r); - } + if (elapsed > mConstants.ALLOW_BG_ACTIVITY_START_TIMEOUT) { + // if the receiver has run for more than allowed bg activity start timeout, + // just remove the token for this process now and we're done + r.curApp.removeAllowBackgroundActivityStartsToken(r); + } else { + // the receiver had run for less than allowed bg activity start timeout, + // so allow the process to still start activities from bg for some more time + String msgToken = (r.curApp.toShortString() + r.toString()).intern(); + // first, if there exists a past scheduled request to remove this token, drop + // that request - we don't want the token to be swept from under our feet... + mHandler.removeCallbacksAndMessages(msgToken); + // ...then schedule the removal of the token after the extended timeout + mHandler.postAtTime(() -> { + if (r.curApp != null) { + r.curApp.removeAllowBackgroundActivityStartsToken(r); + } + }, msgToken, (r.receiverTime + mConstants.ALLOW_BG_ACTIVITY_START_TIMEOUT)); + } + } // If we're abandoning this broadcast before any receivers were actually spun up, // nextReceiver is zero; in which case time-to-process bookkeeping doesn't apply. if (r.nextReceiver > 0) { @@ -554,7 +565,7 @@ public final class BroadcastQueue { void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver, Intent intent, int resultCode, String data, Bundle extras, - boolean ordered, boolean sticky, int sendingUser, BroadcastRecord br) + boolean ordered, boolean sticky, int sendingUser) throws RemoteException { // Send the intent to the receiver asynchronously using one-way binder calls. if (app != null) { @@ -562,15 +573,6 @@ public final class BroadcastQueue { // If we have an app thread, do the call through that so it is // correctly ordered with other one-way calls. try { - if (br.allowBackgroundActivityStarts) { - app.addAllowBackgroundActivityStartsToken(br); - // schedule removal of the whitelisting token after the timeout - mHandler.postDelayed(() -> { - if (app != null) { - app.removeAllowBackgroundActivityStartsToken(br); - } - }, RECEIVER_BG_ACTIVITY_START_TIMEOUT_MS); - } app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode, data, extras, ordered, sticky, sendingUser, app.getReportedProcState()); // TODO: Uncomment this when (b/28322359) is fixed and we aren't getting @@ -794,9 +796,13 @@ public final class BroadcastQueue { skipReceiverLocked(r); } } else { + if (r.receiverTime == 0) { + r.receiverTime = SystemClock.uptimeMillis(); + } + maybeAddAllowBackgroundActivityStartsToken(filter.receiverList.app, r); performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver, new Intent(r.intent), r.resultCode, r.resultData, - r.resultExtras, r.ordered, r.initialSticky, r.userId, r); + r.resultExtras, r.ordered, r.initialSticky, r.userId); } if (ordered) { r.state = BroadcastRecord.CALL_DONE_RECEIVE; @@ -1100,7 +1106,7 @@ public final class BroadcastQueue { } performReceiveLocked(r.callerApp, r.resultTo, new Intent(r.intent), r.resultCode, - r.resultData, r.resultExtras, false, false, r.userId, r); + r.resultData, r.resultExtras, false, false, r.userId); // Set this to null so that the reference // (local and remote) isn't kept in the mBroadcastHistory. r.resultTo = null; @@ -1255,6 +1261,9 @@ public final class BroadcastQueue { r.state = BroadcastRecord.IDLE; scheduleBroadcastsLocked(); } else { + if (filter.receiverList != null) { + maybeAddAllowBackgroundActivityStartsToken(filter.receiverList.app, r); + } if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) { scheduleTempWhitelistLocked(filter.owningUid, brOptions.getTemporaryAppWhitelistDuration(), r); @@ -1561,6 +1570,7 @@ public final class BroadcastQueue { try { app.addPackage(info.activityInfo.packageName, info.activityInfo.applicationInfo.versionCode, mService.mProcessStats); + maybeAddAllowBackgroundActivityStartsToken(app, r); processCurBroadcastLocked(r, app, skipOomAdj); return; } catch (RemoteException e) { @@ -1611,10 +1621,23 @@ public final class BroadcastQueue { return; } + maybeAddAllowBackgroundActivityStartsToken(r.curApp, r); mPendingBroadcast = r; mPendingBroadcastRecvIndex = recIdx; } + private void maybeAddAllowBackgroundActivityStartsToken(ProcessRecord proc, BroadcastRecord r) { + if (r == null || proc == null || !r.allowBackgroundActivityStarts) { + return; + } + String msgToken = (proc.toShortString() + r.toString()).intern(); + // first, if there exists a past scheduled request to remove this token, drop + // that request - we don't want the token to be swept from under our feet... + mHandler.removeCallbacksAndMessages(msgToken); + // ...then add the token + proc.addAllowBackgroundActivityStartsToken(r); + } + final void setBroadcastTimeoutLocked(long timeoutTime) { if (! mPendingBroadcastTimeoutMessage) { Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG, this); |