Add a global setting to turn on/off the proc state cpu times tracking.
Bug: 66953194
Test: atest core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
Test: atest hostsidetests/incident/src/com/android/server/cts/BatteryStatsValidationTest.java
Test: atest core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
Change-Id: Id26476ad77c95994f358d8bd59b6c2e6513c4c54
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 009fc39..36ad625 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9782,6 +9782,22 @@
public static final String TEXT_CLASSIFIER_CONSTANTS = "text_classifier_constants";
/**
+ * BatteryStats specific settings.
+ * This is encoded as a key=value list, separated by commas. Ex: "foo=1,bar=true"
+ *
+ * The following keys are supported:
+ * <pre>
+ * track_cpu_times_by_proc_state (boolean)
+ * </pre>
+ *
+ * <p>
+ * Type: string
+ * @hide
+ * see also com.android.internal.os.BatteryStatsImpl.Constants
+ */
+ public static final String BATTERY_STATS_CONSTANTS = "battery_stats_constants";
+
+ /**
* Whether or not App Standby feature is enabled. This controls throttling of apps
* based on usage patterns and predictions.
* Type: int (0 for false, 1 for true)
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 9015cbb..b8ff9e4 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -21,10 +21,13 @@
import android.app.ActivityManager;
import android.bluetooth.BluetoothActivityEnergyInfo;
import android.bluetooth.UidTraffic;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.database.ContentObserver;
import android.net.ConnectivityManager;
import android.net.NetworkStats;
+import android.net.Uri;
import android.net.wifi.WifiActivityEnergyInfo;
import android.net.wifi.WifiManager;
import android.os.BatteryManager;
@@ -46,6 +49,7 @@
import android.os.UserHandle;
import android.os.WorkSource;
import android.os.WorkSource.WorkChain;
+import android.provider.Settings;
import android.telephony.DataConnectionRealTimeInfo;
import android.telephony.ModemActivityInfo;
import android.telephony.ServiceState;
@@ -54,6 +58,7 @@
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.IntArray;
+import android.util.KeyValueListParser;
import android.util.Log;
import android.util.LogWriter;
import android.util.LongSparseArray;
@@ -292,9 +297,18 @@
public void updateProcStateCpuTimes(boolean onBattery, boolean onBatteryScreenOff) {
final SparseIntArray uidStates;
synchronized (BatteryStatsImpl.this) {
+ if (!mConstants.TRACK_CPU_TIMES_BY_PROC_STATE) {
+ return;
+ }
if(!initKernelSingleUidTimeReaderLocked()) {
return;
}
+ // If the KernelSingleUidTimeReader has stale cpu times, then we shouldn't try to
+ // compute deltas since it might result in mis-attributing cpu times to wrong states.
+ if (mKernelSingleUidTimeReader.hasStaleData()) {
+ mPendingUids.clear();
+ return;
+ }
if (mPendingUids.size() == 0) {
return;
@@ -355,12 +369,23 @@
*/
public void copyFromAllUidsCpuTimes(boolean onBattery, boolean onBatteryScreenOff) {
synchronized (BatteryStatsImpl.this) {
+ if (!mConstants.TRACK_CPU_TIMES_BY_PROC_STATE) {
+ return;
+ }
if(!initKernelSingleUidTimeReaderLocked()) {
return;
}
final SparseArray<long[]> allUidCpuFreqTimesMs =
mKernelUidCpuFreqTimeReader.getAllUidCpuFreqTimeMs();
+ // If the KernelSingleUidTimeReader has stale cpu times, then we shouldn't try to
+ // compute deltas since it might result in mis-attributing cpu times to wrong states.
+ if (mKernelSingleUidTimeReader.hasStaleData()) {
+ mKernelSingleUidTimeReader.setAllUidsCpuTimesMs(allUidCpuFreqTimesMs);
+ mKernelSingleUidTimeReader.markDataAsStale(false);
+ mPendingUids.clear();
+ return;
+ }
for (int i = allUidCpuFreqTimesMs.size() - 1; i >= 0; --i) {
final int uid = allUidCpuFreqTimesMs.keyAt(i);
final Uid u = getAvailableUidStatsLocked(mapUid(uid));
@@ -450,6 +475,7 @@
Future<?> scheduleCpuSyncDueToRemovedUid(int uid);
Future<?> scheduleReadProcStateCpuTimes(boolean onBattery, boolean onBatteryScreenOff);
Future<?> scheduleCopyFromAllUidsCpuTimes(boolean onBattery, boolean onBatteryScreenOff);
+ Future<?> scheduleCpuSyncDueToSettingChange();
}
public Handler mHandler;
@@ -812,6 +838,9 @@
@VisibleForTesting
protected PowerProfile mPowerProfile;
+ @GuardedBy("this")
+ private final Constants mConstants;
+
/*
* Holds a SamplingTimer associated with each Resource Power Manager state and voter,
* recording their times when on-battery (regardless of screen state).
@@ -900,6 +929,7 @@
mHandler = null;
mPlatformIdleStateCallback = null;
mUserInfoProvider = null;
+ mConstants = new Constants(mHandler);
clearHistoryLocked();
}
@@ -9411,7 +9441,7 @@
if (mProcessState != ActivityManager.PROCESS_STATE_NONEXISTENT) {
mProcessStateTimer[mProcessState].stopRunningLocked(elapsedRealtimeMs);
- if (mBsi.mPerProcStateCpuTimesAvailable) {
+ if (mBsi.trackPerProcStateCpuTimes()) {
if (mBsi.mPendingUids.size() == 0) {
mBsi.mExternalSync.scheduleReadProcStateCpuTimes(
mBsi.mOnBatteryTimeBase.isRunning(),
@@ -9765,6 +9795,7 @@
mCheckinFile = new AtomicFile(new File(systemDir, "batterystats-checkin.bin"));
mDailyFile = new AtomicFile(new File(systemDir, "batterystats-daily.xml"));
mHandler = new MyHandler(handler.getLooper());
+ mConstants = new Constants(mHandler);
mStartCount++;
mScreenOnTimer = new StopwatchTimer(mClocks, null, -1, null, mOnBatteryTimeBase);
mScreenDozeTimer = new StopwatchTimer(mClocks, null, -1, null, mOnBatteryTimeBase);
@@ -9860,6 +9891,7 @@
mDailyFile = null;
mHandler = null;
mExternalSync = null;
+ mConstants = new Constants(mHandler);
clearHistoryLocked();
readFromParcel(p);
mPlatformIdleStateCallback = null;
@@ -12613,6 +12645,78 @@
mShuttingDown = true;
}
+ public boolean trackPerProcStateCpuTimes() {
+ return mConstants.TRACK_CPU_TIMES_BY_PROC_STATE && mPerProcStateCpuTimesAvailable;
+ }
+
+ public void systemServicesReady(Context context) {
+ mConstants.startObserving(context.getContentResolver());
+ }
+
+ @VisibleForTesting
+ public final class Constants extends ContentObserver {
+ public static final String KEY_TRACK_CPU_TIMES_BY_PROC_STATE
+ = "track_cpu_times_by_proc_state";
+
+ private static final boolean DEFAULT_TRACK_CPU_TIMES_BY_PROC_STATE = true;
+
+ public boolean TRACK_CPU_TIMES_BY_PROC_STATE = DEFAULT_TRACK_CPU_TIMES_BY_PROC_STATE;
+
+ private ContentResolver mResolver;
+ private final KeyValueListParser mParser = new KeyValueListParser(',');
+
+ public Constants(Handler handler) {
+ super(handler);
+ }
+
+ public void startObserving(ContentResolver resolver) {
+ mResolver = resolver;
+ mResolver.registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.BATTERY_STATS_CONSTANTS),
+ false /* notifyForDescendants */, this);
+ updateConstants();
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ updateConstants();
+ }
+
+ private void updateConstants() {
+ synchronized (BatteryStatsImpl.this) {
+ try {
+ mParser.setString(Settings.Global.getString(mResolver,
+ Settings.Global.BATTERY_STATS_CONSTANTS));
+ } catch (IllegalArgumentException e) {
+ // Failed to parse the settings string, log this and move on
+ // with defaults.
+ Slog.e(TAG, "Bad batterystats settings", e);
+ }
+
+ updateTrackCpuTimesByProcStateLocked(TRACK_CPU_TIMES_BY_PROC_STATE,
+ mParser.getBoolean(KEY_TRACK_CPU_TIMES_BY_PROC_STATE,
+ DEFAULT_TRACK_CPU_TIMES_BY_PROC_STATE));
+ }
+ }
+
+ private void updateTrackCpuTimesByProcStateLocked(boolean wasEnabled, boolean isEnabled) {
+ TRACK_CPU_TIMES_BY_PROC_STATE = isEnabled;
+ if (isEnabled && !wasEnabled) {
+ mKernelSingleUidTimeReader.markDataAsStale(true);
+ mExternalSync.scheduleCpuSyncDueToSettingChange();
+ }
+ }
+
+ public void dumpLocked(PrintWriter pw) {
+ pw.print(KEY_TRACK_CPU_TIMES_BY_PROC_STATE); pw.print("=");
+ pw.println(TRACK_CPU_TIMES_BY_PROC_STATE);
+ }
+ }
+
+ public void dumpConstantsLocked(PrintWriter pw) {
+ mConstants.dumpLocked(pw);
+ }
+
Parcel mPendingWrite = null;
final ReentrantLock mWriteLock = new ReentrantLock();
diff --git a/core/java/com/android/internal/os/KernelSingleUidTimeReader.java b/core/java/com/android/internal/os/KernelSingleUidTimeReader.java
index ca635a4..ebeb24c4 100644
--- a/core/java/com/android/internal/os/KernelSingleUidTimeReader.java
+++ b/core/java/com/android/internal/os/KernelSingleUidTimeReader.java
@@ -46,12 +46,14 @@
private final int mCpuFreqsCount;
@GuardedBy("this")
- private final SparseArray<long[]> mLastUidCpuTimeMs = new SparseArray<>();
+ private SparseArray<long[]> mLastUidCpuTimeMs = new SparseArray<>();
@GuardedBy("this")
private int mReadErrorCounter;
@GuardedBy("this")
private boolean mSingleUidCpuTimesAvailable = true;
+ @GuardedBy("this")
+ private boolean mHasStaleData;
private final Injector mInjector;
@@ -166,6 +168,30 @@
return deltaTimesMs;
}
+ public void markDataAsStale(boolean hasStaleData) {
+ synchronized (this) {
+ mHasStaleData = hasStaleData;
+ }
+ }
+
+ public boolean hasStaleData() {
+ synchronized (this) {
+ return mHasStaleData;
+ }
+ }
+
+ public void setAllUidsCpuTimesMs(SparseArray<long[]> allUidsCpuTimesMs) {
+ synchronized (this) {
+ mLastUidCpuTimeMs.clear();
+ for (int i = allUidsCpuTimesMs.size() - 1; i >= 0; --i) {
+ final long[] cpuTimesMs = allUidsCpuTimesMs.valueAt(i);
+ if (cpuTimesMs != null) {
+ mLastUidCpuTimeMs.put(allUidsCpuTimesMs.keyAt(i), cpuTimesMs.clone());
+ }
+ }
+ }
+ }
+
public void removeUid(int uid) {
synchronized (this) {
mLastUidCpuTimeMs.delete(uid);
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index fc86500..91782e9 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -112,6 +112,7 @@
Settings.Global.BATTERY_DISCHARGE_DURATION_THRESHOLD,
Settings.Global.BATTERY_DISCHARGE_THRESHOLD,
Settings.Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS,
+ Settings.Global.BATTERY_STATS_CONSTANTS,
Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE,
Settings.Global.BLUETOOTH_A2DP_SINK_PRIORITY_PREFIX,
Settings.Global.BLUETOOTH_A2DP_SRC_PRIORITY_PREFIX,
diff --git a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
index e54fe7d..4d34721 100644
--- a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
@@ -25,6 +25,8 @@
import static android.os.BatteryStats.Uid.PROCESS_STATE_TOP_SLEEPING;
import static android.os.BatteryStats.Uid.UID_PROCESS_TYPES;
+import static com.android.internal.os.BatteryStatsImpl.Constants.KEY_TRACK_CPU_TIMES_BY_PROC_STATE;
+
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
@@ -48,15 +50,19 @@
import android.os.PowerManager;
import android.os.Process;
import android.os.SystemClock;
+import android.provider.Settings;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.LargeTest;
import android.support.test.runner.AndroidJUnit4;
import android.support.test.uiautomator.UiDevice;
+import android.text.TextUtils;
import android.util.DebugUtils;
import android.util.Log;
import org.junit.BeforeClass;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TestName;
import org.junit.runner.RunWith;
import java.util.Arrays;
@@ -86,6 +92,9 @@
private static final int START_SERVICE_TIMEOUT_MS = 2000;
private static final int START_ISOLATED_SERVICE_TIMEOUT_MS = 2000;
+ private static final int SETTING_UPDATE_TIMEOUT_MS = 2000;
+ private static final int SETTING_UPDATE_CHECK_INTERVAL_MS = 200;
+
private static final int GENERAL_TIMEOUT_MS = 4000;
private static final int GENERAL_INTERVAL_MS = 200;
@@ -97,6 +106,8 @@
private static boolean sCpuFreqTimesAvailable;
private static boolean sPerProcStateTimesAvailable;
+ @Rule public TestName testName = new TestName();
+
@BeforeClass
public static void setupOnce() throws Exception {
sContext = InstrumentationRegistry.getContext();
@@ -123,6 +134,9 @@
@Test
public void testCpuFreqTimes() throws Exception {
if (!sCpuFreqTimesAvailable) {
+ Log.w(TAG, "Skipping " + testName.getMethodName()
+ + "; freqTimesAvailable=" + sCpuFreqTimesAvailable
+ + ", procStateTimesAvailable=" + sPerProcStateTimesAvailable);
return;
}
@@ -148,6 +162,9 @@
@Test
public void testCpuFreqTimes_screenOff() throws Exception {
if (!sCpuFreqTimesAvailable) {
+ Log.w(TAG, "Skipping " + testName.getMethodName()
+ + "; freqTimesAvailable=" + sCpuFreqTimesAvailable
+ + ", procStateTimesAvailable=" + sPerProcStateTimesAvailable);
return;
}
@@ -179,6 +196,9 @@
@Test
public void testCpuFreqTimes_isolatedProcess() throws Exception {
if (!sCpuFreqTimesAvailable) {
+ Log.w(TAG, "Skipping " + testName.getMethodName()
+ + "; freqTimesAvailable=" + sCpuFreqTimesAvailable
+ + ", procStateTimesAvailable=" + sPerProcStateTimesAvailable);
return;
}
@@ -204,6 +224,9 @@
@Test
public void testCpuFreqTimes_stateTop() throws Exception {
if (!sCpuFreqTimesAvailable || !sPerProcStateTimesAvailable) {
+ Log.w(TAG, "Skipping " + testName.getMethodName()
+ + "; freqTimesAvailable=" + sCpuFreqTimesAvailable
+ + ", procStateTimesAvailable=" + sPerProcStateTimesAvailable);
return;
}
@@ -234,6 +257,9 @@
@Test
public void testIsolatedCpuFreqTimes_stateService() throws Exception {
if (!sCpuFreqTimesAvailable || !sPerProcStateTimesAvailable) {
+ Log.w(TAG, "Skipping " + testName.getMethodName()
+ + "; freqTimesAvailable=" + sCpuFreqTimesAvailable
+ + ", procStateTimesAvailable=" + sPerProcStateTimesAvailable);
return;
}
@@ -272,6 +298,9 @@
@Test
public void testCpuFreqTimes_stateTopSleeping() throws Exception {
if (!sCpuFreqTimesAvailable || !sPerProcStateTimesAvailable) {
+ Log.w(TAG, "Skipping " + testName.getMethodName()
+ + "; freqTimesAvailable=" + sCpuFreqTimesAvailable
+ + ", procStateTimesAvailable=" + sPerProcStateTimesAvailable);
return;
}
@@ -302,6 +331,9 @@
@Test
public void testCpuFreqTimes_stateFgService() throws Exception {
if (!sCpuFreqTimesAvailable || !sPerProcStateTimesAvailable) {
+ Log.w(TAG, "Skipping " + testName.getMethodName()
+ + "; freqTimesAvailable=" + sCpuFreqTimesAvailable
+ + ", procStateTimesAvailable=" + sPerProcStateTimesAvailable);
return;
}
@@ -332,6 +364,9 @@
@Test
public void testCpuFreqTimes_stateFg() throws Exception {
if (!sCpuFreqTimesAvailable || !sPerProcStateTimesAvailable) {
+ Log.w(TAG, "Skipping " + testName.getMethodName()
+ + "; freqTimesAvailable=" + sCpuFreqTimesAvailable
+ + ", procStateTimesAvailable=" + sPerProcStateTimesAvailable);
return;
}
@@ -362,6 +397,9 @@
@Test
public void testCpuFreqTimes_stateBg() throws Exception {
if (!sCpuFreqTimesAvailable || !sPerProcStateTimesAvailable) {
+ Log.w(TAG, "Skipping " + testName.getMethodName()
+ + "; freqTimesAvailable=" + sCpuFreqTimesAvailable
+ + ", procStateTimesAvailable=" + sPerProcStateTimesAvailable);
return;
}
@@ -392,6 +430,9 @@
@Test
public void testCpuFreqTimes_stateCached() throws Exception {
if (!sCpuFreqTimesAvailable || !sPerProcStateTimesAvailable) {
+ Log.w(TAG, "Skipping " + testName.getMethodName()
+ + "; freqTimesAvailable=" + sCpuFreqTimesAvailable
+ + ", procStateTimesAvailable=" + sPerProcStateTimesAvailable);
return;
}
@@ -419,6 +460,124 @@
batteryOffScreenOn();
}
+ @Test
+ public void testCpuFreqTimes_trackingDisabled() throws Exception {
+ if (!sCpuFreqTimesAvailable || !sPerProcStateTimesAvailable) {
+ Log.w(TAG, "Skipping " + testName.getMethodName()
+ + "; freqTimesAvailable=" + sCpuFreqTimesAvailable
+ + ", procStateTimesAvailable=" + sPerProcStateTimesAvailable);
+ return;
+ }
+
+ final String bstatsConstants = Settings.Global.getString(sContext.getContentResolver(),
+ Settings.Global.BATTERY_STATS_CONSTANTS);
+ try {
+ batteryOnScreenOn();
+ forceStop();
+ resetBatteryStats();
+ final long[] initialSnapshot = getAllCpuFreqTimes(sTestPkgUid);
+ assertNull("Initial snapshot should be null, initial="
+ + Arrays.toString(initialSnapshot), initialSnapshot);
+ assertNull("Initial top state snapshot should be null",
+ getAllCpuFreqTimes(sTestPkgUid, PROCESS_STATE_TOP));
+
+ doSomeWork(PROCESS_STATE_TOP);
+ forceStop();
+
+ final long[] cpuTimesMs = getAllCpuFreqTimes(sTestPkgUid, PROCESS_STATE_TOP);
+ final String msgCpuTimes = getAllCpuTimesMsg();
+ assertCpuTimesValid(cpuTimesMs);
+ long actualCpuTimeMs = 0;
+ for (int i = 0; i < cpuTimesMs.length / 2; ++i) {
+ actualCpuTimeMs += cpuTimesMs[i];
+ }
+ assertApproximateValue("Incorrect total cpu time, " + msgCpuTimes,
+ WORK_DURATION_MS, actualCpuTimeMs);
+
+ updateTrackPerProcStateCpuTimesSetting(bstatsConstants, false);
+
+ doSomeWork(PROCESS_STATE_TOP);
+ forceStop();
+
+ final long[] cpuTimesMs2 = getAllCpuFreqTimes(sTestPkgUid, PROCESS_STATE_TOP);
+ assertCpuTimesValid(cpuTimesMs2);
+ assertCpuTimesEqual(cpuTimesMs2, cpuTimesMs, 20,
+ "Unexpected cpu times with tracking off");
+
+ updateTrackPerProcStateCpuTimesSetting(bstatsConstants, true);
+
+ final long[] cpuTimesMs3 = getAllCpuFreqTimes(sTestPkgUid, PROCESS_STATE_TOP);
+ assertCpuTimesValid(cpuTimesMs3);
+ assertCpuTimesEqual(cpuTimesMs3, cpuTimesMs, 20,
+ "Unexpected cpu times after turning on tracking");
+
+ doSomeWork(PROCESS_STATE_TOP);
+ forceStop();
+
+ final long[] cpuTimesMs4 = getAllCpuFreqTimes(sTestPkgUid, PROCESS_STATE_TOP);
+ assertCpuTimesValid(cpuTimesMs4);
+ actualCpuTimeMs = 0;
+ for (int i = 0; i < cpuTimesMs.length / 2; ++i) {
+ actualCpuTimeMs += cpuTimesMs[i];
+ }
+ assertApproximateValue("Incorrect total cpu time, " + msgCpuTimes,
+ 2 * WORK_DURATION_MS, actualCpuTimeMs);
+
+ batteryOffScreenOn();
+ } finally {
+ Settings.Global.putString(sContext.getContentResolver(),
+ Settings.Global.BATTERY_STATS_CONSTANTS, bstatsConstants);
+ }
+ }
+
+ private void assertCpuTimesEqual(long[] actual, long[] expected, long delta, String errMsg) {
+ for (int i = actual.length - 1; i >= 0; --i) {
+ if (actual[i] > expected[i] + delta || actual[i] < expected[i]) {
+ fail(errMsg + ", actual=" + actual + ", expected=" + expected + ", delta=" + delta);
+ }
+ }
+ }
+
+ private void updateTrackPerProcStateCpuTimesSetting(String originalConstants, boolean enabled)
+ throws Exception {
+ final String newConstants;
+ final String setting = KEY_TRACK_CPU_TIMES_BY_PROC_STATE + "=" + enabled;
+ if (originalConstants == null || "null".equals(originalConstants)) {
+ newConstants = setting;
+ } else if (originalConstants.contains(KEY_TRACK_CPU_TIMES_BY_PROC_STATE)) {
+ newConstants = originalConstants.replaceAll(
+ KEY_TRACK_CPU_TIMES_BY_PROC_STATE + "=(true|false)", setting);
+ } else {
+ newConstants = originalConstants + "," + setting;
+ }
+ Settings.Global.putString(sContext.getContentResolver(),
+ Settings.Global.BATTERY_STATS_CONSTANTS, newConstants);
+ assertTrackPerProcStateCpuTimesSetting(enabled);
+ }
+
+ private void assertTrackPerProcStateCpuTimesSetting(boolean enabled) throws Exception {
+ final String expectedValue = Boolean.toString(enabled);
+ assertDelayedCondition("Unexpected value for " + KEY_TRACK_CPU_TIMES_BY_PROC_STATE, () -> {
+ final String actualValue = getSettingValueFromDump(KEY_TRACK_CPU_TIMES_BY_PROC_STATE);
+ return expectedValue.equals(actualValue)
+ ? null : "expected=" + expectedValue + ", actual=" + actualValue;
+ }, SETTING_UPDATE_TIMEOUT_MS, SETTING_UPDATE_CHECK_INTERVAL_MS);
+ }
+
+ private String getSettingValueFromDump(String key) throws Exception {
+ final String settingsDump = executeCmdSilent("dumpsys batterystats --settings");
+ final TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter('\n');
+ splitter.setString(settingsDump);
+ String next;
+ while (splitter.hasNext()) {
+ next = splitter.next();
+ if (next.startsWith(key)) {
+ return next.split("=")[1];
+ }
+ }
+ return null;
+ }
+
private void assertCpuTimesValid(long[] cpuTimes) {
assertNotNull(cpuTimes);
for (int i = 0; i < cpuTimes.length; ++i) {
@@ -750,13 +909,18 @@
}
private void assertDelayedCondition(String errMsgPrefix, ExpectedCondition condition)
- throws Exception {
- final long endTime = SystemClock.uptimeMillis() + GENERAL_TIMEOUT_MS;
+ throws Exception {
+ assertDelayedCondition(errMsgPrefix, condition, GENERAL_TIMEOUT_MS, GENERAL_INTERVAL_MS);
+ }
+
+ private void assertDelayedCondition(String errMsgPrefix, ExpectedCondition condition,
+ long timeoutMs, long checkIntervalMs) throws Exception {
+ final long endTime = SystemClock.uptimeMillis() + timeoutMs;
while (SystemClock.uptimeMillis() <= endTime) {
if (condition.getErrIfNotTrue() == null) {
return;
}
- SystemClock.sleep(GENERAL_INTERVAL_MS);
+ SystemClock.sleep(checkIntervalMs);
}
final String errMsg = condition.getErrIfNotTrue();
if (errMsg != null) {
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 43b41a0..6c5a2aa 100644
--- a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
+++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
@@ -139,6 +139,11 @@
}
@Override
+ public Future<?> scheduleCpuSyncDueToSettingChange() {
+ return null;
+ }
+
+ @Override
public Future<?> scheduleReadProcStateCpuTimes(
boolean onBattery, boolean onBatteryScreenOff) {
return null;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 81e34df..2da1c2b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2695,6 +2695,13 @@
}
@Override
+ public void onBootPhase(int phase) {
+ if (phase == PHASE_SYSTEM_SERVICES_READY) {
+ mService.mBatteryStatsService.systemServicesReady();
+ }
+ }
+
+ @Override
public void onCleanupUser(int userId) {
mService.mBatteryStatsService.onCleanupUser(userId);
}
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index 28b8edf..1fcaeef 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -118,9 +118,14 @@
}
@Override
+ public synchronized Future<?> scheduleCpuSyncDueToSettingChange() {
+ return scheduleSyncLocked("setting-change", UPDATE_CPU);
+ }
+
+ @Override
public Future<?> scheduleReadProcStateCpuTimes(boolean onBattery, boolean onBatteryScreenOff) {
synchronized (mStats) {
- if (!mStats.mPerProcStateCpuTimesAvailable) {
+ if (!mStats.trackPerProcStateCpuTimes()) {
return null;
}
}
@@ -138,7 +143,7 @@
public Future<?> scheduleCopyFromAllUidsCpuTimes(
boolean onBattery, boolean onBatteryScreenOff) {
synchronized (mStats) {
- if (!mStats.mPerProcStateCpuTimesAvailable) {
+ if (!mStats.trackPerProcStateCpuTimes()) {
return null;
}
}
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 813e617..c9aa9a2 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -185,6 +185,10 @@
ServiceManager.addService(BatteryStats.SERVICE_NAME, asBinder());
}
+ public void systemServicesReady() {
+ mStats.systemServicesReady(mContext);
+ }
+
private final class LocalService extends BatteryStatsInternal {
@Override
public String[] getWifiIfaces() {
@@ -1185,6 +1189,7 @@
pw.println(" --write: force write current collected stats to disk.");
pw.println(" --new-daily: immediately create and write new daily stats record.");
pw.println(" --read-daily: read-load last written daily stats.");
+ pw.println(" --settings: dump the settings key/values related to batterystats");
pw.println(" <package.name>: optional name of package to filter output by.");
pw.println(" -h: print this help text.");
pw.println("Battery stats (batterystats) commands:");
@@ -1197,6 +1202,12 @@
pw.println(" pretend-screen-off: pretend the screen is off, even if screen state changes");
}
+ private void dumpSettings(PrintWriter pw) {
+ synchronized (mStats) {
+ mStats.dumpConstantsLocked(pw);
+ }
+ }
+
private int doEnableOrDisable(PrintWriter pw, int i, String[] args, boolean enable) {
i++;
if (i >= args.length) {
@@ -1307,6 +1318,9 @@
} else if ("-h".equals(arg)) {
dumpHelp(pw);
return;
+ } else if ("--settings".equals(arg)) {
+ dumpSettings(pw);
+ return;
} else if ("-a".equals(arg)) {
flags |= BatteryStats.DUMP_VERBOSE;
} else if (arg.length() > 0 && arg.charAt(0) == '-'){