Merge "Retry manifest bcast delivery if the receiver dies as part of unfreezing." into udc-dev am: 0bd2ce4eb7

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/23500523

Change-Id: I66fee62f6e01f610f8039e582ebe7545d16319a3
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Sudheer Shanka
2023-06-13 20:04:03 +00:00
committed by Automerger Merge Worker
2 changed files with 74 additions and 8 deletions

View File

@@ -458,7 +458,17 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
updateWarmProcess(queue); updateWarmProcess(queue);
final boolean processWarm = queue.isProcessWarm(); final boolean processWarm = queue.isProcessWarm();
if (!processWarm) { if (processWarm) {
mService.mOomAdjuster.unfreezeTemporarily(queue.app,
CachedAppOptimizer.UNFREEZE_REASON_START_RECEIVER);
// The process could be killed as part of unfreezing. So, check again if it
// is still warm.
if (!queue.isProcessWarm()) {
queue = nextQueue;
enqueueUpdateRunningList();
continue;
}
} else {
// We only offer to run one cold-start at a time to preserve // We only offer to run one cold-start at a time to preserve
// system resources; below we either claim that single slot or // system resources; below we either claim that single slot or
// skip to look for another warm process // skip to look for another warm process
@@ -530,6 +540,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
mRunningColdStart.reEnqueueActiveBroadcast(); mRunningColdStart.reEnqueueActiveBroadcast();
demoteFromRunningLocked(mRunningColdStart); demoteFromRunningLocked(mRunningColdStart);
clearRunningColdStart(); clearRunningColdStart();
enqueueUpdateRunningList();
} }
private void checkPendingColdStartValidity() { private void checkPendingColdStartValidity() {
@@ -564,6 +575,9 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
@Override @Override
public boolean onApplicationAttachedLocked(@NonNull ProcessRecord app) public boolean onApplicationAttachedLocked(@NonNull ProcessRecord app)
throws BroadcastDeliveryFailedException { throws BroadcastDeliveryFailedException {
if (DEBUG_BROADCAST) {
logv("Process " + app + " is attached");
}
// Process records can be recycled, so always start by looking up the // Process records can be recycled, so always start by looking up the
// relevant per-process queue // relevant per-process queue
final BroadcastProcessQueue queue = getProcessQueue(app); final BroadcastProcessQueue queue = getProcessQueue(app);
@@ -613,18 +627,21 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
@Override @Override
public void onApplicationCleanupLocked(@NonNull ProcessRecord app) { public void onApplicationCleanupLocked(@NonNull ProcessRecord app) {
// Process records can be recycled, so always start by looking up the if (DEBUG_BROADCAST) {
// relevant per-process queue logv("Process " + app + " is cleaned up");
final BroadcastProcessQueue queue = getProcessQueue(app);
if (queue != null) {
setQueueProcess(queue, null);
} }
if ((mRunningColdStart != null) && (mRunningColdStart == queue)) { // This cleanup callback could be for an old process and not for the one we are waiting
// on, so explicitly check if this for the same ProcessRecord that a queue has.
final BroadcastProcessQueue queue = getProcessQueue(app);
if ((mRunningColdStart != null) && (mRunningColdStart == queue)
&& mRunningColdStart.app == app) {
clearRunningColdStart(); clearRunningColdStart();
} }
if (queue != null) { if (queue != null && queue.app == app) {
setQueueProcess(queue, null);
// If queue was running a broadcast, fail it // If queue was running a broadcast, fail it
if (queue.isActive()) { if (queue.isActive()) {
finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE, finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE,
@@ -1073,6 +1090,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
// If we were trying to deliver a manifest broadcast, throw the error as we need // If we were trying to deliver a manifest broadcast, throw the error as we need
// to try redelivering the broadcast to this receiver. // to try redelivering the broadcast to this receiver.
if (receiver instanceof ResolveInfo) { if (receiver instanceof ResolveInfo) {
mLocalHandler.removeMessages(MSG_DELIVERY_TIMEOUT_SOFT, queue);
throw new BroadcastDeliveryFailedException(e); throw new BroadcastDeliveryFailedException(e);
} }
finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE, finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE,

View File

@@ -261,6 +261,7 @@ public class BroadcastQueueTest {
// Create a different process that will be linked to the // Create a different process that will be linked to the
// returned process via a predecessor/successor relationship // returned process via a predecessor/successor relationship
mActiveProcesses.remove(res); mActiveProcesses.remove(res);
res.setKilled(true);
deliverRes = makeActiveProcessRecord(ai, processName, deliverRes = makeActiveProcessRecord(ai, processName,
ProcessBehavior.NORMAL, UnaryOperator.identity()); ProcessBehavior.NORMAL, UnaryOperator.identity());
deliverRes.mPredecessor = res; deliverRes.mPredecessor = res;
@@ -1316,6 +1317,53 @@ public class BroadcastQueueTest {
verifyScheduleReceiver(times(1), receiverOrangeApp, timezone); verifyScheduleReceiver(times(1), receiverOrangeApp, timezone);
} }
/**
* Verify that a broadcast sent to a frozen app, which gets killed as part of unfreezing
* process due to pending sync binder transactions, is delivered as expected.
*/
@Test
public void testDeliveryToFrozenApp_killedWhileUnfreeze() throws Exception {
final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED);
final ProcessRecord receiverBlueApp = makeActiveProcessRecord(PACKAGE_BLUE);
// Mark the app as killed while unfreezing it, which can happen either when we directly
// try to unfreeze it or when it is done as part of OomAdjust computation.
doAnswer(invocation -> {
final ProcessRecord app = invocation.getArgument(0);
if (app == receiverBlueApp) {
app.setKilled(true);
mActiveProcesses.remove(app);
}
return null;
}).when(mAms.mOomAdjuster).unfreezeTemporarily(eq(receiverBlueApp), anyInt());
doAnswer(invocation -> {
final ProcessRecord app = invocation.getArgument(0);
if (app == receiverBlueApp) {
app.setKilled(true);
mActiveProcesses.remove(app);
}
return null;
}).when(mAms).enqueueOomAdjTargetLocked(eq(receiverBlueApp));
final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
enqueueBroadcast(makeBroadcastRecord(airplane, callerApp, List.of(
makeManifestReceiver(PACKAGE_BLUE, CLASS_BLUE))));
waitForIdle();
final ProcessRecord restartedReceiverBlueApp = mAms.getProcessRecordLocked(PACKAGE_BLUE,
getUidForPackage(PACKAGE_BLUE));
assertNotEquals(receiverBlueApp, restartedReceiverBlueApp);
// Legacy queue will always try delivering the broadcast even if the process
// has been killed.
if (mImpl == Impl.MODERN) {
verifyScheduleReceiver(never(), receiverBlueApp, airplane);
} else {
verifyScheduleReceiver(times(1), receiverBlueApp, airplane);
}
// Verify that the new process receives the broadcast.
verifyScheduleReceiver(times(1), restartedReceiverBlueApp, airplane);
}
@Test @Test
public void testCold_Success() throws Exception { public void testCold_Success() throws Exception {
doCold(ProcessStartBehavior.SUCCESS); doCold(ProcessStartBehavior.SUCCESS);