summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/ActivityManager.java32
-rw-r--r--core/java/android/app/IActivityManager.aidl8
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java19
-rw-r--r--services/core/java/com/android/server/am/BroadcastProcessQueue.java28
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueue.java10
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueueModernImpl.java28
-rw-r--r--services/core/java/com/android/server/am/ProcessRecord.java5
-rw-r--r--services/core/java/com/android/server/am/TEST_MAPPING9
8 files changed, 130 insertions, 9 deletions
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 83963fd2141d..2d6eaf1d33eb 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -5305,6 +5305,38 @@ public class ActivityManager {
}
/**
+ * Delays delivering broadcasts to the specified package.
+ *
+ * <p> When {@code delayedDurationMs} is {@code 0}, it will clears any previously
+ * set forced delays.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.DUMP)
+ public void forceDelayBroadcastDelivery(@NonNull String targetPackage,
+ @IntRange(from = 0) long delayedDurationMs) {
+ try {
+ getService().forceDelayBroadcastDelivery(targetPackage, delayedDurationMs);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Checks if the "modern" broadcast queue is enabled.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.DUMP)
+ public boolean isModernBroadcastQueueEnabled() {
+ try {
+ return getService().isModernBroadcastQueueEnabled();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* @return The reason code of whether or not the given UID should be exempted from background
* restrictions here.
*
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 040111c78531..938f1f66a7d2 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -771,6 +771,14 @@ interface IActivityManager {
/** Blocks until all broadcast queues become idle. */
void waitForBroadcastIdle();
+ /** Delays delivering broadcasts to the specified package. */
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.DUMP)")
+ void forceDelayBroadcastDelivery(in String targetPackage, long delayedDurationMs);
+
+ /** Checks if the modern broadcast queue is enabled. */
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.DUMP)")
+ boolean isModernBroadcastQueueEnabled();
+
/**
* @return The reason code of whether or not the given UID should be exempted from background
* restrictions here.
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 699a622efe55..091782a3f838 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -18333,6 +18333,25 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@Override
+ public void forceDelayBroadcastDelivery(@NonNull String targetPackage,
+ long delayedDurationMs) {
+ Objects.requireNonNull(targetPackage);
+ Preconditions.checkArgumentNonnegative(delayedDurationMs);
+ Preconditions.checkState(mEnableModernQueue, "Not valid in legacy queue");
+ enforceCallingPermission(permission.DUMP, "forceDelayBroadcastDelivery()");
+
+ for (BroadcastQueue queue : mBroadcastQueues) {
+ queue.forceDelayBroadcastDelivery(targetPackage, delayedDurationMs);
+ }
+ }
+
+ @Override
+ public boolean isModernBroadcastQueueEnabled() {
+ enforceCallingPermission(permission.DUMP, "isModernBroadcastQueueEnabled()");
+ return mEnableModernQueue;
+ }
+
+ @Override
@ReasonCode
public int getBackgroundRestrictionExemptionReason(int uid) {
enforceCallingPermission(android.Manifest.permission.DEVICE_POWER,
diff --git a/services/core/java/com/android/server/am/BroadcastProcessQueue.java b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
index 15d2fa334dcf..ec055fcb50ec 100644
--- a/services/core/java/com/android/server/am/BroadcastProcessQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
@@ -183,6 +183,11 @@ class BroadcastProcessQueue {
private String mCachedToString;
private String mCachedToShortString;
+ /**
+ * The duration by which any broadcasts to this process need to be delayed
+ */
+ private long mForcedDelayedDurationMs;
+
public BroadcastProcessQueue(@NonNull BroadcastConstants constants,
@NonNull String processName, int uid) {
this.constants = Objects.requireNonNull(constants);
@@ -275,7 +280,7 @@ class BroadcastProcessQueue {
*/
@FunctionalInterface
public interface BroadcastPredicate {
- public boolean test(@NonNull BroadcastRecord r, int index);
+ boolean test(@NonNull BroadcastRecord r, int index);
}
/**
@@ -284,7 +289,7 @@ class BroadcastProcessQueue {
*/
@FunctionalInterface
public interface BroadcastConsumer {
- public void accept(@NonNull BroadcastRecord r, int index);
+ void accept(@NonNull BroadcastRecord r, int index);
}
/**
@@ -418,6 +423,13 @@ class BroadcastProcessQueue {
}
/**
+ * Get package name of the first application loaded into this process.
+ */
+ public String getPackageName() {
+ return app.getApplicationInfo().packageName;
+ }
+
+ /**
* Set the currently active broadcast to the next pending broadcast.
*/
public void makeActiveNextPending() {
@@ -555,6 +567,10 @@ class BroadcastProcessQueue {
return mActive != null;
}
+ void forceDelayBroadcastDelivery(long delayedDurationMs) {
+ mForcedDelayedDurationMs = delayedDurationMs;
+ }
+
/**
* Will thrown an exception if there are no pending broadcasts; relies on
* {@link #isEmpty()} being false.
@@ -729,6 +745,7 @@ class BroadcastProcessQueue {
static final int REASON_BLOCKED = 4;
static final int REASON_INSTRUMENTED = 5;
static final int REASON_PERSISTENT = 6;
+ static final int REASON_FORCE_DELAYED = 7;
static final int REASON_CONTAINS_FOREGROUND = 10;
static final int REASON_CONTAINS_ORDERED = 11;
static final int REASON_CONTAINS_ALARM = 12;
@@ -746,6 +763,7 @@ class BroadcastProcessQueue {
REASON_BLOCKED,
REASON_INSTRUMENTED,
REASON_PERSISTENT,
+ REASON_FORCE_DELAYED,
REASON_CONTAINS_FOREGROUND,
REASON_CONTAINS_ORDERED,
REASON_CONTAINS_ALARM,
@@ -767,6 +785,7 @@ class BroadcastProcessQueue {
case REASON_BLOCKED: return "BLOCKED";
case REASON_INSTRUMENTED: return "INSTRUMENTED";
case REASON_PERSISTENT: return "PERSISTENT";
+ case REASON_FORCE_DELAYED: return "FORCE_DELAYED";
case REASON_CONTAINS_FOREGROUND: return "CONTAINS_FOREGROUND";
case REASON_CONTAINS_ORDERED: return "CONTAINS_ORDERED";
case REASON_CONTAINS_ALARM: return "CONTAINS_ALARM";
@@ -809,7 +828,10 @@ class BroadcastProcessQueue {
return;
}
- if (mCountForeground > 0) {
+ if (mForcedDelayedDurationMs > 0) {
+ mRunnableAt = runnableAt + mForcedDelayedDurationMs;
+ mRunnableAtReason = REASON_FORCE_DELAYED;
+ } else if (mCountForeground > 0) {
mRunnableAt = runnableAt + constants.DELAY_URGENT_MILLIS;
mRunnableAtReason = REASON_CONTAINS_FOREGROUND;
} else if (mCountInteractive > 0) {
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 153ad1ec1b52..75e93366bce4 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -233,6 +233,16 @@ public abstract class BroadcastQueue {
public abstract void waitForBarrier(@Nullable PrintWriter pw);
/**
+ * Delays delivering broadcasts to the specified package.
+ *
+ * <p> Note that this is only valid for modern queue.
+ */
+ public void forceDelayBroadcastDelivery(@NonNull String targetPackage,
+ long delayedDurationMs) {
+ // No default implementation.
+ }
+
+ /**
* Brief summary of internal state, useful for debugging purposes.
*/
@GuardedBy("mService")
diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
index 6ba1b1fd13c5..affa0cd15ea2 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
@@ -1225,12 +1225,16 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
return didSomething;
}
- private void forEachQueue(@NonNull Consumer<BroadcastProcessQueue> consumer) {
- for (int i = 0; i < mProcessQueues.size(); ++i) {
+ private void forEachMatchingQueue(
+ @NonNull Predicate<BroadcastProcessQueue> queuePredicate,
+ @NonNull Consumer<BroadcastProcessQueue> queueConsumer) {
+ for (int i = 0; i < mProcessQueues.size(); i++) {
BroadcastProcessQueue leaf = mProcessQueues.valueAt(i);
while (leaf != null) {
- consumer.accept(leaf);
- updateRunnableList(leaf);
+ if (queuePredicate.test(leaf)) {
+ queueConsumer.accept(leaf);
+ updateRunnableList(leaf);
+ }
leaf = leaf.processNameNext;
}
}
@@ -1294,7 +1298,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
final CountDownLatch latch = new CountDownLatch(1);
synchronized (mService) {
mWaitingFor.add(Pair.create(condition, latch));
- forEachQueue(q -> q.setPrioritizeEarliest(true));
+ forEachMatchingQueue(QUEUE_PREDICATE_ANY,
+ (q) -> q.setPrioritizeEarliest(true));
}
enqueueUpdateRunningList();
try {
@@ -1304,13 +1309,24 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
} finally {
synchronized (mService) {
if (mWaitingFor.isEmpty()) {
- forEachQueue(q -> q.setPrioritizeEarliest(false));
+ forEachMatchingQueue(QUEUE_PREDICATE_ANY,
+ (q) -> q.setPrioritizeEarliest(false));
}
}
}
}
@Override
+ public void forceDelayBroadcastDelivery(@NonNull String targetPackage,
+ long delayedDurationMs) {
+ synchronized (mService) {
+ forEachMatchingQueue(
+ (q) -> targetPackage.equals(q.getPackageName()),
+ (q) -> q.forceDelayBroadcastDelivery(delayedDurationMs));
+ }
+ }
+
+ @Override
public String describeStateLocked() {
return getRunningSize() + " running";
}
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 4706c26889de..33d7f9d04185 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -1016,6 +1016,11 @@ class ProcessRecord implements WindowProcessListener {
return mWindowProcessController.hasRecentTasks();
}
+ @GuardedBy("mService")
+ public ApplicationInfo getApplicationInfo() {
+ return info;
+ }
+
@GuardedBy({"mService", "mProcLock"})
boolean onCleanupApplicationRecordLSP(ProcessStatsService processStats, boolean allowRestart,
boolean unlinkDeath) {
diff --git a/services/core/java/com/android/server/am/TEST_MAPPING b/services/core/java/com/android/server/am/TEST_MAPPING
index 2a693634087b..4e1d1ca0ac66 100644
--- a/services/core/java/com/android/server/am/TEST_MAPPING
+++ b/services/core/java/com/android/server/am/TEST_MAPPING
@@ -97,6 +97,15 @@
{ "include-filter": "com.android.server.am.BroadcastQueueTest" },
{ "include-filter": "com.android.server.am.BroadcastQueueModernImplTest" }
]
+ },
+ {
+ "file_patterns": ["Broadcast"],
+ "name": "CtsBroadcastTestCases",
+ "options": [
+ { "exclude-annotation": "androidx.test.filters.LargeTest" },
+ { "exclude-annotation": "androidx.test.filters.FlakyTest" },
+ { "exclude-annotation": "org.junit.Ignore" }
+ ]
}
],
"presubmit-large": [