Merge "Schedule external stats sync on battery level change with a delay" into pi-dev
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 318265b..4d7c202 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -10776,6 +10776,7 @@
* read_binary_cpu_time (boolean)
* proc_state_cpu_times_read_delay_ms (long)
* external_stats_collection_rate_limit_ms (long)
+ * battery_level_collection_delay_ms (long)
* </pre>
*
* <p>
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index a4680ca..be83498 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -585,6 +585,7 @@
boolean onBatteryScreenOff);
Future<?> scheduleCpuSyncDueToWakelockChange(long delayMillis);
void cancelCpuSyncDueToWakelockChange();
+ Future<?> scheduleSyncDueToBatteryLevelChange(long delayMillis);
}
public Handler mHandler;
@@ -12614,7 +12615,8 @@
// TODO(adamlesinski): Schedule the creation of a HistoryStepDetails record
// which will pull external stats.
- scheduleSyncExternalStatsLocked("battery-level", ExternalStatsSync.UPDATE_ALL);
+ mExternalSync.scheduleSyncDueToBatteryLevelChange(
+ mConstants.BATTERY_LEVEL_COLLECTION_DELAY_MS);
}
if (mHistoryCur.batteryStatus != status) {
mHistoryCur.batteryStatus = (byte)status;
@@ -13270,6 +13272,8 @@
= "uid_remove_delay_ms";
public static final String KEY_EXTERNAL_STATS_COLLECTION_RATE_LIMIT_MS
= "external_stats_collection_rate_limit_ms";
+ public static final String KEY_BATTERY_LEVEL_COLLECTION_DELAY_MS
+ = "battery_level_collection_delay_ms";
private static final boolean DEFAULT_TRACK_CPU_TIMES_BY_PROC_STATE = true;
private static final boolean DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME = true;
@@ -13277,6 +13281,7 @@
private static final long DEFAULT_KERNEL_UID_READERS_THROTTLE_TIME = 10_000;
private static final long DEFAULT_UID_REMOVE_DELAY_MS = 5L * 60L * 1000L;
private static final long DEFAULT_EXTERNAL_STATS_COLLECTION_RATE_LIMIT_MS = 600_000;
+ private static final long DEFAULT_BATTERY_LEVEL_COLLECTION_DELAY_MS = 300_000;
public boolean TRACK_CPU_TIMES_BY_PROC_STATE = DEFAULT_TRACK_CPU_TIMES_BY_PROC_STATE;
public boolean TRACK_CPU_ACTIVE_CLUSTER_TIME = DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME;
@@ -13285,6 +13290,8 @@
public long UID_REMOVE_DELAY_MS = DEFAULT_UID_REMOVE_DELAY_MS;
public long EXTERNAL_STATS_COLLECTION_RATE_LIMIT_MS
= DEFAULT_EXTERNAL_STATS_COLLECTION_RATE_LIMIT_MS;
+ public long BATTERY_LEVEL_COLLECTION_DELAY_MS
+ = DEFAULT_BATTERY_LEVEL_COLLECTION_DELAY_MS;
private ContentResolver mResolver;
private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -13333,6 +13340,9 @@
EXTERNAL_STATS_COLLECTION_RATE_LIMIT_MS = mParser.getLong(
KEY_EXTERNAL_STATS_COLLECTION_RATE_LIMIT_MS,
DEFAULT_EXTERNAL_STATS_COLLECTION_RATE_LIMIT_MS);
+ BATTERY_LEVEL_COLLECTION_DELAY_MS = mParser.getLong(
+ KEY_BATTERY_LEVEL_COLLECTION_DELAY_MS,
+ DEFAULT_BATTERY_LEVEL_COLLECTION_DELAY_MS);
}
}
@@ -13384,6 +13394,8 @@
pw.println(KERNEL_UID_READERS_THROTTLE_TIME);
pw.print(KEY_EXTERNAL_STATS_COLLECTION_RATE_LIMIT_MS); pw.print("=");
pw.println(EXTERNAL_STATS_COLLECTION_RATE_LIMIT_MS);
+ pw.print(KEY_BATTERY_LEVEL_COLLECTION_DELAY_MS); pw.print("=");
+ pw.println(BATTERY_LEVEL_COLLECTION_DELAY_MS);
}
}
diff --git a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
index 36e54ad..b68f6b1 100644
--- a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
+++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
@@ -190,6 +190,11 @@
@Override
public void cancelCpuSyncDueToWakelockChange() {
}
+
+ @Override
+ public Future<?> scheduleSyncDueToBatteryLevelChange(long delayMillis) {
+ return null;
+ }
}
}
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index 87194bc..49fa902 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -103,6 +103,9 @@
@GuardedBy("this")
private Future<?> mWakelockChangesUpdate;
+ @GuardedBy("this")
+ private Future<?> mBatteryLevelSync;
+
private final Object mWorkerLock = new Object();
@GuardedBy("mWorkerLock")
@@ -197,35 +200,75 @@
@Override
public Future<?> scheduleCpuSyncDueToWakelockChange(long delayMillis) {
- if (mExecutorService.isShutdown()) {
- return CompletableFuture.failedFuture(new IllegalStateException("worker shutdown"));
+ synchronized (BatteryExternalStatsWorker.this) {
+ mWakelockChangesUpdate = scheduleDelayedSyncLocked(mWakelockChangesUpdate,
+ () -> {
+ scheduleSync("wakelock-change", UPDATE_CPU);
+ scheduleRunnable(() -> mStats.postBatteryNeedsCpuUpdateMsg());
+ },
+ delayMillis);
+ return mWakelockChangesUpdate;
}
-
- if (mWakelockChangesUpdate != null) {
- // If there's already a scheduled task, leave it as is if we're trying to re-schedule
- // it again with a delay, otherwise cancel and re-schedule it.
- if (delayMillis == 0) {
- mWakelockChangesUpdate.cancel(false);
- } else {
- return mWakelockChangesUpdate;
- }
- }
-
- mWakelockChangesUpdate = mExecutorService.schedule(() -> {
- scheduleSync("wakelock-change", UPDATE_CPU);
- scheduleRunnable(() -> mStats.postBatteryNeedsCpuUpdateMsg());
- mWakelockChangesUpdate = null;
- }, delayMillis, TimeUnit.MILLISECONDS);
- return mWakelockChangesUpdate;
}
@Override
public void cancelCpuSyncDueToWakelockChange() {
- if (mWakelockChangesUpdate != null) {
- mWakelockChangesUpdate.cancel(false);
+ synchronized (BatteryExternalStatsWorker.this) {
+ if (mWakelockChangesUpdate != null) {
+ mWakelockChangesUpdate.cancel(false);
+ mWakelockChangesUpdate = null;
+ }
}
}
+ @Override
+ public Future<?> scheduleSyncDueToBatteryLevelChange(long delayMillis) {
+ synchronized (BatteryExternalStatsWorker.this) {
+ mBatteryLevelSync = scheduleDelayedSyncLocked(mBatteryLevelSync,
+ () -> scheduleSync("battery-level", UPDATE_ALL),
+ delayMillis);
+ return mBatteryLevelSync;
+ }
+ }
+
+ @GuardedBy("this")
+ private void cancelSyncDueToBatteryLevelChangeLocked() {
+ if (mBatteryLevelSync != null) {
+ mBatteryLevelSync.cancel(false);
+ mBatteryLevelSync = null;
+ }
+ }
+
+ /**
+ * Schedule a sync {@param syncRunnable} with a delay. If there's already a scheduled sync, a
+ * new sync won't be scheduled unless it is being scheduled to run immediately (delayMillis=0).
+ *
+ * @param lastScheduledSync the task which was earlier scheduled to run
+ * @param syncRunnable the task that needs to be scheduled to run
+ * @param delayMillis time after which {@param syncRunnable} needs to be scheduled
+ * @return scheduled {@link Future} which can be used to check if task is completed or to
+ * cancel it if needed
+ */
+ @GuardedBy("this")
+ private Future<?> scheduleDelayedSyncLocked(Future<?> lastScheduledSync, Runnable syncRunnable,
+ long delayMillis) {
+ if (mExecutorService.isShutdown()) {
+ return CompletableFuture.failedFuture(new IllegalStateException("worker shutdown"));
+ }
+
+ if (lastScheduledSync != null) {
+ // If there's already a scheduled task, leave it as is if we're trying to
+ // re-schedule it again with a delay, otherwise cancel and re-schedule it.
+ if (delayMillis == 0) {
+ lastScheduledSync.cancel(false);
+ } else {
+ return lastScheduledSync;
+ }
+ }
+
+ return mExecutorService.schedule(syncRunnable, delayMillis, TimeUnit.MILLISECONDS);
+ }
+
public synchronized Future<?> scheduleWrite() {
if (mExecutorService.isShutdown()) {
return CompletableFuture.failedFuture(new IllegalStateException("worker shutdown"));
@@ -294,6 +337,12 @@
mUidsToRemove.clear();
mCurrentFuture = null;
mUseLatestStates = true;
+ if ((updateFlags & UPDATE_ALL) != 0) {
+ cancelSyncDueToBatteryLevelChangeLocked();
+ }
+ if ((updateFlags & UPDATE_CPU) != 0) {
+ cancelCpuSyncDueToWakelockChange();
+ }
}
try {