diff options
9 files changed, 349 insertions, 7 deletions
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index c1030cb0a246..0850bd997c3a 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -9775,6 +9775,22 @@ public final class Settings { 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 9015cbbe2a19..b8ff9e4e3ebc 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.annotation.Nullable; 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.SystemClock; 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.telephony.TelephonyManager; 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 class BatteryStatsImpl extends BatteryStats { 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 class BatteryStatsImpl extends BatteryStats { */ 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 @@ public class BatteryStatsImpl extends BatteryStats { 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 @@ public class BatteryStatsImpl extends BatteryStats { @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 @@ public class BatteryStatsImpl extends BatteryStats { mHandler = null; mPlatformIdleStateCallback = null; mUserInfoProvider = null; + mConstants = new Constants(mHandler); clearHistoryLocked(); } @@ -9411,7 +9441,7 @@ public class BatteryStatsImpl extends BatteryStats { 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 @@ public class BatteryStatsImpl extends BatteryStats { 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 @@ public class BatteryStatsImpl extends BatteryStats { mDailyFile = null; mHandler = null; mExternalSync = null; + mConstants = new Constants(mHandler); clearHistoryLocked(); readFromParcel(p); mPlatformIdleStateCallback = null; @@ -12613,6 +12645,78 @@ public class BatteryStatsImpl extends BatteryStats { 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 ca635a409a44..ebeb24c41479 100644 --- a/core/java/com/android/internal/os/KernelSingleUidTimeReader.java +++ b/core/java/com/android/internal/os/KernelSingleUidTimeReader.java @@ -46,12 +46,14 @@ public class KernelSingleUidTimeReader { 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 @@ public class KernelSingleUidTimeReader { 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 9df4f516e1e7..dfefbfd79551 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -112,6 +112,7 @@ public class SettingsBackupTest { 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 e54fe7ddbf19..4d34721b5aba 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; 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.IBinder; 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 @@ public class BstatsCpuTimesValidationTest { 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 @@ public class BstatsCpuTimesValidationTest { 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 @@ public class BstatsCpuTimesValidationTest { @Test public void testCpuFreqTimes() throws Exception { if (!sCpuFreqTimesAvailable) { + Log.w(TAG, "Skipping " + testName.getMethodName() + + "; freqTimesAvailable=" + sCpuFreqTimesAvailable + + ", procStateTimesAvailable=" + sPerProcStateTimesAvailable); return; } @@ -148,6 +162,9 @@ public class BstatsCpuTimesValidationTest { @Test public void testCpuFreqTimes_screenOff() throws Exception { if (!sCpuFreqTimesAvailable) { + Log.w(TAG, "Skipping " + testName.getMethodName() + + "; freqTimesAvailable=" + sCpuFreqTimesAvailable + + ", procStateTimesAvailable=" + sPerProcStateTimesAvailable); return; } @@ -179,6 +196,9 @@ public class BstatsCpuTimesValidationTest { @Test public void testCpuFreqTimes_isolatedProcess() throws Exception { if (!sCpuFreqTimesAvailable) { + Log.w(TAG, "Skipping " + testName.getMethodName() + + "; freqTimesAvailable=" + sCpuFreqTimesAvailable + + ", procStateTimesAvailable=" + sPerProcStateTimesAvailable); return; } @@ -204,6 +224,9 @@ public class BstatsCpuTimesValidationTest { @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 @@ public class BstatsCpuTimesValidationTest { @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 @@ public class BstatsCpuTimesValidationTest { @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 @@ public class BstatsCpuTimesValidationTest { @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 @@ public class BstatsCpuTimesValidationTest { @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 @@ public class BstatsCpuTimesValidationTest { @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 @@ public class BstatsCpuTimesValidationTest { @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 @@ public class BstatsCpuTimesValidationTest { 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 @@ public class BstatsCpuTimesValidationTest { } 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 43b41a0d142b..6c5a2aac159b 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 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl { } @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 700562258ba6..624035d2c720 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -2697,6 +2697,13 @@ public class ActivityManagerService extends IActivityManager.Stub } @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 28b8edf6fef1..1fcaeef72dba 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 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync { } @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 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync { 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 813e617cc2e0..c9aa9a2e2fa3 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 @@ public final class BatteryStatsService extends IBatteryStats.Stub 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 @@ public final class BatteryStatsService extends IBatteryStats.Stub 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 @@ public final class BatteryStatsService extends IBatteryStats.Stub 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 @@ public final class BatteryStatsService extends IBatteryStats.Stub } 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) == '-'){ |