Loading services/core/java/com/android/server/am/BroadcastProcessQueue.java +19 −0 Original line number Diff line number Diff line Loading @@ -151,6 +151,11 @@ class BroadcastProcessQueue { */ private int mActiveIndex; /** * True if the broadcast actively being dispatched to this process was re-enqueued previously. */ private boolean mActiveReEnqueued; /** * Count of {@link #mActive} broadcasts that have been dispatched since this * queue was last idle. Loading Loading @@ -312,6 +317,7 @@ class BroadcastProcessQueue { final SomeArgs broadcastArgs = SomeArgs.obtain(); broadcastArgs.arg1 = record; broadcastArgs.argi1 = recordIndex; broadcastArgs.argi2 = 1; getQueueForBroadcast(record).addFirst(broadcastArgs); onBroadcastEnqueued(record, recordIndex); } Loading Loading @@ -609,6 +615,7 @@ class BroadcastProcessQueue { final SomeArgs next = removeNextBroadcast(); mActive = (BroadcastRecord) next.arg1; mActiveIndex = next.argi1; mActiveReEnqueued = (next.argi2 == 1); mActiveCountSinceIdle++; mActiveAssumedDeliveryCountSinceIdle += (mActive.isAssumedDelivered(mActiveIndex) ? 1 : 0); Loading @@ -624,12 +631,21 @@ class BroadcastProcessQueue { public void makeActiveIdle() { mActive = null; mActiveIndex = 0; mActiveReEnqueued = false; mActiveCountSinceIdle = 0; mActiveAssumedDeliveryCountSinceIdle = 0; mActiveViaColdStart = false; invalidateRunnableAt(); } public boolean wasActiveBroadcastReEnqueued() { // If the flag is not enabled, treat as if the broadcast was never re-enqueued. if (!Flags.avoidRepeatedBcastReEnqueues()) { return false; } return mActiveReEnqueued; } /** * Update summary statistics when the given record has been enqueued. */ Loading Loading @@ -1476,6 +1492,9 @@ class BroadcastProcessQueue { if (runningOomAdjusted) { pw.print("runningOomAdjusted:"); pw.println(runningOomAdjusted); } if (mActiveReEnqueued) { pw.print("activeReEnqueued:"); pw.println(mActiveReEnqueued); } } @NeverCompile Loading services/core/java/com/android/server/am/BroadcastQueueModernImpl.java +29 −17 Original line number Diff line number Diff line Loading @@ -542,8 +542,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue { updateOomAdj |= queue.runningOomAdjusted; try { completed = scheduleReceiverWarmLocked(queue); } catch (BroadcastDeliveryFailedException e) { reEnqueueActiveBroadcast(queue); } catch (BroadcastRetryException e) { finishOrReEnqueueActiveBroadcast(queue); completed = true; } } else { Loading Loading @@ -586,7 +586,12 @@ class BroadcastQueueModernImpl extends BroadcastQueue { private void clearInvalidPendingColdStart() { logw("Clearing invalid pending cold start: " + mRunningColdStart); if (mRunningColdStart.wasActiveBroadcastReEnqueued()) { finishReceiverActiveLocked(mRunningColdStart, BroadcastRecord.DELIVERY_FAILURE, "invalid start with re-enqueued broadcast"); } else { mRunningColdStart.reEnqueueActiveBroadcast(); } demoteFromRunningLocked(mRunningColdStart); clearRunningColdStart(); enqueueUpdateRunningList(); Loading @@ -613,19 +618,26 @@ class BroadcastQueueModernImpl extends BroadcastQueue { } } private void reEnqueueActiveBroadcast(@NonNull BroadcastProcessQueue queue) { private void finishOrReEnqueueActiveBroadcast(@NonNull BroadcastProcessQueue queue) { checkState(queue.isActive(), "isActive"); if (queue.wasActiveBroadcastReEnqueued()) { // If the broadcast was already re-enqueued previously, finish it to avoid repeated // delivery attempts finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE, "re-enqueued broadcast delivery failed"); } else { final BroadcastRecord record = queue.getActive(); final int index = queue.getActiveIndex(); setDeliveryState(queue, queue.app, record, index, record.receivers.get(index), BroadcastRecord.DELIVERY_PENDING, "reEnqueueActiveBroadcast"); queue.reEnqueueActiveBroadcast(); } } @Override public boolean onApplicationAttachedLocked(@NonNull ProcessRecord app) throws BroadcastDeliveryFailedException { throws BroadcastRetryException { if (DEBUG_BROADCAST) { logv("Process " + app + " is attached"); } Loading Loading @@ -653,8 +665,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue { if (scheduleReceiverWarmLocked(queue)) { demoteFromRunningLocked(queue); } } catch (BroadcastDeliveryFailedException e) { reEnqueueActiveBroadcast(queue); } catch (BroadcastRetryException e) { finishOrReEnqueueActiveBroadcast(queue); demoteFromRunningLocked(queue); throw e; } Loading Loading @@ -983,7 +995,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue { @CheckResult @GuardedBy("mService") private boolean scheduleReceiverWarmLocked(@NonNull BroadcastProcessQueue queue) throws BroadcastDeliveryFailedException { throws BroadcastRetryException { checkState(queue.isActive(), "isActive"); final int cookie = traceBegin("scheduleReceiverWarmLocked"); Loading Loading @@ -1065,7 +1077,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue { */ @CheckResult private boolean dispatchReceivers(@NonNull BroadcastProcessQueue queue, @NonNull BroadcastRecord r, int index) throws BroadcastDeliveryFailedException { @NonNull BroadcastRecord r, int index) throws BroadcastRetryException { final ProcessRecord app = queue.app; final Object receiver = r.receivers.get(index); Loading Loading @@ -1157,7 +1169,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue { // to try redelivering the broadcast to this receiver. if (receiver instanceof ResolveInfo) { cancelDeliveryTimeoutLocked(queue); throw new BroadcastDeliveryFailedException(e); throw new BroadcastRetryException(e); } finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE, "remote app"); Loading Loading @@ -1316,8 +1328,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue { demoteFromRunningLocked(queue); return true; } } catch (BroadcastDeliveryFailedException e) { reEnqueueActiveBroadcast(queue); } catch (BroadcastRetryException e) { finishOrReEnqueueActiveBroadcast(queue); demoteFromRunningLocked(queue); return true; } Loading services/core/java/com/android/server/am/BroadcastRetryException.java 0 → 100644 +30 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.am; /** * Exception to represent that broadcast delivery failed and we should try redelivering it. */ public class BroadcastRetryException extends BroadcastDeliveryFailedException { public BroadcastRetryException(String name) { super(name); } public BroadcastRetryException(Exception cause) { super(cause); } } services/core/java/com/android/server/am/flags.aconfig +11 −0 Original line number Diff line number Diff line Loading @@ -42,3 +42,14 @@ flag { description: "Optimize the service bindings by different policies like skipping oom adjuster" bug: "318717054" } flag { namespace: "backstage_power" name: "avoid_repeated_bcast_re_enqueues" description: "Avoid re-enqueueing a broadcast repeatedly" bug: "319225224" is_fixed_read_only: true metadata { purpose: PURPOSE_BUGFIX } } services/tests/mockingservicestests/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -73,6 +73,7 @@ android_test { "testng", "compatibility-device-util-axt", "flag-junit", "am_flags_lib", ], libs: [ Loading Loading
services/core/java/com/android/server/am/BroadcastProcessQueue.java +19 −0 Original line number Diff line number Diff line Loading @@ -151,6 +151,11 @@ class BroadcastProcessQueue { */ private int mActiveIndex; /** * True if the broadcast actively being dispatched to this process was re-enqueued previously. */ private boolean mActiveReEnqueued; /** * Count of {@link #mActive} broadcasts that have been dispatched since this * queue was last idle. Loading Loading @@ -312,6 +317,7 @@ class BroadcastProcessQueue { final SomeArgs broadcastArgs = SomeArgs.obtain(); broadcastArgs.arg1 = record; broadcastArgs.argi1 = recordIndex; broadcastArgs.argi2 = 1; getQueueForBroadcast(record).addFirst(broadcastArgs); onBroadcastEnqueued(record, recordIndex); } Loading Loading @@ -609,6 +615,7 @@ class BroadcastProcessQueue { final SomeArgs next = removeNextBroadcast(); mActive = (BroadcastRecord) next.arg1; mActiveIndex = next.argi1; mActiveReEnqueued = (next.argi2 == 1); mActiveCountSinceIdle++; mActiveAssumedDeliveryCountSinceIdle += (mActive.isAssumedDelivered(mActiveIndex) ? 1 : 0); Loading @@ -624,12 +631,21 @@ class BroadcastProcessQueue { public void makeActiveIdle() { mActive = null; mActiveIndex = 0; mActiveReEnqueued = false; mActiveCountSinceIdle = 0; mActiveAssumedDeliveryCountSinceIdle = 0; mActiveViaColdStart = false; invalidateRunnableAt(); } public boolean wasActiveBroadcastReEnqueued() { // If the flag is not enabled, treat as if the broadcast was never re-enqueued. if (!Flags.avoidRepeatedBcastReEnqueues()) { return false; } return mActiveReEnqueued; } /** * Update summary statistics when the given record has been enqueued. */ Loading Loading @@ -1476,6 +1492,9 @@ class BroadcastProcessQueue { if (runningOomAdjusted) { pw.print("runningOomAdjusted:"); pw.println(runningOomAdjusted); } if (mActiveReEnqueued) { pw.print("activeReEnqueued:"); pw.println(mActiveReEnqueued); } } @NeverCompile Loading
services/core/java/com/android/server/am/BroadcastQueueModernImpl.java +29 −17 Original line number Diff line number Diff line Loading @@ -542,8 +542,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue { updateOomAdj |= queue.runningOomAdjusted; try { completed = scheduleReceiverWarmLocked(queue); } catch (BroadcastDeliveryFailedException e) { reEnqueueActiveBroadcast(queue); } catch (BroadcastRetryException e) { finishOrReEnqueueActiveBroadcast(queue); completed = true; } } else { Loading Loading @@ -586,7 +586,12 @@ class BroadcastQueueModernImpl extends BroadcastQueue { private void clearInvalidPendingColdStart() { logw("Clearing invalid pending cold start: " + mRunningColdStart); if (mRunningColdStart.wasActiveBroadcastReEnqueued()) { finishReceiverActiveLocked(mRunningColdStart, BroadcastRecord.DELIVERY_FAILURE, "invalid start with re-enqueued broadcast"); } else { mRunningColdStart.reEnqueueActiveBroadcast(); } demoteFromRunningLocked(mRunningColdStart); clearRunningColdStart(); enqueueUpdateRunningList(); Loading @@ -613,19 +618,26 @@ class BroadcastQueueModernImpl extends BroadcastQueue { } } private void reEnqueueActiveBroadcast(@NonNull BroadcastProcessQueue queue) { private void finishOrReEnqueueActiveBroadcast(@NonNull BroadcastProcessQueue queue) { checkState(queue.isActive(), "isActive"); if (queue.wasActiveBroadcastReEnqueued()) { // If the broadcast was already re-enqueued previously, finish it to avoid repeated // delivery attempts finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE, "re-enqueued broadcast delivery failed"); } else { final BroadcastRecord record = queue.getActive(); final int index = queue.getActiveIndex(); setDeliveryState(queue, queue.app, record, index, record.receivers.get(index), BroadcastRecord.DELIVERY_PENDING, "reEnqueueActiveBroadcast"); queue.reEnqueueActiveBroadcast(); } } @Override public boolean onApplicationAttachedLocked(@NonNull ProcessRecord app) throws BroadcastDeliveryFailedException { throws BroadcastRetryException { if (DEBUG_BROADCAST) { logv("Process " + app + " is attached"); } Loading Loading @@ -653,8 +665,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue { if (scheduleReceiverWarmLocked(queue)) { demoteFromRunningLocked(queue); } } catch (BroadcastDeliveryFailedException e) { reEnqueueActiveBroadcast(queue); } catch (BroadcastRetryException e) { finishOrReEnqueueActiveBroadcast(queue); demoteFromRunningLocked(queue); throw e; } Loading Loading @@ -983,7 +995,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue { @CheckResult @GuardedBy("mService") private boolean scheduleReceiverWarmLocked(@NonNull BroadcastProcessQueue queue) throws BroadcastDeliveryFailedException { throws BroadcastRetryException { checkState(queue.isActive(), "isActive"); final int cookie = traceBegin("scheduleReceiverWarmLocked"); Loading Loading @@ -1065,7 +1077,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue { */ @CheckResult private boolean dispatchReceivers(@NonNull BroadcastProcessQueue queue, @NonNull BroadcastRecord r, int index) throws BroadcastDeliveryFailedException { @NonNull BroadcastRecord r, int index) throws BroadcastRetryException { final ProcessRecord app = queue.app; final Object receiver = r.receivers.get(index); Loading Loading @@ -1157,7 +1169,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue { // to try redelivering the broadcast to this receiver. if (receiver instanceof ResolveInfo) { cancelDeliveryTimeoutLocked(queue); throw new BroadcastDeliveryFailedException(e); throw new BroadcastRetryException(e); } finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE, "remote app"); Loading Loading @@ -1316,8 +1328,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue { demoteFromRunningLocked(queue); return true; } } catch (BroadcastDeliveryFailedException e) { reEnqueueActiveBroadcast(queue); } catch (BroadcastRetryException e) { finishOrReEnqueueActiveBroadcast(queue); demoteFromRunningLocked(queue); return true; } Loading
services/core/java/com/android/server/am/BroadcastRetryException.java 0 → 100644 +30 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.am; /** * Exception to represent that broadcast delivery failed and we should try redelivering it. */ public class BroadcastRetryException extends BroadcastDeliveryFailedException { public BroadcastRetryException(String name) { super(name); } public BroadcastRetryException(Exception cause) { super(cause); } }
services/core/java/com/android/server/am/flags.aconfig +11 −0 Original line number Diff line number Diff line Loading @@ -42,3 +42,14 @@ flag { description: "Optimize the service bindings by different policies like skipping oom adjuster" bug: "318717054" } flag { namespace: "backstage_power" name: "avoid_repeated_bcast_re_enqueues" description: "Avoid re-enqueueing a broadcast repeatedly" bug: "319225224" is_fixed_read_only: true metadata { purpose: PURPOSE_BUGFIX } }
services/tests/mockingservicestests/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -73,6 +73,7 @@ android_test { "testng", "compatibility-device-util-axt", "flag-junit", "am_flags_lib", ], libs: [ Loading