Merge changes from topic "oct26"
* changes: Enable "modern" BroadcastQueue by default; take two. BroadcastQueue: make "oneway" calls non-blocking. BroadcastQueue: only OOM adjust for manifest.
This commit is contained in:
@@ -85,9 +85,16 @@ class BroadcastProcessQueue {
|
||||
@Nullable ProcessRecord app;
|
||||
|
||||
/**
|
||||
* Track name to use for {@link Trace} events.
|
||||
* Track name to use for {@link Trace} events, defined as part of upgrading
|
||||
* into a running slot.
|
||||
*/
|
||||
@Nullable String traceTrackName;
|
||||
@Nullable String runningTraceTrackName;
|
||||
|
||||
/**
|
||||
* Flag indicating if this process should be OOM adjusted, defined as part
|
||||
* of upgrading into a running slot.
|
||||
*/
|
||||
boolean runningOomAdjusted;
|
||||
|
||||
/**
|
||||
* Snapshotted value of {@link ProcessRecord#getCpuDelayTime()}, typically
|
||||
@@ -141,7 +148,8 @@ class BroadcastProcessQueue {
|
||||
private boolean mActiveViaColdStart;
|
||||
|
||||
/**
|
||||
* Count of {@link #mPending} broadcasts of these various flavors.
|
||||
* Count of {@link #mPending} and {@link #mPendingUrgent} broadcasts of
|
||||
* these various flavors.
|
||||
*/
|
||||
private int mCountForeground;
|
||||
private int mCountOrdered;
|
||||
@@ -150,6 +158,7 @@ class BroadcastProcessQueue {
|
||||
private int mCountInteractive;
|
||||
private int mCountResultTo;
|
||||
private int mCountInstrumented;
|
||||
private int mCountManifest;
|
||||
|
||||
private @UptimeMillisLong long mRunnableAt = Long.MAX_VALUE;
|
||||
private @Reason int mRunnableAtReason = REASON_EMPTY;
|
||||
@@ -206,7 +215,7 @@ class BroadcastProcessQueue {
|
||||
// with implicit responsiveness expectations.
|
||||
final ArrayDeque<SomeArgs> queue = record.isUrgent() ? mPendingUrgent : mPending;
|
||||
queue.addLast(newBroadcastArgs);
|
||||
onBroadcastEnqueued(record);
|
||||
onBroadcastEnqueued(record, recordIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -224,7 +233,8 @@ class BroadcastProcessQueue {
|
||||
while (it.hasNext()) {
|
||||
final SomeArgs args = it.next();
|
||||
final BroadcastRecord testRecord = (BroadcastRecord) args.arg1;
|
||||
final Object testReceiver = testRecord.receivers.get(args.argi1);
|
||||
final int testRecordIndex = args.argi1;
|
||||
final Object testReceiver = testRecord.receivers.get(testRecordIndex);
|
||||
if ((record.callingUid == testRecord.callingUid)
|
||||
&& (record.userId == testRecord.userId)
|
||||
&& record.intent.filterEquals(testRecord.intent)
|
||||
@@ -233,8 +243,8 @@ class BroadcastProcessQueue {
|
||||
args.arg1 = record;
|
||||
args.argi1 = recordIndex;
|
||||
args.argi2 = blockedUntilTerminalCount;
|
||||
onBroadcastDequeued(testRecord);
|
||||
onBroadcastEnqueued(record);
|
||||
onBroadcastDequeued(testRecord, testRecordIndex);
|
||||
onBroadcastEnqueued(record, recordIndex);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -284,13 +294,13 @@ class BroadcastProcessQueue {
|
||||
while (it.hasNext()) {
|
||||
final SomeArgs args = it.next();
|
||||
final BroadcastRecord record = (BroadcastRecord) args.arg1;
|
||||
final int index = args.argi1;
|
||||
if (predicate.test(record, index)) {
|
||||
consumer.accept(record, index);
|
||||
final int recordIndex = args.argi1;
|
||||
if (predicate.test(record, recordIndex)) {
|
||||
consumer.accept(record, recordIndex);
|
||||
if (andRemove) {
|
||||
args.recycle();
|
||||
it.remove();
|
||||
onBroadcastDequeued(record);
|
||||
onBroadcastDequeued(record, recordIndex);
|
||||
}
|
||||
didSomething = true;
|
||||
}
|
||||
@@ -339,7 +349,7 @@ class BroadcastProcessQueue {
|
||||
* Return if we know of an actively running "warm" process for this queue.
|
||||
*/
|
||||
public boolean isProcessWarm() {
|
||||
return (app != null) && (app.getThread() != null) && !app.isKilled();
|
||||
return (app != null) && (app.getOnewayThread() != null) && !app.isKilled();
|
||||
}
|
||||
|
||||
public int getPreferredSchedulingGroupLocked() {
|
||||
@@ -385,7 +395,7 @@ class BroadcastProcessQueue {
|
||||
mActiveCountSinceIdle++;
|
||||
mActiveViaColdStart = false;
|
||||
next.recycle();
|
||||
onBroadcastDequeued(mActive);
|
||||
onBroadcastDequeued(mActive, mActiveIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -403,7 +413,7 @@ class BroadcastProcessQueue {
|
||||
/**
|
||||
* Update summary statistics when the given record has been enqueued.
|
||||
*/
|
||||
private void onBroadcastEnqueued(@NonNull BroadcastRecord record) {
|
||||
private void onBroadcastEnqueued(@NonNull BroadcastRecord record, int recordIndex) {
|
||||
if (record.isForeground()) {
|
||||
mCountForeground++;
|
||||
}
|
||||
@@ -425,13 +435,16 @@ class BroadcastProcessQueue {
|
||||
if (record.callerInstrumented) {
|
||||
mCountInstrumented++;
|
||||
}
|
||||
if (record.receivers.get(recordIndex) instanceof ResolveInfo) {
|
||||
mCountManifest++;
|
||||
}
|
||||
invalidateRunnableAt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update summary statistics when the given record has been dequeued.
|
||||
*/
|
||||
private void onBroadcastDequeued(@NonNull BroadcastRecord record) {
|
||||
private void onBroadcastDequeued(@NonNull BroadcastRecord record, int recordIndex) {
|
||||
if (record.isForeground()) {
|
||||
mCountForeground--;
|
||||
}
|
||||
@@ -453,34 +466,37 @@ class BroadcastProcessQueue {
|
||||
if (record.callerInstrumented) {
|
||||
mCountInstrumented--;
|
||||
}
|
||||
if (record.receivers.get(recordIndex) instanceof ResolveInfo) {
|
||||
mCountManifest--;
|
||||
}
|
||||
invalidateRunnableAt();
|
||||
}
|
||||
|
||||
public void traceProcessStartingBegin() {
|
||||
Trace.asyncTraceForTrackBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
|
||||
traceTrackName, toShortString() + " starting", hashCode());
|
||||
runningTraceTrackName, toShortString() + " starting", hashCode());
|
||||
}
|
||||
|
||||
public void traceProcessRunningBegin() {
|
||||
Trace.asyncTraceForTrackBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
|
||||
traceTrackName, toShortString() + " running", hashCode());
|
||||
runningTraceTrackName, toShortString() + " running", hashCode());
|
||||
}
|
||||
|
||||
public void traceProcessEnd() {
|
||||
Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER,
|
||||
traceTrackName, hashCode());
|
||||
runningTraceTrackName, hashCode());
|
||||
}
|
||||
|
||||
public void traceActiveBegin() {
|
||||
final int cookie = mActive.receivers.get(mActiveIndex).hashCode();
|
||||
Trace.asyncTraceForTrackBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
|
||||
traceTrackName, mActive.toShortString() + " scheduled", cookie);
|
||||
runningTraceTrackName, mActive.toShortString() + " scheduled", cookie);
|
||||
}
|
||||
|
||||
public void traceActiveEnd() {
|
||||
final int cookie = mActive.receivers.get(mActiveIndex).hashCode();
|
||||
Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER,
|
||||
traceTrackName, cookie);
|
||||
runningTraceTrackName, cookie);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -539,6 +555,14 @@ class BroadcastProcessQueue {
|
||||
return (queue != null) ? (BroadcastRecord) queue.peekFirst().arg1 : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Quickly determine if this queue has broadcasts waiting to be delivered to
|
||||
* manifest receivers, which indicates we should request an OOM adjust.
|
||||
*/
|
||||
public boolean isPendingManifest() {
|
||||
return mCountManifest > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Quickly determine if this queue has broadcasts that are still waiting to
|
||||
* be delivered at some point in the future.
|
||||
|
||||
@@ -401,7 +401,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
|
||||
mRunnableHead = removeFromRunnableList(mRunnableHead, queue);
|
||||
|
||||
// Emit all trace events for this process into a consistent track
|
||||
queue.traceTrackName = TAG + ".mRunning[" + queueIndex + "]";
|
||||
queue.runningTraceTrackName = TAG + ".mRunning[" + queueIndex + "]";
|
||||
queue.runningOomAdjusted = queue.isPendingManifest();
|
||||
|
||||
// If we're already warm, schedule next pending broadcast now;
|
||||
// otherwise we'll wait for the cold start to circle back around
|
||||
@@ -415,9 +416,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
|
||||
scheduleReceiverColdLocked(queue);
|
||||
}
|
||||
|
||||
// We've moved at least one process into running state above, so we
|
||||
// need to kick off an OOM adjustment pass
|
||||
updateOomAdj = true;
|
||||
// Only kick off an OOM adjustment pass if needed
|
||||
updateOomAdj |= queue.runningOomAdjusted;
|
||||
|
||||
// Move to considering next runnable queue
|
||||
queue = nextQueue;
|
||||
@@ -736,7 +736,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
|
||||
if (DEBUG_BROADCAST) logv("Scheduling " + r + " to warm " + app);
|
||||
setDeliveryState(queue, app, r, index, receiver, BroadcastRecord.DELIVERY_SCHEDULED);
|
||||
|
||||
final IApplicationThread thread = app.getThread();
|
||||
final IApplicationThread thread = app.getOnewayThread();
|
||||
if (thread != null) {
|
||||
try {
|
||||
if (receiver instanceof BroadcastFilter) {
|
||||
@@ -777,7 +777,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
|
||||
private void scheduleResultTo(@NonNull BroadcastRecord r) {
|
||||
if ((r.resultToApp == null) || (r.resultTo == null)) return;
|
||||
final ProcessRecord app = r.resultToApp;
|
||||
final IApplicationThread thread = app.getThread();
|
||||
final IApplicationThread thread = app.getOnewayThread();
|
||||
if (thread != null) {
|
||||
mService.mOomAdjuster.mCachedAppOptimizer.unfreezeTemporarily(
|
||||
app, OOM_ADJ_REASON_FINISH_RECEIVER);
|
||||
@@ -1245,8 +1245,6 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
|
||||
if (queue.app != null) {
|
||||
queue.app.mReceivers.incrementCurReceivers();
|
||||
|
||||
queue.app.mState.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER);
|
||||
|
||||
// Don't bump its LRU position if it's in the background restricted.
|
||||
if (mService.mInternal.getRestrictionLevel(
|
||||
queue.uid) < ActivityManager.RESTRICTION_LEVEL_RESTRICTED_BUCKET) {
|
||||
@@ -1256,7 +1254,10 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
|
||||
mService.mOomAdjuster.mCachedAppOptimizer.unfreezeTemporarily(queue.app,
|
||||
OOM_ADJ_REASON_START_RECEIVER);
|
||||
|
||||
mService.enqueueOomAdjTargetLocked(queue.app);
|
||||
if (queue.runningOomAdjusted) {
|
||||
queue.app.mState.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER);
|
||||
mService.enqueueOomAdjTargetLocked(queue.app);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1266,10 +1267,11 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
|
||||
*/
|
||||
private void notifyStoppedRunning(@NonNull BroadcastProcessQueue queue) {
|
||||
if (queue.app != null) {
|
||||
// Update during our next pass; no need for an immediate update
|
||||
mService.enqueueOomAdjTargetLocked(queue.app);
|
||||
|
||||
queue.app.mReceivers.decrementCurReceivers();
|
||||
|
||||
if (queue.runningOomAdjusted) {
|
||||
mService.enqueueOomAdjTargetLocked(queue.app);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.app.procstats.ProcessState;
|
||||
import com.android.internal.app.procstats.ProcessStats;
|
||||
import com.android.internal.os.Zygote;
|
||||
import com.android.server.FgThread;
|
||||
import com.android.server.wm.WindowProcessController;
|
||||
import com.android.server.wm.WindowProcessListener;
|
||||
|
||||
@@ -142,6 +143,13 @@ class ProcessRecord implements WindowProcessListener {
|
||||
@CompositeRWLock({"mService", "mProcLock"})
|
||||
private IApplicationThread mThread;
|
||||
|
||||
/**
|
||||
* Instance of {@link #mThread} that will always meet the {@code oneway}
|
||||
* contract, possibly by using {@link SameProcessApplicationThread}.
|
||||
*/
|
||||
@CompositeRWLock({"mService", "mProcLock"})
|
||||
private IApplicationThread mOnewayThread;
|
||||
|
||||
/**
|
||||
* Always keep this application running?
|
||||
*/
|
||||
@@ -603,16 +611,27 @@ class ProcessRecord implements WindowProcessListener {
|
||||
return mThread;
|
||||
}
|
||||
|
||||
@GuardedBy(anyOf = {"mService", "mProcLock"})
|
||||
IApplicationThread getOnewayThread() {
|
||||
return mOnewayThread;
|
||||
}
|
||||
|
||||
@GuardedBy({"mService", "mProcLock"})
|
||||
public void makeActive(IApplicationThread thread, ProcessStatsService tracker) {
|
||||
mProfile.onProcessActive(thread, tracker);
|
||||
mThread = thread;
|
||||
if (mPid == Process.myPid()) {
|
||||
mOnewayThread = new SameProcessApplicationThread(thread, FgThread.getHandler());
|
||||
} else {
|
||||
mOnewayThread = thread;
|
||||
}
|
||||
mWindowProcessController.setThread(thread);
|
||||
}
|
||||
|
||||
@GuardedBy({"mService", "mProcLock"})
|
||||
public void makeInactive(ProcessStatsService tracker) {
|
||||
mThread = null;
|
||||
mOnewayThread = null;
|
||||
mWindowProcessController.setThread(null);
|
||||
mProfile.onProcessInactive(tracker);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.app.IApplicationThread;
|
||||
import android.content.IIntentReceiver;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.res.CompatibilityInfo;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Wrapper around an {@link IApplicationThread} that delegates selected calls
|
||||
* through a {@link Handler} so they meet the {@code oneway} contract of
|
||||
* returning immediately after dispatch.
|
||||
*/
|
||||
public class SameProcessApplicationThread extends IApplicationThread.Default {
|
||||
private final IApplicationThread mWrapped;
|
||||
private final Handler mHandler;
|
||||
|
||||
public SameProcessApplicationThread(@NonNull IApplicationThread wrapped,
|
||||
@NonNull Handler handler) {
|
||||
mWrapped = Objects.requireNonNull(wrapped);
|
||||
mHandler = Objects.requireNonNull(handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scheduleReceiver(Intent intent, ActivityInfo info, CompatibilityInfo compatInfo,
|
||||
int resultCode, String data, Bundle extras, boolean sync, int sendingUser,
|
||||
int processState) {
|
||||
mHandler.post(() -> {
|
||||
try {
|
||||
mWrapped.scheduleReceiver(intent, info, compatInfo, resultCode, data, extras, sync,
|
||||
sendingUser, processState);
|
||||
} catch (RemoteException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent, int resultCode,
|
||||
String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser,
|
||||
int processState) {
|
||||
mHandler.post(() -> {
|
||||
try {
|
||||
mWrapped.scheduleRegisteredReceiver(receiver, intent, resultCode, data, extras,
|
||||
ordered, sticky, sendingUser, processState);
|
||||
} catch (RemoteException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -87,6 +87,10 @@ public class BroadcastQueueModernImplTest {
|
||||
mHandlerThread.start();
|
||||
|
||||
mConstants = new BroadcastConstants(Settings.Global.BROADCAST_FG_CONSTANTS);
|
||||
mConstants.DELAY_URGENT_MILLIS = -120_000;
|
||||
mConstants.DELAY_NORMAL_MILLIS = 10_000;
|
||||
mConstants.DELAY_CACHED_MILLIS = 120_000;
|
||||
|
||||
mImpl = new BroadcastQueueModernImpl(mAms, mHandlerThread.getThreadHandler(),
|
||||
mConstants, mConstants);
|
||||
|
||||
|
||||
@@ -888,7 +888,7 @@ public class BroadcastQueueTest {
|
||||
}) {
|
||||
// Confirm expected OOM adjustments; we were invoked once to upgrade
|
||||
// and once to downgrade
|
||||
assertEquals(ActivityManager.PROCESS_STATE_RECEIVER,
|
||||
assertEquals(String.valueOf(receiverApp), ActivityManager.PROCESS_STATE_RECEIVER,
|
||||
receiverApp.mState.getReportedProcState());
|
||||
verify(mAms, times(2)).enqueueOomAdjTargetLocked(eq(receiverApp));
|
||||
|
||||
@@ -897,8 +897,8 @@ public class BroadcastQueueTest {
|
||||
// cold-started apps to be thawed, but the modern stack does
|
||||
} else {
|
||||
// Confirm that app was thawed
|
||||
verify(mAms.mOomAdjuster.mCachedAppOptimizer).unfreezeTemporarily(eq(receiverApp),
|
||||
eq(OomAdjuster.OOM_ADJ_REASON_START_RECEIVER));
|
||||
verify(mAms.mOomAdjuster.mCachedAppOptimizer, atLeastOnce()).unfreezeTemporarily(
|
||||
eq(receiverApp), eq(OomAdjuster.OOM_ADJ_REASON_START_RECEIVER));
|
||||
|
||||
// Confirm that we added package to process
|
||||
verify(receiverApp, atLeastOnce()).addPackage(eq(receiverApp.info.packageName),
|
||||
@@ -1599,4 +1599,39 @@ public class BroadcastQueueTest {
|
||||
assertTrue(mQueue.isBeyondBarrierLocked(afterFirst));
|
||||
assertTrue(mQueue.isBeyondBarrierLocked(afterSecond));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that we OOM adjust for manifest receivers.
|
||||
*/
|
||||
@Test
|
||||
public void testOomAdjust_Manifest() throws Exception {
|
||||
final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED);
|
||||
|
||||
final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
|
||||
enqueueBroadcast(makeBroadcastRecord(airplane, callerApp,
|
||||
List.of(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN),
|
||||
makeManifestReceiver(PACKAGE_GREEN, CLASS_BLUE),
|
||||
makeManifestReceiver(PACKAGE_GREEN, CLASS_RED))));
|
||||
|
||||
waitForIdle();
|
||||
verify(mAms, atLeastOnce()).enqueueOomAdjTargetLocked(any());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that we never OOM adjust for registered receivers.
|
||||
*/
|
||||
@Test
|
||||
public void testOomAdjust_Registered() throws Exception {
|
||||
final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED);
|
||||
final ProcessRecord receiverApp = makeActiveProcessRecord(PACKAGE_GREEN);
|
||||
|
||||
final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
|
||||
enqueueBroadcast(makeBroadcastRecord(airplane, callerApp,
|
||||
List.of(makeRegisteredReceiver(receiverApp),
|
||||
makeRegisteredReceiver(receiverApp),
|
||||
makeRegisteredReceiver(receiverApp))));
|
||||
|
||||
waitForIdle();
|
||||
verify(mAms, never()).enqueueOomAdjTargetLocked(any());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user