summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/ContextImpl.java22
-rw-r--r--core/java/android/app/LoadedApk.java12
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java105
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerShellCommand.java7
-rw-r--r--services/core/java/com/android/server/am/BroadcastHistory.java224
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueue.java65
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueueImpl.java316
-rw-r--r--services/core/java/com/android/server/am/BroadcastRecord.java14
-rw-r--r--services/core/java/com/android/server/am/OomAdjuster.java7
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java11
-rw-r--r--services/core/java/com/android/server/am/ProcessStateRecord.java9
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java17
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java4
13 files changed, 463 insertions, 350 deletions
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 4c7bc6da7fb2..80121b729779 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1390,8 +1390,9 @@ class ContextImpl extends Context {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
- rd = new LoadedApk.ReceiverDispatcher(
- resultReceiver, getOuterContext(), scheduler, null, false).getIIntentReceiver();
+ rd = new LoadedApk.ReceiverDispatcher(mMainThread.getApplicationThread(),
+ resultReceiver, getOuterContext(), scheduler, null, false)
+ .getIIntentReceiver();
}
}
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
@@ -1497,8 +1498,9 @@ class ContextImpl extends Context {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
- rd = new LoadedApk.ReceiverDispatcher(resultReceiver, getOuterContext(),
- scheduler, null, false).getIIntentReceiver();
+ rd = new LoadedApk.ReceiverDispatcher(mMainThread.getApplicationThread(),
+ resultReceiver, getOuterContext(), scheduler, null, false)
+ .getIIntentReceiver();
}
}
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
@@ -1616,8 +1618,9 @@ class ContextImpl extends Context {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
- rd = new LoadedApk.ReceiverDispatcher(
- resultReceiver, getOuterContext(), scheduler, null, false).getIIntentReceiver();
+ rd = new LoadedApk.ReceiverDispatcher(mMainThread.getApplicationThread(),
+ resultReceiver, getOuterContext(), scheduler, null, false)
+ .getIIntentReceiver();
}
}
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
@@ -1699,8 +1702,9 @@ class ContextImpl extends Context {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
- rd = new LoadedApk.ReceiverDispatcher(
- resultReceiver, getOuterContext(), scheduler, null, false).getIIntentReceiver();
+ rd = new LoadedApk.ReceiverDispatcher(mMainThread.getApplicationThread(),
+ resultReceiver, getOuterContext(), scheduler, null, false)
+ .getIIntentReceiver();
}
}
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
@@ -1802,7 +1806,7 @@ class ContextImpl extends Context {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
- rd = new LoadedApk.ReceiverDispatcher(
+ rd = new LoadedApk.ReceiverDispatcher(mMainThread.getApplicationThread(),
receiver, context, scheduler, null, true).getIIntentReceiver();
}
}
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 0849a6f67dbc..3620a601d355 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -1598,8 +1598,8 @@ public final class LoadedApk {
}
}
if (rd == null) {
- rd = new ReceiverDispatcher(r, context, handler,
- instrumentation, registered);
+ rd = new ReceiverDispatcher(mActivityThread.getApplicationThread(), r, context,
+ handler, instrumentation, registered);
if (registered) {
if (map == null) {
map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
@@ -1714,6 +1714,7 @@ public final class LoadedApk {
}
}
+ final IApplicationThread mAppThread;
final IIntentReceiver.Stub mIIntentReceiver;
@UnsupportedAppUsage
final BroadcastReceiver mReceiver;
@@ -1736,7 +1737,7 @@ public final class LoadedApk {
boolean ordered, boolean sticky, int sendingUser) {
super(resultCode, resultData, resultExtras,
mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED, ordered,
- sticky, mIIntentReceiver.asBinder(), sendingUser, intent.getFlags());
+ sticky, mAppThread.asBinder(), sendingUser, intent.getFlags());
mCurIntent = intent;
mOrdered = ordered;
}
@@ -1811,13 +1812,14 @@ public final class LoadedApk {
}
}
- ReceiverDispatcher(BroadcastReceiver receiver, Context context,
- Handler activityThread, Instrumentation instrumentation,
+ ReceiverDispatcher(IApplicationThread appThread, BroadcastReceiver receiver,
+ Context context, Handler activityThread, Instrumentation instrumentation,
boolean registered) {
if (activityThread == null) {
throw new NullPointerException("Handler must not be null");
}
+ mAppThread = appThread;
mIIntentReceiver = new InnerReceiver(this, !registered);
mReceiver = receiver;
mContext = context;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2cf24fa9df1f..0a3323c76a50 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2412,13 +2412,13 @@ public class ActivityManagerService extends IActivityManager.Stub
mBroadcastQueues = new BroadcastQueue[4];
mFgBroadcastQueue = new BroadcastQueueImpl(this, mHandler,
- "foreground", foreConstants, false);
+ "foreground", foreConstants, false, ProcessList.SCHED_GROUP_DEFAULT);
mBgBroadcastQueue = new BroadcastQueueImpl(this, mHandler,
- "background", backConstants, true);
+ "background", backConstants, true, ProcessList.SCHED_GROUP_BACKGROUND);
mBgOffloadBroadcastQueue = new BroadcastQueueImpl(this, mHandler,
- "offload_bg", offloadConstants, true);
+ "offload_bg", offloadConstants, true, ProcessList.SCHED_GROUP_BACKGROUND);
mFgOffloadBroadcastQueue = new BroadcastQueueImpl(this, mHandler,
- "offload_fg", foreConstants, true);
+ "offload_fg", foreConstants, true, ProcessList.SCHED_GROUP_BACKGROUND);
mBroadcastQueues[0] = mFgBroadcastQueue;
mBroadcastQueues[1] = mBgBroadcastQueue;
mBroadcastQueues[2] = mBgOffloadBroadcastQueue;
@@ -3263,13 +3263,20 @@ public class ActivityManagerService extends IActivityManager.Stub
if (thread == null) {
return null;
}
+ return getRecordForAppLOSP(thread.asBinder());
+ }
+
+ @GuardedBy(anyOf = {"this", "mProcLock"})
+ ProcessRecord getRecordForAppLOSP(IBinder threadBinder) {
+ if (threadBinder == null) {
+ return null;
+ }
- ProcessRecord record = mProcessList.getLRURecordForAppLOSP(thread);
+ ProcessRecord record = mProcessList.getLRURecordForAppLOSP(threadBinder);
if (record != null) return record;
// Validation: if it isn't in the LRU list, it shouldn't exist, but let's
// double-check that.
- final IBinder threadBinder = thread.asBinder();
final ArrayMap<String, SparseArray<ProcessRecord>> pmap =
mProcessList.getProcessNamesLOSP().getMap();
for (int i = pmap.size()-1; i >= 0; i--) {
@@ -10649,7 +10656,7 @@ public class ActivityManagerService extends IActivityManager.Stub
if (!onlyHistory && !onlyReceivers && dumpAll) {
pw.println();
for (BroadcastQueue queue : mBroadcastQueues) {
- pw.println(" Queue " + queue.toString() + ": " + queue.describeState());
+ pw.println(" Queue " + queue.toString() + ": " + queue.describeStateLocked());
}
pw.println(" mHandler:");
mHandler.dump(new PrintWriterPrinter(pw), " ");
@@ -13370,7 +13377,7 @@ public class ActivityManagerService extends IActivityManager.Stub
final BroadcastRecord r = rl.curBroadcast;
if (r != null) {
final boolean doNext = r.queue.finishReceiverLocked(
- receiver.asBinder(), r.resultCode, r.resultData, r.resultExtras,
+ rl.app, r.resultCode, r.resultData, r.resultExtras,
r.resultAbort, false);
if (doNext) {
doTrim = true;
@@ -14538,9 +14545,9 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- public void finishReceiver(IBinder who, int resultCode, String resultData,
+ public void finishReceiver(IBinder caller, int resultCode, String resultData,
Bundle resultExtras, boolean resultAbort, int flags) {
- if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Finish receiver: " + who);
+ if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Finish receiver: " + caller);
// Refuse possible leaked file descriptors
if (resultExtras != null && resultExtras.hasFileDescriptors()) {
@@ -14549,12 +14556,15 @@ public class ActivityManagerService extends IActivityManager.Stub
final long origId = Binder.clearCallingIdentity();
try {
- boolean doNext = false;
- BroadcastRecord r;
- BroadcastQueue queue;
synchronized(this) {
- queue = broadcastQueueForFlags(flags);
- doNext = queue.finishReceiverLocked(who, resultCode,
+ final ProcessRecord callerApp = getRecordForAppLOSP(caller);
+ if (callerApp == null) {
+ Slog.w(TAG, "finishReceiver: no app for " + caller);
+ return;
+ }
+
+ final BroadcastQueue queue = broadcastQueueForFlags(flags);
+ queue.finishReceiverLocked(callerApp, resultCode,
resultData, resultExtras, resultAbort, true);
// updateOomAdjLocked() will be done here
trimApplicationsLocked(false, OomAdjuster.OOM_ADJ_REASON_FINISH_RECEIVER);
@@ -15106,30 +15116,13 @@ public class ActivityManagerService extends IActivityManager.Stub
// LIFETIME MANAGEMENT
// =========================================================
- // Returns whether the app is receiving broadcast.
- // If receiving, fetch all broadcast queues which the app is
- // the current [or imminent] receiver on.
- boolean isReceivingBroadcastLocked(ProcessRecord app,
- ArraySet<BroadcastQueue> receivingQueues) {
- final ProcessReceiverRecord prr = app.mReceivers;
- final int numOfReceivers = prr.numberOfCurReceivers();
- if (numOfReceivers > 0) {
- for (int i = 0; i < numOfReceivers; i++) {
- receivingQueues.add(prr.getCurReceiverAt(i).queue);
- }
- return true;
- }
-
- // It's not the current receiver, but it might be starting up to become one
+ boolean isReceivingBroadcastLocked(ProcessRecord app, int[] outSchedGroup) {
+ int res = ProcessList.SCHED_GROUP_UNDEFINED;
for (BroadcastQueue queue : mBroadcastQueues) {
- final BroadcastRecord r = queue.getPendingBroadcastLocked();
- if (r != null && r.curApp == app) {
- // found it; report which queue it's in
- receivingQueues.add(queue);
- }
+ res = Math.max(res, queue.getPreferredSchedulingGroupLocked(app));
}
-
- return !receivingQueues.isEmpty();
+ outSchedGroup[0] = res;
+ return res != ProcessList.SCHED_GROUP_UNDEFINED;
}
Association startAssociationLocked(int sourceUid, String sourceProcess, int sourceState,
@@ -15237,7 +15230,7 @@ public class ActivityManagerService extends IActivityManager.Stub
@GuardedBy("this")
final boolean canGcNowLocked() {
for (BroadcastQueue q : mBroadcastQueues) {
- if (!q.isIdle()) {
+ if (!q.isIdleLocked()) {
return false;
}
}
@@ -17814,35 +17807,15 @@ public class ActivityManagerService extends IActivityManager.Stub
public void waitForBroadcastIdle(@Nullable PrintWriter pw) {
enforceCallingPermission(permission.DUMP, "waitForBroadcastIdle()");
- while (true) {
- boolean idle = true;
- synchronized (this) {
- for (BroadcastQueue queue : mBroadcastQueues) {
- if (!queue.isIdle()) {
- final String msg = "Waiting for queue " + queue + " to become idle...";
- if (pw != null) {
- pw.println(msg);
- pw.println(queue.describeState());
- pw.flush();
- }
- Slog.v(TAG, msg);
- queue.flush();
- idle = false;
- }
- }
- }
+ for (BroadcastQueue queue : mBroadcastQueues) {
+ queue.waitForIdle(pw);
+ }
+ }
- if (idle) {
- final String msg = "All broadcast queues are idle!";
- if (pw != null) {
- pw.println(msg);
- pw.flush();
- }
- Slog.v(TAG, msg);
- return;
- } else {
- SystemClock.sleep(1000);
- }
+ public void waitForBroadcastBarrier(@Nullable PrintWriter pw) {
+ enforceCallingPermission(permission.DUMP, "waitForBroadcastBarrier()");
+ for (BroadcastQueue queue : mBroadcastQueues) {
+ queue.waitForBarrier(pw);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index a42b2a48f886..b4f6e35b3df3 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -341,6 +341,8 @@ final class ActivityManagerShellCommand extends ShellCommand {
return runNoHomeScreen(pw);
case "wait-for-broadcast-idle":
return runWaitForBroadcastIdle(pw);
+ case "wait-for-broadcast-barrier":
+ return runWaitForBroadcastBarrier(pw);
case "compat":
return runCompat(pw);
case "refresh-settings-cache":
@@ -3112,6 +3114,11 @@ final class ActivityManagerShellCommand extends ShellCommand {
return 0;
}
+ int runWaitForBroadcastBarrier(PrintWriter pw) throws RemoteException {
+ mInternal.waitForBroadcastBarrier(pw);
+ return 0;
+ }
+
int runRefreshSettingsCache() throws RemoteException {
mInternal.refreshSettingsCache();
return 0;
diff --git a/services/core/java/com/android/server/am/BroadcastHistory.java b/services/core/java/com/android/server/am/BroadcastHistory.java
new file mode 100644
index 000000000000..d820d6c802b3
--- /dev/null
+++ b/services/core/java/com/android/server/am/BroadcastHistory.java
@@ -0,0 +1,224 @@
+/*
+ * 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.app.ActivityManager;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
+
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * Collection of recent historical broadcasts that are available to be dumped
+ * for debugging purposes. Automatically trims itself over time.
+ */
+public class BroadcastHistory {
+ static final int MAX_BROADCAST_HISTORY = ActivityManager.isLowRamDeviceStatic() ? 10 : 50;
+ static final int MAX_BROADCAST_SUMMARY_HISTORY
+ = ActivityManager.isLowRamDeviceStatic() ? 25 : 300;
+
+ /**
+ * Historical data of past broadcasts, for debugging. This is a ring buffer
+ * whose last element is at mHistoryNext.
+ */
+ final BroadcastRecord[] mBroadcastHistory = new BroadcastRecord[MAX_BROADCAST_HISTORY];
+ int mHistoryNext = 0;
+
+ /**
+ * Summary of historical data of past broadcasts, for debugging. This is a
+ * ring buffer whose last element is at mSummaryHistoryNext.
+ */
+ final Intent[] mBroadcastSummaryHistory = new Intent[MAX_BROADCAST_SUMMARY_HISTORY];
+ int mSummaryHistoryNext = 0;
+
+ /**
+ * Various milestone timestamps of entries in the mBroadcastSummaryHistory ring
+ * buffer, also tracked via the mSummaryHistoryNext index. These are all in wall
+ * clock time, not elapsed.
+ */
+ final long[] mSummaryHistoryEnqueueTime = new long[MAX_BROADCAST_SUMMARY_HISTORY];
+ final long[] mSummaryHistoryDispatchTime = new long[MAX_BROADCAST_SUMMARY_HISTORY];
+ final long[] mSummaryHistoryFinishTime = new long[MAX_BROADCAST_SUMMARY_HISTORY];
+
+ public void addBroadcastToHistoryLocked(BroadcastRecord original) {
+ // Note sometimes (only for sticky broadcasts?) we reuse BroadcastRecords,
+ // So don't change the incoming record directly.
+ final BroadcastRecord historyRecord = original.maybeStripForHistory();
+
+ mBroadcastHistory[mHistoryNext] = historyRecord;
+ mHistoryNext = ringAdvance(mHistoryNext, 1, MAX_BROADCAST_HISTORY);
+
+ mBroadcastSummaryHistory[mSummaryHistoryNext] = historyRecord.intent;
+ mSummaryHistoryEnqueueTime[mSummaryHistoryNext] = historyRecord.enqueueClockTime;
+ mSummaryHistoryDispatchTime[mSummaryHistoryNext] = historyRecord.dispatchClockTime;
+ mSummaryHistoryFinishTime[mSummaryHistoryNext] = System.currentTimeMillis();
+ mSummaryHistoryNext = ringAdvance(mSummaryHistoryNext, 1, MAX_BROADCAST_SUMMARY_HISTORY);
+ }
+
+ private final int ringAdvance(int x, final int increment, final int ringSize) {
+ x += increment;
+ if (x < 0) return (ringSize - 1);
+ else if (x >= ringSize) return 0;
+ else return x;
+ }
+
+ public void dumpDebug(ProtoOutputStream proto) {
+ int lastIndex = mHistoryNext;
+ int ringIndex = lastIndex;
+ do {
+ // increasing index = more recent entry, and we want to print the most
+ // recent first and work backwards, so we roll through the ring backwards.
+ ringIndex = ringAdvance(ringIndex, -1, MAX_BROADCAST_HISTORY);
+ BroadcastRecord r = mBroadcastHistory[ringIndex];
+ if (r != null) {
+ r.dumpDebug(proto, BroadcastQueueProto.HISTORICAL_BROADCASTS);
+ }
+ } while (ringIndex != lastIndex);
+
+ lastIndex = ringIndex = mSummaryHistoryNext;
+ do {
+ ringIndex = ringAdvance(ringIndex, -1, MAX_BROADCAST_SUMMARY_HISTORY);
+ Intent intent = mBroadcastSummaryHistory[ringIndex];
+ if (intent == null) {
+ continue;
+ }
+ long summaryToken = proto.start(BroadcastQueueProto.HISTORICAL_BROADCASTS_SUMMARY);
+ intent.dumpDebug(proto, BroadcastQueueProto.BroadcastSummary.INTENT,
+ false, true, true, false);
+ proto.write(BroadcastQueueProto.BroadcastSummary.ENQUEUE_CLOCK_TIME_MS,
+ mSummaryHistoryEnqueueTime[ringIndex]);
+ proto.write(BroadcastQueueProto.BroadcastSummary.DISPATCH_CLOCK_TIME_MS,
+ mSummaryHistoryDispatchTime[ringIndex]);
+ proto.write(BroadcastQueueProto.BroadcastSummary.FINISH_CLOCK_TIME_MS,
+ mSummaryHistoryFinishTime[ringIndex]);
+ proto.end(summaryToken);
+ } while (ringIndex != lastIndex);
+ }
+
+ public boolean dumpLocked(PrintWriter pw, String dumpPackage, String queueName,
+ SimpleDateFormat sdf, boolean dumpAll, boolean needSep) {
+ int i;
+ boolean printed = false;
+
+ i = -1;
+ int lastIndex = mHistoryNext;
+ int ringIndex = lastIndex;
+ do {
+ // increasing index = more recent entry, and we want to print the most
+ // recent first and work backwards, so we roll through the ring backwards.
+ ringIndex = ringAdvance(ringIndex, -1, MAX_BROADCAST_HISTORY);
+ BroadcastRecord r = mBroadcastHistory[ringIndex];
+ if (r == null) {
+ continue;
+ }
+
+ i++; // genuine record of some sort even if we're filtering it out
+ if (dumpPackage != null && !dumpPackage.equals(r.callerPackage)) {
+ continue;
+ }
+ if (!printed) {
+ if (needSep) {
+ pw.println();
+ }
+ needSep = true;
+ pw.println(" Historical broadcasts [" + queueName + "]:");
+ printed = true;
+ }
+ if (dumpAll) {
+ pw.print(" Historical Broadcast " + queueName + " #");
+ pw.print(i); pw.println(":");
+ r.dump(pw, " ", sdf);
+ } else {
+ pw.print(" #"); pw.print(i); pw.print(": "); pw.println(r);
+ pw.print(" ");
+ pw.println(r.intent.toShortString(false, true, true, false));
+ if (r.targetComp != null && r.targetComp != r.intent.getComponent()) {
+ pw.print(" targetComp: "); pw.println(r.targetComp.toShortString());
+ }
+ Bundle bundle = r.intent.getExtras();
+ if (bundle != null) {
+ pw.print(" extras: "); pw.println(bundle.toString());
+ }
+ }
+ } while (ringIndex != lastIndex);
+
+ if (dumpPackage == null) {
+ lastIndex = ringIndex = mSummaryHistoryNext;
+ if (dumpAll) {
+ printed = false;
+ i = -1;
+ } else {
+ // roll over the 'i' full dumps that have already been issued
+ for (int j = i;
+ j > 0 && ringIndex != lastIndex;) {
+ ringIndex = ringAdvance(ringIndex, -1, MAX_BROADCAST_SUMMARY_HISTORY);
+ BroadcastRecord r = mBroadcastHistory[ringIndex];
+ if (r == null) {
+ continue;
+ }
+ j--;
+ }
+ }
+ // done skipping; dump the remainder of the ring. 'i' is still the ordinal within
+ // the overall broadcast history.
+ do {
+ ringIndex = ringAdvance(ringIndex, -1, MAX_BROADCAST_SUMMARY_HISTORY);
+ Intent intent = mBroadcastSummaryHistory[ringIndex];
+ if (intent == null) {
+ continue;
+ }
+ if (!printed) {
+ if (needSep) {
+ pw.println();
+ }
+ needSep = true;
+ pw.println(" Historical broadcasts summary [" + queueName + "]:");
+ printed = true;
+ }
+ if (!dumpAll && i >= 50) {
+ pw.println(" ...");
+ break;
+ }
+ i++;
+ pw.print(" #"); pw.print(i); pw.print(": ");
+ pw.println(intent.toShortString(false, true, true, false));
+ pw.print(" ");
+ TimeUtils.formatDuration(mSummaryHistoryDispatchTime[ringIndex]
+ - mSummaryHistoryEnqueueTime[ringIndex], pw);
+ pw.print(" dispatch ");
+ TimeUtils.formatDuration(mSummaryHistoryFinishTime[ringIndex]
+ - mSummaryHistoryDispatchTime[ringIndex], pw);
+ pw.println(" finish");
+ pw.print(" enq=");
+ pw.print(sdf.format(new Date(mSummaryHistoryEnqueueTime[ringIndex])));
+ pw.print(" disp=");
+ pw.print(sdf.format(new Date(mSummaryHistoryDispatchTime[ringIndex])));
+ pw.print(" fin=");
+ pw.println(sdf.format(new Date(mSummaryHistoryFinishTime[ringIndex])));
+ Bundle bundle = intent.getExtras();
+ if (bundle != null) {
+ pw.print(" extras: "); pw.println(bundle.toString());
+ }
+ } while (ringIndex != lastIndex);
+ }
+ return needSep;
+ }
+}
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 752c6b683e05..6814509922b1 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -18,12 +18,10 @@ package com.android.server.am;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
-import android.os.IBinder;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
@@ -43,16 +41,18 @@ public abstract class BroadcastQueue {
final @NonNull Handler mHandler;
final @NonNull BroadcastConstants mConstants;
final @NonNull BroadcastSkipPolicy mSkipPolicy;
+ final @NonNull BroadcastHistory mHistory;
final @NonNull String mQueueName;
BroadcastQueue(@NonNull ActivityManagerService service, @NonNull Handler handler,
@NonNull String name, @NonNull BroadcastConstants constants,
- @NonNull BroadcastSkipPolicy skipPolicy) {
+ @NonNull BroadcastSkipPolicy skipPolicy, @NonNull BroadcastHistory history) {
mService = Objects.requireNonNull(service);
mHandler = Objects.requireNonNull(handler);
mQueueName = Objects.requireNonNull(name);
mConstants = Objects.requireNonNull(constants);
mSkipPolicy = Objects.requireNonNull(skipPolicy);
+ mHistory = Objects.requireNonNull(history);
}
void start(@NonNull ContentResolver resolver) {
@@ -66,11 +66,15 @@ public abstract class BroadcastQueue {
public abstract boolean isDelayBehindServices();
- @GuardedBy("mService")
- public abstract @Nullable BroadcastRecord getPendingBroadcastLocked();
-
- @GuardedBy("mService")
- public abstract @Nullable BroadcastRecord getActiveBroadcastLocked();
+ /**
+ * Return the preferred scheduling group for the given process, typically
+ * influenced by a broadcast being actively dispatched.
+ *
+ * @return scheduling group such as {@link ProcessList#SCHED_GROUP_DEFAULT},
+ * otherwise {@link ProcessList#SCHED_GROUP_UNDEFINED} if this queue
+ * has no opinion.
+ */
+ public abstract int getPreferredSchedulingGroupLocked(@NonNull ProcessRecord app);
/**
* Enqueue the given broadcast to be eventually dispatched.
@@ -85,17 +89,14 @@ public abstract class BroadcastQueue {
public abstract void enqueueBroadcastLocked(@NonNull BroadcastRecord r);
/**
- * Signal delivered back from a {@link BroadcastReceiver} to indicate that
- * it's finished processing the current broadcast being dispatched to it.
+ * Signal delivered back from the given process to indicate that it's
+ * finished processing the current broadcast being dispatched to it.
* <p>
* If this signal isn't delivered back in a timely fashion, we assume the
* receiver has somehow wedged and we trigger an ANR.
- *
- * @param receiver the value to match against
- * {@link BroadcastRecord#receiver} to identify the caller.
*/
@GuardedBy("mService")
- public abstract boolean finishReceiverLocked(@NonNull IBinder receiver, int resultCode,
+ public abstract boolean finishReceiverLocked(@NonNull ProcessRecord app, int resultCode,
@Nullable String resultData, @Nullable Bundle resultExtras, boolean resultAbort,
boolean waitForServices);
@@ -144,22 +145,40 @@ public abstract class BroadcastQueue {
* Quickly determine if this queue has broadcasts that are still waiting to
* be delivered at some point in the future.
*
- * @see #flush()
+ * @see #waitForIdle
+ * @see #waitForBarrier
*/
- public abstract boolean isIdle();
+ @GuardedBy("mService")
+ public abstract boolean isIdleLocked();
/**
- * Brief summary of internal state, useful for debugging purposes.
+ * Wait until this queue becomes completely idle.
+ * <p>
+ * Any broadcasts waiting to be delivered at some point in the future will
+ * be dispatched as quickly as possible.
+ * <p>
+ * Callers are cautioned that the queue may take a long time to go idle,
+ * since running apps can continue sending new broadcasts in perpetuity;
+ * consider using {@link #waitForBarrier} instead.
*/
- public abstract @NonNull String describeState();
+ public abstract void waitForIdle(@Nullable PrintWriter pw);
/**
- * Flush any broadcasts still waiting to be delivered, causing them to be
- * delivered as soon as possible.
- *
- * @see #isIdle()
+ * Wait until any currently waiting broadcasts have been dispatched.
+ * <p>
+ * Any broadcasts waiting to be delivered at some point in the future will
+ * be dispatched as quickly as possible.
+ * <p>
+ * Callers are advised that this method will <em>not</em> wait for any
+ * future broadcasts that are newly enqueued after being invoked.
*/
- public abstract void flush();
+ public abstract void waitForBarrier(@Nullable PrintWriter pw);
+
+ /**
+ * Brief summary of internal state, useful for debugging purposes.
+ */
+ @GuardedBy("mService")
+ public abstract @NonNull String describeStateLocked();
public abstract void dumpDebug(@NonNull ProtoOutputStream proto, long fieldId);
diff --git a/services/core/java/com/android/server/am/BroadcastQueueImpl.java b/services/core/java/com/android/server/am/BroadcastQueueImpl.java
index d9146121fc27..56112cfbc3e9 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueImpl.java
@@ -73,7 +73,6 @@ import android.text.TextUtils;
import android.util.EventLog;
import android.util.Slog;
import android.util.SparseIntArray;
-import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
import com.android.internal.os.TimeoutRecord;
@@ -85,8 +84,8 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
-import java.util.Date;
import java.util.Set;
+import java.util.function.BooleanSupplier;
/**
* BROADCASTS
@@ -99,16 +98,14 @@ public class BroadcastQueueImpl extends BroadcastQueue {
private static final String TAG_MU = TAG + POSTFIX_MU;
private static final String TAG_BROADCAST = TAG + POSTFIX_BROADCAST;
- static final int MAX_BROADCAST_HISTORY = ActivityManager.isLowRamDeviceStatic() ? 10 : 50;
- static final int MAX_BROADCAST_SUMMARY_HISTORY
- = ActivityManager.isLowRamDeviceStatic() ? 25 : 300;
-
/**
* If true, we can delay broadcasts while waiting services to finish in the previous
* receiver's process.
*/
final boolean mDelayBehindServices;
+ final int mSchedGroup;
+
/**
* Lists of all active broadcasts that are to be executed immediately
* (without waiting for another broadcast to finish). Currently this only
@@ -133,29 +130,6 @@ public class BroadcastQueueImpl extends BroadcastQueue {
private int mNextToken = 0;
/**
- * Historical data of past broadcasts, for debugging. This is a ring buffer
- * whose last element is at mHistoryNext.
- */
- final BroadcastRecord[] mBroadcastHistory = new BroadcastRecord[MAX_BROADCAST_HISTORY];
- int mHistoryNext = 0;
-
- /**
- * Summary of historical data of past broadcasts, for debugging. This is a
- * ring buffer whose last element is at mSummaryHistoryNext.
- */
- final Intent[] mBroadcastSummaryHistory = new Intent[MAX_BROADCAST_SUMMARY_HISTORY];
- int mSummaryHistoryNext = 0;
-
- /**
- * Various milestone timestamps of entries in the mBroadcastSummaryHistory ring
- * buffer, also tracked via the mSummaryHistoryNext index. These are all in wall
- * clock time, not elapsed.
- */
- final long[] mSummaryHistoryEnqueueTime = new long[MAX_BROADCAST_SUMMARY_HISTORY];
- final long[] mSummaryHistoryDispatchTime = new long[MAX_BROADCAST_SUMMARY_HISTORY];
- final long[] mSummaryHistoryFinishTime = new long[MAX_BROADCAST_SUMMARY_HISTORY];
-
- /**
* Set when we current have a BROADCAST_INTENT_MSG in flight.
*/
boolean mBroadcastsScheduled = false;
@@ -211,17 +185,19 @@ public class BroadcastQueueImpl extends BroadcastQueue {
}
BroadcastQueueImpl(ActivityManagerService service, Handler handler,
- String name, BroadcastConstants constants, boolean allowDelayBehindServices) {
+ String name, BroadcastConstants constants, boolean allowDelayBehindServices,
+ int schedGroup) {
this(service, handler, name, constants, new BroadcastSkipPolicy(service),
- allowDelayBehindServices);
+ new BroadcastHistory(), allowDelayBehindServices, schedGroup);
}
BroadcastQueueImpl(ActivityManagerService service, Handler handler,
String name, BroadcastConstants constants, BroadcastSkipPolicy skipPolicy,
- boolean allowDelayBehindServices) {
- super(service, handler, name, constants, skipPolicy);
+ BroadcastHistory history, boolean allowDelayBehindServices, int schedGroup) {
+ super(service, handler, name, constants, skipPolicy, history);
mHandler = new BroadcastHandler(handler.getLooper());
mDelayBehindServices = allowDelayBehindServices;
+ mSchedGroup = schedGroup;
mDispatcher = new BroadcastDispatcher(this, mConstants, mHandler, mService);
}
@@ -242,6 +218,18 @@ public class BroadcastQueueImpl extends BroadcastQueue {
return mDispatcher.getActiveBroadcastLocked();
}
+ public int getPreferredSchedulingGroupLocked(ProcessRecord app) {
+ final BroadcastRecord active = getActiveBroadcastLocked();
+ if (active != null && active.curApp == app) {
+ return mSchedGroup;
+ }
+ final BroadcastRecord pending = getPendingBroadcastLocked();
+ if (pending != null && pending.curApp == app) {
+ return mSchedGroup;
+ }
+ return ProcessList.SCHED_GROUP_UNDEFINED;
+ }
+
public void enqueueBroadcastLocked(BroadcastRecord r) {
final boolean replacePending = (r.intent.getFlags()
& Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
@@ -369,7 +357,6 @@ public class BroadcastQueueImpl extends BroadcastQueue {
return;
}
- r.receiver = thread.asBinder();
r.curApp = app;
final ProcessReceiverRecord prr = app.mReceivers;
prr.addCurReceiver(r);
@@ -407,7 +394,6 @@ public class BroadcastQueueImpl extends BroadcastQueue {
if (!started) {
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Process cur broadcast " + r + ": NOT STARTED!");
- r.receiver = null;
r.curApp = null;
prr.removeCurReceiver(r);
}
@@ -524,16 +510,16 @@ public class BroadcastQueueImpl extends BroadcastQueue {
mBroadcastsScheduled = true;
}
- public BroadcastRecord getMatchingOrderedReceiver(IBinder receiver) {
+ public BroadcastRecord getMatchingOrderedReceiver(ProcessRecord app) {
BroadcastRecord br = mDispatcher.getActiveBroadcastLocked();
if (br == null) {
Slog.w(TAG_BROADCAST, "getMatchingOrderedReceiver [" + mQueueName
+ "] no active broadcast");
return null;
}
- if (br.receiver != receiver) {
+ if (br.curApp != app) {
Slog.w(TAG_BROADCAST, "getMatchingOrderedReceiver [" + mQueueName
- + "] active broadcast " + br.receiver + " doesn't match " + receiver);
+ + "] active broadcast " + br.curApp + " doesn't match " + app);
return null;
}
return br;
@@ -564,9 +550,9 @@ public class BroadcastQueueImpl extends BroadcastQueue {
}, msgToken, (r.receiverTime + mConstants.ALLOW_BG_ACTIVITY_START_TIMEOUT));
}
- public boolean finishReceiverLocked(IBinder receiver, int resultCode,
+ public boolean finishReceiverLocked(ProcessRecord app, int resultCode,
String resultData, Bundle resultExtras, boolean resultAbort, boolean waitForServices) {
- final BroadcastRecord r = getMatchingOrderedReceiver(receiver);
+ final BroadcastRecord r = getMatchingOrderedReceiver(app);
if (r != null) {
return finishReceiverLocked(r, resultCode,
resultData, resultExtras, resultAbort, waitForServices);
@@ -647,7 +633,6 @@ public class BroadcastQueueImpl extends BroadcastQueue {
}
}
- r.receiver = null;
r.intent.setComponent(null);
if (r.curApp != null && r.curApp.mReceivers.hasCurReceiver(r)) {
r.curApp.mReceivers.removeCurReceiver(r);
@@ -674,7 +659,7 @@ public class BroadcastQueueImpl extends BroadcastQueue {
// If we want to wait behind services *AND* we're finishing the head/
// active broadcast on its queue
if (waitForServices && r.curComponent != null && r.queue.isDelayBehindServices()
- && r.queue.getActiveBroadcastLocked() == r) {
+ && ((BroadcastQueueImpl) r.queue).getActiveBroadcastLocked() == r) {
ActivityInfo nextReceiver;
if (r.nextReceiver < r.receivers.size()) {
Object obj = r.receivers.get(r.nextReceiver);
@@ -805,7 +790,6 @@ public class BroadcastQueueImpl extends BroadcastQueue {
// don't want to touch the fields that keep track of the current
// state of ordered broadcasts.
if (ordered) {
- r.receiver = filter.receiverList.receiver.asBinder();
r.curFilter = filter;
filter.receiverList.curBroadcast = r;
r.state = BroadcastRecord.CALL_IN_RECEIVE;
@@ -869,7 +853,6 @@ public class BroadcastQueueImpl extends BroadcastQueue {
}
// And BroadcastRecord state related to ordered delivery, if appropriate
if (ordered) {
- r.receiver = null;
r.curFilter = null;
filter.receiverList.curBroadcast = null;
}
@@ -1289,12 +1272,13 @@ public class BroadcastQueueImpl extends BroadcastQueue {
+ filter + ": " + r);
r.mIsReceiverAppRunning = true;
deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx);
- if (r.receiver == null || !r.ordered) {
+ if ((r.curReceiver == null && r.curFilter == null) || !r.ordered) {
// The receiver has already finished, so schedule to
// process the next one.
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Quick finishing ["
- + mQueueName + "]: ordered="
- + r.ordered + " receiver=" + r.receiver);
+ + mQueueName + "]: ordered=" + r.ordered
+ + " curFilter=" + r.curFilter
+ + " curReceiver=" + r.curReceiver);
r.state = BroadcastRecord.IDLE;
scheduleBroadcastsLocked();
} else {
@@ -1346,7 +1330,6 @@ public class BroadcastQueueImpl extends BroadcastQueue {
"Skipping delivery of ordered [" + mQueueName + "] "
+ r + " for reason described above");
r.delivery[recIdx] = BroadcastRecord.DELIVERY_SKIPPED;
- r.receiver = null;
r.curFilter = null;
r.state = BroadcastRecord.IDLE;
r.manifestSkipCount++;
@@ -1636,8 +1619,8 @@ public class BroadcastQueueImpl extends BroadcastQueue {
final boolean debugging = (r.curApp != null && r.curApp.isDebugging());
long timeoutDurationMs = now - r.receiverTime;
- Slog.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver
- + ", started " + timeoutDurationMs + "ms ago");
+ Slog.w(TAG, "Timeout of broadcast " + r + " - curFilter=" + r.curFilter + " curReceiver="
+ + r.curReceiver + ", started " + timeoutDurationMs + "ms ago");
r.receiverTime = now;
if (!debugging) {
r.anrCount++;
@@ -1689,13 +1672,6 @@ public class BroadcastQueueImpl extends BroadcastQueue {
}
}
- private final int ringAdvance(int x, final int increment, final int ringSize) {
- x += increment;
- if (x < 0) return (ringSize - 1);
- else if (x >= ringSize) return 0;
- else return x;
- }
-
private final void addBroadcastToHistoryLocked(BroadcastRecord original) {
if (original.callingUid < 0) {
// This was from a registerReceiver() call; ignore it.
@@ -1716,18 +1692,7 @@ public class BroadcastQueueImpl extends BroadcastQueue {
original.callingUid, 0, callerPackage).sendToTarget();
}
- // Note sometimes (only for sticky broadcasts?) we reuse BroadcastRecords,
- // So don't change the incoming record directly.
- final BroadcastRecord historyRecord = original.maybeStripForHistory();
-
- mBroadcastHistory[mHistoryNext] = historyRecord;
- mHistoryNext = ringAdvance(mHistoryNext, 1, MAX_BROADCAST_HISTORY);
-
- mBroadcastSummaryHistory[mSummaryHistoryNext] = historyRecord.intent;
- mSummaryHistoryEnqueueTime[mSummaryHistoryNext] = historyRecord.enqueueClockTime;
- mSummaryHistoryDispatchTime[mSummaryHistoryNext] = historyRecord.dispatchClockTime;
- mSummaryHistoryFinishTime[mSummaryHistoryNext] = System.currentTimeMillis();
- mSummaryHistoryNext = ringAdvance(mSummaryHistoryNext, 1, MAX_BROADCAST_SUMMARY_HISTORY);
+ mHistory.addBroadcastToHistoryLocked(original);
}
public boolean cleanupDisabledPackageReceiversLocked(
@@ -1781,13 +1746,72 @@ public class BroadcastQueueImpl extends BroadcastQueue {
record.intent == null ? "" : record.intent.getAction());
}
- public boolean isIdle() {
+ public boolean isIdleLocked() {
return mParallelBroadcasts.isEmpty() && mDispatcher.isIdle()
&& (mPendingBroadcast == null);
}
- public void flush() {
- cancelDeferrals();
+ public boolean isBeyondBarrierLocked(long barrierTime) {
+ // If nothing active, we're beyond barrier
+ if (isIdleLocked()) return true;
+
+ // Check if active broadcast is beyond barrier
+ final BroadcastRecord active = getActiveBroadcastLocked();
+ if (active != null && active.enqueueTime > barrierTime) {
+ return true;
+ }
+
+ // Check if pending broadcast is beyond barrier
+ final BroadcastRecord pending = getPendingBroadcastLocked();
+ if (pending != null && pending.enqueueTime > barrierTime) {
+ return true;
+ }
+
+ return false;
+ }
+
+ public void waitForIdle(PrintWriter pw) {
+ waitFor(() -> isIdleLocked(), pw, "idle");
+ }
+
+ public void waitForBarrier(PrintWriter pw) {
+ final long barrierTime = SystemClock.uptimeMillis();
+ waitFor(() -> isBeyondBarrierLocked(barrierTime), pw, "barrier");
+ }
+
+ private void waitFor(BooleanSupplier condition, PrintWriter pw, String conditionName) {
+ long lastPrint = 0;
+ while (true) {
+ synchronized (mService) {
+ if (condition.getAsBoolean()) {
+ final String msg = "Queue [" + mQueueName + "] reached " + conditionName
+ + " condition";
+ Slog.v(TAG, msg);
+ if (pw != null) {
+ pw.println(msg);
+ pw.flush();
+ }
+ return;
+ }
+ }
+
+ // Print at most every second
+ final long now = SystemClock.uptimeMillis();
+ if (now >= lastPrint + 1000) {
+ lastPrint = now;
+ final String msg = "Queue [" + mQueueName + "] waiting for " + conditionName
+ + " condition; state is " + describeStateLocked();
+ Slog.v(TAG, msg);
+ if (pw != null) {
+ pw.println(msg);
+ pw.flush();
+ }
+ }
+
+ // Push through any deferrals to try meeting our condition
+ cancelDeferrals();
+ SystemClock.sleep(100);
+ }
}
// Used by wait-for-broadcast-idle : fast-forward all current deferrals to
@@ -1799,11 +1823,9 @@ public class BroadcastQueueImpl extends BroadcastQueue {
}
}
- public String describeState() {
- synchronized (mService) {
- return mParallelBroadcasts.size() + " parallel; "
- + mDispatcher.describeStateLocked();
- }
+ public String describeStateLocked() {
+ return mParallelBroadcasts.size() + " parallel; "
+ + mDispatcher.describeStateLocked();
}
public void dumpDebug(ProtoOutputStream proto, long fieldId) {
@@ -1818,37 +1840,7 @@ public class BroadcastQueueImpl extends BroadcastQueue {
if (mPendingBroadcast != null) {
mPendingBroadcast.dumpDebug(proto, BroadcastQueueProto.PENDING_BROADCAST);
}
-
- int lastIndex = mHistoryNext;
- int ringIndex = lastIndex;
- do {
- // increasing index = more recent entry, and we want to print the most
- // recent first and work backwards, so we roll through the ring backwards.
- ringIndex = ringAdvance(ringIndex, -1, MAX_BROADCAST_HISTORY);
- BroadcastRecord r = mBroadcastHistory[ringIndex];
- if (r != null) {
- r.dumpDebug(proto, BroadcastQueueProto.HISTORICAL_BROADCASTS);
- }
- } while (ringIndex != lastIndex);
-
- lastIndex = ringIndex = mSummaryHistoryNext;
- do {
- ringIndex = ringAdvance(ringIndex, -1, MAX_BROADCAST_SUMMARY_HISTORY);
- Intent intent = mBroadcastSummaryHistory[ringIndex];
- if (intent == null) {
- continue;
- }
- long summaryToken = proto.start(BroadcastQueueProto.HISTORICAL_BROADCASTS_SUMMARY);
- intent.dumpDebug(proto, BroadcastQueueProto.BroadcastSummary.INTENT,
- false, true, true, false);
- proto.write(BroadcastQueueProto.BroadcastSummary.ENQUEUE_CLOCK_TIME_MS,
- mSummaryHistoryEnqueueTime[ringIndex]);
- proto.write(BroadcastQueueProto.BroadcastSummary.DISPATCH_CLOCK_TIME_MS,
- mSummaryHistoryDispatchTime[ringIndex]);
- proto.write(BroadcastQueueProto.BroadcastSummary.FINISH_CLOCK_TIME_MS,
- mSummaryHistoryFinishTime[ringIndex]);
- proto.end(summaryToken);
- } while (ringIndex != lastIndex);
+ mHistory.dumpDebug(proto);
proto.end(token);
}
@@ -1889,114 +1881,8 @@ public class BroadcastQueueImpl extends BroadcastQueue {
needSep = true;
}
}
-
mConstants.dump(pw);
-
- int i;
- boolean printed = false;
-
- i = -1;
- int lastIndex = mHistoryNext;
- int ringIndex = lastIndex;
- do {
- // increasing index = more recent entry, and we want to print the most
- // recent first and work backwards, so we roll through the ring backwards.
- ringIndex = ringAdvance(ringIndex, -1, MAX_BROADCAST_HISTORY);
- BroadcastRecord r = mBroadcastHistory[ringIndex];
- if (r == null) {
- continue;
- }
-
- i++; // genuine record of some sort even if we're filtering it out
- if (dumpPackage != null && !dumpPackage.equals(r.callerPackage)) {
- continue;
- }
- if (!printed) {
- if (needSep) {
- pw.println();
- }
- needSep = true;
- pw.println(" Historical broadcasts [" + mQueueName + "]:");
- printed = true;
- }
- if (dumpAll) {
- pw.print(" Historical Broadcast " + mQueueName + " #");
- pw.print(i); pw.println(":");
- r.dump(pw, " ", sdf);
- } else {
- pw.print(" #"); pw.print(i); pw.print(": "); pw.println(r);
- pw.print(" ");
- pw.println(r.intent.toShortString(false, true, true, false));
- if (r.targetComp != null && r.targetComp != r.intent.getComponent()) {
- pw.print(" targetComp: "); pw.println(r.targetComp.toShortString());
- }
- Bundle bundle = r.intent.getExtras();
- if (bundle != null) {
- pw.print(" extras: "); pw.println(bundle.toString());
- }
- }
- } while (ringIndex != lastIndex);
-
- if (dumpPackage == null) {
- lastIndex = ringIndex = mSummaryHistoryNext;
- if (dumpAll) {
- printed = false;
- i = -1;
- } else {
- // roll over the 'i' full dumps that have already been issued
- for (int j = i;
- j > 0 && ringIndex != lastIndex;) {
- ringIndex = ringAdvance(ringIndex, -1, MAX_BROADCAST_SUMMARY_HISTORY);
- BroadcastRecord r = mBroadcastHistory[ringIndex];
- if (r == null) {
- continue;
- }
- j--;
- }
- }
- // done skipping; dump the remainder of the ring. 'i' is still the ordinal within
- // the overall broadcast history.
- do {
- ringIndex = ringAdvance(ringIndex, -1, MAX_BROADCAST_SUMMARY_HISTORY);
- Intent intent = mBroadcastSummaryHistory[ringIndex];
- if (intent == null) {
- continue;
- }
- if (!printed) {
- if (needSep) {
- pw.println();
- }
- needSep = true;
- pw.println(" Historical broadcasts summary [" + mQueueName + "]:");
- printed = true;
- }
- if (!dumpAll && i >= 50) {
- pw.println(" ...");
- break;
- }
- i++;
- pw.print(" #"); pw.print(i); pw.print(": ");
- pw.println(intent.toShortString(false, true, true, false));
- pw.print(" ");
- TimeUtils.formatDuration(mSummaryHistoryDispatchTime[ringIndex]
- - mSummaryHistoryEnqueueTime[ringIndex], pw);
- pw.print(" dispatch ");
- TimeUtils.formatDuration(mSummaryHistoryFinishTime[ringIndex]
- - mSummaryHistoryDispatchTime[ringIndex], pw);
- pw.println(" finish");
- pw.print(" enq=");
- pw.print(sdf.format(new Date(mSummaryHistoryEnqueueTime[ringIndex])));
- pw.print(" disp=");
- pw.print(sdf.format(new Date(mSummaryHistoryDispatchTime[ringIndex])));
- pw.print(" fin=");
- pw.println(sdf.format(new Date(mSummaryHistoryFinishTime[ringIndex])));
- Bundle bundle = intent.getExtras();
- if (bundle != null) {
- pw.print(" extras: "); pw.println(bundle.toString());
- }
- } while (ringIndex != lastIndex);
- }
-
+ needSep = mHistory.dumpLocked(pw, dumpPackage, mQueueName, sdf, dumpAll, needSep);
return needSep;
}
}
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index 18fbfdeb832c..817831cb003b 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -103,7 +103,6 @@ final class BroadcastRecord extends Binder {
Bundle resultExtras; // current result extra data values.
boolean resultAbort; // current result abortBroadcast value.
int nextReceiver; // next receiver to be executed.
- IBinder receiver; // who is currently running, null if none.
int state;
int anrCount; // has this broadcast record hit any ANRs?
int manifestCount; // number of manifest receivers dispatched.
@@ -133,15 +132,10 @@ final class BroadcastRecord extends Binder {
static final int DELIVERY_SKIPPED = 2;
static final int DELIVERY_TIMEOUT = 3;
- // The following are set when we are calling a receiver (one that
- // was found in our list of registered receivers).
- BroadcastFilter curFilter;
-
- // The following are set only when we are launching a receiver (one
- // that was found by querying the package manager).
ProcessRecord curApp; // hosting application of current receiver.
ComponentName curComponent; // the receiver class that is currently running.
- ActivityInfo curReceiver; // info about the receiver that is currently running.
+ ActivityInfo curReceiver; // the manifest receiver that is currently running.
+ BroadcastFilter curFilter; // the registered receiver currently running.
Bundle curFilteredExtras; // the bundle that has been filtered by the package visibility rules
boolean mIsReceiverAppRunning; // Was the receiver's app already running.
@@ -217,9 +211,8 @@ final class BroadcastRecord extends Binder {
pw.print(" sticky="); pw.print(sticky);
pw.print(" initialSticky="); pw.println(initialSticky);
}
- if (nextReceiver != 0 || receiver != null) {
+ if (nextReceiver != 0) {
pw.print(prefix); pw.print("nextReceiver="); pw.print(nextReceiver);
- pw.print(" receiver="); pw.println(receiver);
}
if (curFilter != null) {
pw.print(prefix); pw.print("curFilter="); pw.println(curFilter);
@@ -368,7 +361,6 @@ final class BroadcastRecord extends Binder {
resultExtras = from.resultExtras;
resultAbort = from.resultAbort;
nextReceiver = from.nextReceiver;
- receiver = from.receiver;
state = from.state;
anrCount = from.anrCount;
manifestCount = from.manifestCount;
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 12aa66b84d85..80dd2669a9a9 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -305,7 +305,7 @@ public class OomAdjuster {
*/
private final Handler mProcessGroupHandler;
- private final ArraySet<BroadcastQueue> mTmpBroadcastQueue = new ArraySet();
+ private final int[] mTmpSchedGroup = new int[1];
private final ActivityManagerService mService;
private final ProcessList mProcessList;
@@ -1677,14 +1677,13 @@ public class OomAdjuster {
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making instrumentation: " + app);
}
- } else if (state.getCachedIsReceivingBroadcast(mTmpBroadcastQueue)) {
+ } else if (state.getCachedIsReceivingBroadcast(mTmpSchedGroup)) {
// An app that is currently receiving a broadcast also
// counts as being in the foreground for OOM killer purposes.
// It's placed in a sched group based on the nature of the
// broadcast as reflected by which queue it's active in.
adj = ProcessList.FOREGROUND_APP_ADJ;
- schedGroup = (mTmpBroadcastQueue.contains(mService.mFgBroadcastQueue))
- ? ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;
+ schedGroup = mTmpSchedGroup[0];
state.setAdjType("broadcast");
procState = ActivityManager.PROCESS_STATE_RECEIVER;
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 90719a3f83ea..affb084708eb 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -276,6 +276,8 @@ public final class ProcessList {
// Memory pages are 4K.
static final int PAGE_SIZE = 4 * 1024;
+ // Activity manager's version of an undefined schedule group
+ static final int SCHED_GROUP_UNDEFINED = Integer.MIN_VALUE;
// Activity manager's version of Process.THREAD_GROUP_BACKGROUND
static final int SCHED_GROUP_BACKGROUND = 0;
// Activity manager's version of Process.THREAD_GROUP_RESTRICTED
@@ -3642,7 +3644,14 @@ public final class ProcessList {
if (thread == null) {
return null;
}
- final IBinder threadBinder = thread.asBinder();
+ return getLRURecordForAppLOSP(thread.asBinder());
+ }
+
+ @GuardedBy(anyOf = {"mService", "mProcLock"})
+ ProcessRecord getLRURecordForAppLOSP(IBinder threadBinder) {
+ if (threadBinder == null) {
+ return null;
+ }
// Find the application record.
for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
final ProcessRecord rec = mLruProcesses.get(i);
diff --git a/services/core/java/com/android/server/am/ProcessStateRecord.java b/services/core/java/com/android/server/am/ProcessStateRecord.java
index eb1fd3aa49be..ef137787905f 100644
--- a/services/core/java/com/android/server/am/ProcessStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessStateRecord.java
@@ -30,7 +30,6 @@ import android.annotation.ElapsedRealtimeLong;
import android.app.ActivityManager;
import android.content.ComponentName;
import android.os.SystemClock;
-import android.util.ArraySet;
import android.util.Slog;
import android.util.TimeUtils;
@@ -1071,14 +1070,12 @@ final class ProcessStateRecord {
}
@GuardedBy("mService")
- boolean getCachedIsReceivingBroadcast(ArraySet<BroadcastQueue> tmpQueue) {
+ boolean getCachedIsReceivingBroadcast(int[] outSchedGroup) {
if (mCachedIsReceivingBroadcast == VALUE_INVALID) {
- tmpQueue.clear();
- mCachedIsReceivingBroadcast = mService.isReceivingBroadcastLocked(mApp, tmpQueue)
+ mCachedIsReceivingBroadcast = mService.isReceivingBroadcastLocked(mApp, outSchedGroup)
? VALUE_TRUE : VALUE_FALSE;
if (mCachedIsReceivingBroadcast == VALUE_TRUE) {
- mCachedSchedGroup = tmpQueue.contains(mService.mFgBroadcastQueue)
- ? ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;
+ mCachedSchedGroup = outSchedGroup[0];
mApp.mProfile.addHostingComponentType(HOSTING_COMPONENT_TYPE_BROADCAST_RECEIVER);
} else {
mApp.mProfile.clearHostingComponentType(HOSTING_COMPONENT_TYPE_BROADCAST_RECEIVER);
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
index c00c707b2c66..9bdc93e11b6a 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
@@ -168,10 +168,15 @@ public class BroadcastQueueTest {
return false;
}
};
+ final BroadcastHistory emptyHistory = new BroadcastHistory() {
+ public void addBroadcastToHistoryLocked(BroadcastRecord original) {
+ }
+ };
if (mImpl == Impl.DEFAULT) {
mQueue = new BroadcastQueueImpl(mAms, mHandlerThread.getThreadHandler(), TAG,
- constants, emptySkipPolicy, false);
+ constants, emptySkipPolicy, emptyHistory, false,
+ ProcessList.SCHED_GROUP_DEFAULT);
} else {
throw new UnsupportedOperationException();
}
@@ -225,7 +230,7 @@ public class BroadcastQueueTest {
Log.v(TAG, "Intercepting scheduleReceiver() for "
+ Arrays.toString(invocation.getArguments()));
mHandlerThread.getThreadHandler().post(() -> {
- mQueue.finishReceiverLocked(threadBinder, Activity.RESULT_OK,
+ mQueue.finishReceiverLocked(r, Activity.RESULT_OK,
null, null, false, false);
});
return null;
@@ -236,7 +241,7 @@ public class BroadcastQueueTest {
Log.v(TAG, "Intercepting scheduleRegisteredReceiver() for "
+ Arrays.toString(invocation.getArguments()));
mHandlerThread.getThreadHandler().post(() -> {
- mQueue.finishReceiverLocked(receiverBinder, Activity.RESULT_OK, null, null,
+ mQueue.finishReceiverLocked(r, Activity.RESULT_OK, null, null,
false, false);
});
return null;
@@ -298,11 +303,7 @@ public class BroadcastQueueTest {
}
private void waitForIdle() throws Exception {
- for (int i = 0; i < 100; i++) {
- if (mQueue.isIdle()) break;
- SystemClock.sleep(100);
- }
- assertTrue(mQueue.isIdle());
+ mQueue.waitForIdle(null);
}
private void verifyScheduleReceiver(ProcessRecord app, Intent intent) throws Exception {
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index 598c6b0d9ab5..1c345484bd41 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -317,11 +317,11 @@ public class MockingOomAdjusterTests {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
doReturn(true).when(sService).isReceivingBroadcastLocked(any(ProcessRecord.class),
- any(ArraySet.class));
+ any(int[].class));
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
sService.mOomAdjuster.updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_NONE);
doReturn(false).when(sService).isReceivingBroadcastLocked(any(ProcessRecord.class),
- any(ArraySet.class));
+ any(int[].class));
assertProcStates(app, PROCESS_STATE_RECEIVER, FOREGROUND_APP_ADJ, SCHED_GROUP_BACKGROUND);
}