Loading core/java/com/android/internal/os/BatteryStatsHistory.java +15 −6 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.internal.os; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.BatteryStats; import android.os.Parcel; import android.os.StatFs; Loading Loading @@ -61,6 +63,7 @@ public class BatteryStatsHistory { public static final String FILE_SUFFIX = ".bin"; private static final int MIN_FREE_SPACE = 100 * 1024 * 1024; @Nullable private final BatteryStatsImpl mStats; private final Parcel mHistoryBuffer; private final File mHistoryDir; Loading Loading @@ -107,7 +110,8 @@ public class BatteryStatsHistory { * @param systemDir typically /data/system * @param historyBuffer The in-memory history buffer. */ public BatteryStatsHistory(BatteryStatsImpl stats, File systemDir, Parcel historyBuffer) { public BatteryStatsHistory(@NonNull BatteryStatsImpl stats, File systemDir, Parcel historyBuffer) { mStats = stats; mHistoryBuffer = historyBuffer; mHistoryDir = new File(systemDir, HISTORY_DIR); Loading Loading @@ -149,11 +153,10 @@ public class BatteryStatsHistory { /** * Used when BatteryStatsImpl object is created from deserialization of a parcel, * such as Settings app or checkin file. * @param stats BatteryStatsImpl object. * @param historyBuffer the history buffer inside BatteryStatsImpl * @param historyBuffer the history buffer */ public BatteryStatsHistory(BatteryStatsImpl stats, Parcel historyBuffer) { mStats = stats; public BatteryStatsHistory(Parcel historyBuffer) { mStats = null; mHistoryDir = null; mHistoryBuffer = historyBuffer; } Loading Loading @@ -184,10 +187,16 @@ public class BatteryStatsHistory { * create next history file. */ public void startNextFile() { if (mStats == null) { Slog.wtf(TAG, "mStats should not be null when writing history"); return; } if (mFileNumbers.isEmpty()) { Slog.wtf(TAG, "mFileNumbers should never be empty"); return; } // The last number in mFileNumbers is the highest number. The next file number is highest // number plus one. final int next = mFileNumbers.get(mFileNumbers.size() - 1) + 1; Loading Loading @@ -357,7 +366,7 @@ public class BatteryStatsHistory { private boolean skipHead(Parcel p) { p.setDataPosition(0); final int version = p.readInt(); if (version != mStats.VERSION) { if (version != BatteryStatsImpl.VERSION) { return false; } // skip historyBaseTime field. Loading core/java/com/android/internal/os/BatteryStatsHistoryIterator.java 0 → 100644 +264 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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.internal.os; import android.annotation.NonNull; import android.os.BatteryManager; import android.os.BatteryStats; import android.os.Parcel; import android.util.Slog; import java.util.List; /** * An iterator for {@link BatteryStats.HistoryItem}'s. */ public class BatteryStatsHistoryIterator { private static final boolean DEBUG = false; private static final String TAG = "BatteryStatsHistoryItr"; private final BatteryStatsHistory mBatteryStatsHistory; private final BatteryStats.HistoryStepDetails mReadHistoryStepDetails = new BatteryStats.HistoryStepDetails(); private final String[] mReadHistoryStrings; private final int[] mReadHistoryUids; BatteryStatsHistoryIterator(@NonNull BatteryStatsHistory history, @NonNull List<BatteryStats.HistoryTag> historyTagPool) { mBatteryStatsHistory = history; mBatteryStatsHistory.startIteratingHistory(); mReadHistoryStrings = new String[historyTagPool.size()]; mReadHistoryUids = new int[historyTagPool.size()]; for (int i = historyTagPool.size() - 1; i >= 0; i--) { BatteryStats.HistoryTag tag = historyTagPool.get(i); final int idx = tag.poolIdx; mReadHistoryStrings[idx] = tag.string; mReadHistoryUids[idx] = tag.uid; } } /** * Retrieves the next HistoryItem from battery history, if available. Returns false if there * are no more items. */ public boolean next(BatteryStats.HistoryItem out) { Parcel p = mBatteryStatsHistory.getNextParcel(out); if (p == null) { mBatteryStatsHistory.finishIteratingHistory(); return false; } final long lastRealtimeMs = out.time; final long lastWalltimeMs = out.currentTime; readHistoryDelta(p, out); if (out.cmd != BatteryStats.HistoryItem.CMD_CURRENT_TIME && out.cmd != BatteryStats.HistoryItem.CMD_RESET && lastWalltimeMs != 0) { out.currentTime = lastWalltimeMs + (out.time - lastRealtimeMs); } return true; } void readHistoryDelta(Parcel src, BatteryStats.HistoryItem cur) { int firstToken = src.readInt(); int deltaTimeToken = firstToken & BatteryStatsImpl.DELTA_TIME_MASK; cur.cmd = BatteryStats.HistoryItem.CMD_UPDATE; cur.numReadInts = 1; if (DEBUG) { Slog.i(TAG, "READ DELTA: firstToken=0x" + Integer.toHexString(firstToken) + " deltaTimeToken=" + deltaTimeToken); } if (deltaTimeToken < BatteryStatsImpl.DELTA_TIME_ABS) { cur.time += deltaTimeToken; } else if (deltaTimeToken == BatteryStatsImpl.DELTA_TIME_ABS) { cur.readFromParcel(src); if (DEBUG) Slog.i(TAG, "READ DELTA: ABS time=" + cur.time); return; } else if (deltaTimeToken == BatteryStatsImpl.DELTA_TIME_INT) { int delta = src.readInt(); cur.time += delta; cur.numReadInts += 1; if (DEBUG) Slog.i(TAG, "READ DELTA: time delta=" + delta + " new time=" + cur.time); } else { long delta = src.readLong(); if (DEBUG) Slog.i(TAG, "READ DELTA: time delta=" + delta + " new time=" + cur.time); cur.time += delta; cur.numReadInts += 2; } final int batteryLevelInt; if ((firstToken & BatteryStatsImpl.DELTA_BATTERY_LEVEL_FLAG) != 0) { batteryLevelInt = src.readInt(); readBatteryLevelInt(batteryLevelInt, cur); cur.numReadInts += 1; if (DEBUG) { Slog.i(TAG, "READ DELTA: batteryToken=0x" + Integer.toHexString(batteryLevelInt) + " batteryLevel=" + cur.batteryLevel + " batteryTemp=" + cur.batteryTemperature + " batteryVolt=" + (int) cur.batteryVoltage); } } else { batteryLevelInt = 0; } if ((firstToken & BatteryStatsImpl.DELTA_STATE_FLAG) != 0) { int stateInt = src.readInt(); cur.states = (firstToken & BatteryStatsImpl.DELTA_STATE_MASK) | (stateInt & (~BatteryStatsImpl.STATE_BATTERY_MASK)); cur.batteryStatus = (byte) ((stateInt >> BatteryStatsImpl.STATE_BATTERY_STATUS_SHIFT) & BatteryStatsImpl.STATE_BATTERY_STATUS_MASK); cur.batteryHealth = (byte) ((stateInt >> BatteryStatsImpl.STATE_BATTERY_HEALTH_SHIFT) & BatteryStatsImpl.STATE_BATTERY_HEALTH_MASK); cur.batteryPlugType = (byte) ((stateInt >> BatteryStatsImpl.STATE_BATTERY_PLUG_SHIFT) & BatteryStatsImpl.STATE_BATTERY_PLUG_MASK); switch (cur.batteryPlugType) { case 1: cur.batteryPlugType = BatteryManager.BATTERY_PLUGGED_AC; break; case 2: cur.batteryPlugType = BatteryManager.BATTERY_PLUGGED_USB; break; case 3: cur.batteryPlugType = BatteryManager.BATTERY_PLUGGED_WIRELESS; break; } cur.numReadInts += 1; if (DEBUG) { Slog.i(TAG, "READ DELTA: stateToken=0x" + Integer.toHexString(stateInt) + " batteryStatus=" + cur.batteryStatus + " batteryHealth=" + cur.batteryHealth + " batteryPlugType=" + cur.batteryPlugType + " states=0x" + Integer.toHexString(cur.states)); } } else { cur.states = (firstToken & BatteryStatsImpl.DELTA_STATE_MASK) | (cur.states & (~BatteryStatsImpl.STATE_BATTERY_MASK)); } if ((firstToken & BatteryStatsImpl.DELTA_STATE2_FLAG) != 0) { cur.states2 = src.readInt(); if (DEBUG) { Slog.i(TAG, "READ DELTA: states2=0x" + Integer.toHexString(cur.states2)); } } if ((firstToken & BatteryStatsImpl.DELTA_WAKELOCK_FLAG) != 0) { int indexes = src.readInt(); int wakeLockIndex = indexes & 0xffff; int wakeReasonIndex = (indexes >> 16) & 0xffff; if (wakeLockIndex != 0xffff) { cur.wakelockTag = cur.localWakelockTag; readHistoryTag(wakeLockIndex, cur.wakelockTag); if (DEBUG) { Slog.i(TAG, "READ DELTA: wakelockTag=#" + cur.wakelockTag.poolIdx + " " + cur.wakelockTag.uid + ":" + cur.wakelockTag.string); } } else { cur.wakelockTag = null; } if (wakeReasonIndex != 0xffff) { cur.wakeReasonTag = cur.localWakeReasonTag; readHistoryTag(wakeReasonIndex, cur.wakeReasonTag); if (DEBUG) { Slog.i(TAG, "READ DELTA: wakeReasonTag=#" + cur.wakeReasonTag.poolIdx + " " + cur.wakeReasonTag.uid + ":" + cur.wakeReasonTag.string); } } else { cur.wakeReasonTag = null; } cur.numReadInts += 1; } else { cur.wakelockTag = null; cur.wakeReasonTag = null; } if ((firstToken & BatteryStatsImpl.DELTA_EVENT_FLAG) != 0) { cur.eventTag = cur.localEventTag; final int codeAndIndex = src.readInt(); cur.eventCode = (codeAndIndex & 0xffff); final int index = ((codeAndIndex >> 16) & 0xffff); readHistoryTag(index, cur.eventTag); cur.numReadInts += 1; if (DEBUG) { Slog.i(TAG, "READ DELTA: event=" + cur.eventCode + " tag=#" + cur.eventTag.poolIdx + " " + cur.eventTag.uid + ":" + cur.eventTag.string); } } else { cur.eventCode = BatteryStats.HistoryItem.EVENT_NONE; } if ((batteryLevelInt & BatteryStatsImpl.BATTERY_DELTA_LEVEL_FLAG) != 0) { cur.stepDetails = mReadHistoryStepDetails; cur.stepDetails.readFromParcel(src); } else { cur.stepDetails = null; } if ((firstToken & BatteryStatsImpl.DELTA_BATTERY_CHARGE_FLAG) != 0) { cur.batteryChargeUah = src.readInt(); } cur.modemRailChargeMah = src.readDouble(); cur.wifiRailChargeMah = src.readDouble(); } int getHistoryStringPoolSize() { return mReadHistoryStrings.length; } int getHistoryStringPoolBytes() { int totalChars = 0; for (int i = mReadHistoryStrings.length - 1; i >= 0; i--) { if (mReadHistoryStrings[i] != null) { totalChars += mReadHistoryStrings[i].length() + 1; } } // Each entry is a fixed 12 bytes: 4 for index, 4 for uid, 4 for string size // Each string character is 2 bytes. return (mReadHistoryStrings.length * 12) + (totalChars * 2); } String getHistoryTagPoolString(int index) { return mReadHistoryStrings[index]; } int getHistoryTagPoolUid(int index) { return mReadHistoryUids[index]; } private void readHistoryTag(int index, BatteryStats.HistoryTag tag) { if (index < mReadHistoryStrings.length) { tag.string = mReadHistoryStrings[index]; tag.uid = mReadHistoryUids[index]; } else { tag.string = null; tag.uid = 0; } tag.poolIdx = index; } private static void readBatteryLevelInt(int batteryLevelInt, BatteryStats.HistoryItem out) { out.batteryLevel = (byte) ((batteryLevelInt & 0xfe000000) >>> 25); out.batteryTemperature = (short) ((batteryLevelInt & 0x01ff8000) >>> 15); out.batteryVoltage = (char) ((batteryLevelInt & 0x00007ffe) >>> 1); } } core/java/com/android/internal/os/BatteryStatsImpl.java +29 −185 File changed.Preview size limit exceeded, changes collapsed. Show changes core/tests/coretests/src/com/android/internal/os/BatteryStatsHistoryIteratorTest.java 0 → 100644 +115 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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.internal.os; import static com.google.common.truth.Truth.assertThat; import android.os.BatteryManager; import android.os.BatteryStats; import android.os.Process; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) @SmallTest public class BatteryStatsHistoryIteratorTest { private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42; @Rule public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule(); @Test public void testIterator() { MockBatteryStatsImpl batteryStats = mStatsRule.getBatteryStats(); batteryStats.setRecordAllHistoryLocked(true); batteryStats.forceRecordAllHistory(); mStatsRule.setTime(1000, 1000); batteryStats.setNoAutoReset(true); batteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING, 100, /* plugType */ 0, 90, 72, 3700, 3_600_000, 4_000_000, 0, 1_000_000, 1_000_000, 1_000_000); batteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING, 100, /* plugType */ 0, 80, 72, 3700, 2_400_000, 4_000_000, 0, 2_000_000, 2_000_000, 2_000_000); batteryStats.noteAlarmStartLocked("foo", null, APP_UID, 3_000_000, 2_000_000); batteryStats.noteAlarmFinishLocked("foo", null, APP_UID, 3_001_000, 2_001_000); final BatteryStatsHistoryIterator iterator = batteryStats.createBatteryStatsHistoryIterator(); BatteryStats.HistoryItem item = new BatteryStats.HistoryItem(); assertThat(iterator.next(item)).isTrue(); assertHistoryItem(item, BatteryStats.HistoryItem.CMD_RESET, BatteryStats.HistoryItem.EVENT_NONE, null, 0, 3_600_000, 90, 1_000_000); assertThat(iterator.next(item)).isTrue(); assertHistoryItem(item, BatteryStats.HistoryItem.CMD_UPDATE, BatteryStats.HistoryItem.EVENT_NONE, null, 0, 3_600_000, 90, 1_000_000); assertThat(iterator.next(item)).isTrue(); assertHistoryItem(item, BatteryStats.HistoryItem.CMD_UPDATE, BatteryStats.HistoryItem.EVENT_NONE, null, 0, 2_400_000, 80, 2_000_000); assertThat(iterator.next(item)).isTrue(); assertHistoryItem(item, BatteryStats.HistoryItem.CMD_UPDATE, BatteryStats.HistoryItem.EVENT_NONE, null, 0, 2_400_000, 80, 2_000_000); assertThat(iterator.next(item)).isTrue(); assertHistoryItem(item, BatteryStats.HistoryItem.CMD_UPDATE, BatteryStats.HistoryItem.EVENT_ALARM | BatteryStats.HistoryItem.EVENT_FLAG_START, "foo", APP_UID, 2_400_000, 80, 3_000_000); assertThat(iterator.next(item)).isTrue(); assertHistoryItem(item, BatteryStats.HistoryItem.CMD_UPDATE, BatteryStats.HistoryItem.EVENT_ALARM | BatteryStats.HistoryItem.EVENT_FLAG_FINISH, "foo", APP_UID, 2_400_000, 80, 3_001_000); assertThat(iterator.next(item)).isFalse(); } private void assertHistoryItem(BatteryStats.HistoryItem item, int command, int eventCode, String tag, int uid, int batteryChargeUah, int batteryLevel, long elapsedTimeMs) { assertThat(item.cmd).isEqualTo(command); assertThat(item.eventCode).isEqualTo(eventCode); if (tag == null) { assertThat(item.eventTag).isNull(); } else { assertThat(item.eventTag.string).isEqualTo(tag); assertThat(item.eventTag.uid).isEqualTo(uid); } assertThat(item.batteryChargeUah).isEqualTo(batteryChargeUah); assertThat(item.batteryLevel).isEqualTo(batteryLevel); assertThat(item.time).isEqualTo(elapsedTimeMs); } } core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java +1 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import org.junit.runners.Suite; BatteryStatsDualTimerTest.class, BatteryStatsDurationTimerTest.class, BatteryStatsHelperTest.class, BatteryStatsHistoryIteratorTest.class, BatteryStatsHistoryTest.class, BatteryStatsImplTest.class, BatteryStatsNoteTest.class, Loading Loading
core/java/com/android/internal/os/BatteryStatsHistory.java +15 −6 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.internal.os; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.BatteryStats; import android.os.Parcel; import android.os.StatFs; Loading Loading @@ -61,6 +63,7 @@ public class BatteryStatsHistory { public static final String FILE_SUFFIX = ".bin"; private static final int MIN_FREE_SPACE = 100 * 1024 * 1024; @Nullable private final BatteryStatsImpl mStats; private final Parcel mHistoryBuffer; private final File mHistoryDir; Loading Loading @@ -107,7 +110,8 @@ public class BatteryStatsHistory { * @param systemDir typically /data/system * @param historyBuffer The in-memory history buffer. */ public BatteryStatsHistory(BatteryStatsImpl stats, File systemDir, Parcel historyBuffer) { public BatteryStatsHistory(@NonNull BatteryStatsImpl stats, File systemDir, Parcel historyBuffer) { mStats = stats; mHistoryBuffer = historyBuffer; mHistoryDir = new File(systemDir, HISTORY_DIR); Loading Loading @@ -149,11 +153,10 @@ public class BatteryStatsHistory { /** * Used when BatteryStatsImpl object is created from deserialization of a parcel, * such as Settings app or checkin file. * @param stats BatteryStatsImpl object. * @param historyBuffer the history buffer inside BatteryStatsImpl * @param historyBuffer the history buffer */ public BatteryStatsHistory(BatteryStatsImpl stats, Parcel historyBuffer) { mStats = stats; public BatteryStatsHistory(Parcel historyBuffer) { mStats = null; mHistoryDir = null; mHistoryBuffer = historyBuffer; } Loading Loading @@ -184,10 +187,16 @@ public class BatteryStatsHistory { * create next history file. */ public void startNextFile() { if (mStats == null) { Slog.wtf(TAG, "mStats should not be null when writing history"); return; } if (mFileNumbers.isEmpty()) { Slog.wtf(TAG, "mFileNumbers should never be empty"); return; } // The last number in mFileNumbers is the highest number. The next file number is highest // number plus one. final int next = mFileNumbers.get(mFileNumbers.size() - 1) + 1; Loading Loading @@ -357,7 +366,7 @@ public class BatteryStatsHistory { private boolean skipHead(Parcel p) { p.setDataPosition(0); final int version = p.readInt(); if (version != mStats.VERSION) { if (version != BatteryStatsImpl.VERSION) { return false; } // skip historyBaseTime field. Loading
core/java/com/android/internal/os/BatteryStatsHistoryIterator.java 0 → 100644 +264 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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.internal.os; import android.annotation.NonNull; import android.os.BatteryManager; import android.os.BatteryStats; import android.os.Parcel; import android.util.Slog; import java.util.List; /** * An iterator for {@link BatteryStats.HistoryItem}'s. */ public class BatteryStatsHistoryIterator { private static final boolean DEBUG = false; private static final String TAG = "BatteryStatsHistoryItr"; private final BatteryStatsHistory mBatteryStatsHistory; private final BatteryStats.HistoryStepDetails mReadHistoryStepDetails = new BatteryStats.HistoryStepDetails(); private final String[] mReadHistoryStrings; private final int[] mReadHistoryUids; BatteryStatsHistoryIterator(@NonNull BatteryStatsHistory history, @NonNull List<BatteryStats.HistoryTag> historyTagPool) { mBatteryStatsHistory = history; mBatteryStatsHistory.startIteratingHistory(); mReadHistoryStrings = new String[historyTagPool.size()]; mReadHistoryUids = new int[historyTagPool.size()]; for (int i = historyTagPool.size() - 1; i >= 0; i--) { BatteryStats.HistoryTag tag = historyTagPool.get(i); final int idx = tag.poolIdx; mReadHistoryStrings[idx] = tag.string; mReadHistoryUids[idx] = tag.uid; } } /** * Retrieves the next HistoryItem from battery history, if available. Returns false if there * are no more items. */ public boolean next(BatteryStats.HistoryItem out) { Parcel p = mBatteryStatsHistory.getNextParcel(out); if (p == null) { mBatteryStatsHistory.finishIteratingHistory(); return false; } final long lastRealtimeMs = out.time; final long lastWalltimeMs = out.currentTime; readHistoryDelta(p, out); if (out.cmd != BatteryStats.HistoryItem.CMD_CURRENT_TIME && out.cmd != BatteryStats.HistoryItem.CMD_RESET && lastWalltimeMs != 0) { out.currentTime = lastWalltimeMs + (out.time - lastRealtimeMs); } return true; } void readHistoryDelta(Parcel src, BatteryStats.HistoryItem cur) { int firstToken = src.readInt(); int deltaTimeToken = firstToken & BatteryStatsImpl.DELTA_TIME_MASK; cur.cmd = BatteryStats.HistoryItem.CMD_UPDATE; cur.numReadInts = 1; if (DEBUG) { Slog.i(TAG, "READ DELTA: firstToken=0x" + Integer.toHexString(firstToken) + " deltaTimeToken=" + deltaTimeToken); } if (deltaTimeToken < BatteryStatsImpl.DELTA_TIME_ABS) { cur.time += deltaTimeToken; } else if (deltaTimeToken == BatteryStatsImpl.DELTA_TIME_ABS) { cur.readFromParcel(src); if (DEBUG) Slog.i(TAG, "READ DELTA: ABS time=" + cur.time); return; } else if (deltaTimeToken == BatteryStatsImpl.DELTA_TIME_INT) { int delta = src.readInt(); cur.time += delta; cur.numReadInts += 1; if (DEBUG) Slog.i(TAG, "READ DELTA: time delta=" + delta + " new time=" + cur.time); } else { long delta = src.readLong(); if (DEBUG) Slog.i(TAG, "READ DELTA: time delta=" + delta + " new time=" + cur.time); cur.time += delta; cur.numReadInts += 2; } final int batteryLevelInt; if ((firstToken & BatteryStatsImpl.DELTA_BATTERY_LEVEL_FLAG) != 0) { batteryLevelInt = src.readInt(); readBatteryLevelInt(batteryLevelInt, cur); cur.numReadInts += 1; if (DEBUG) { Slog.i(TAG, "READ DELTA: batteryToken=0x" + Integer.toHexString(batteryLevelInt) + " batteryLevel=" + cur.batteryLevel + " batteryTemp=" + cur.batteryTemperature + " batteryVolt=" + (int) cur.batteryVoltage); } } else { batteryLevelInt = 0; } if ((firstToken & BatteryStatsImpl.DELTA_STATE_FLAG) != 0) { int stateInt = src.readInt(); cur.states = (firstToken & BatteryStatsImpl.DELTA_STATE_MASK) | (stateInt & (~BatteryStatsImpl.STATE_BATTERY_MASK)); cur.batteryStatus = (byte) ((stateInt >> BatteryStatsImpl.STATE_BATTERY_STATUS_SHIFT) & BatteryStatsImpl.STATE_BATTERY_STATUS_MASK); cur.batteryHealth = (byte) ((stateInt >> BatteryStatsImpl.STATE_BATTERY_HEALTH_SHIFT) & BatteryStatsImpl.STATE_BATTERY_HEALTH_MASK); cur.batteryPlugType = (byte) ((stateInt >> BatteryStatsImpl.STATE_BATTERY_PLUG_SHIFT) & BatteryStatsImpl.STATE_BATTERY_PLUG_MASK); switch (cur.batteryPlugType) { case 1: cur.batteryPlugType = BatteryManager.BATTERY_PLUGGED_AC; break; case 2: cur.batteryPlugType = BatteryManager.BATTERY_PLUGGED_USB; break; case 3: cur.batteryPlugType = BatteryManager.BATTERY_PLUGGED_WIRELESS; break; } cur.numReadInts += 1; if (DEBUG) { Slog.i(TAG, "READ DELTA: stateToken=0x" + Integer.toHexString(stateInt) + " batteryStatus=" + cur.batteryStatus + " batteryHealth=" + cur.batteryHealth + " batteryPlugType=" + cur.batteryPlugType + " states=0x" + Integer.toHexString(cur.states)); } } else { cur.states = (firstToken & BatteryStatsImpl.DELTA_STATE_MASK) | (cur.states & (~BatteryStatsImpl.STATE_BATTERY_MASK)); } if ((firstToken & BatteryStatsImpl.DELTA_STATE2_FLAG) != 0) { cur.states2 = src.readInt(); if (DEBUG) { Slog.i(TAG, "READ DELTA: states2=0x" + Integer.toHexString(cur.states2)); } } if ((firstToken & BatteryStatsImpl.DELTA_WAKELOCK_FLAG) != 0) { int indexes = src.readInt(); int wakeLockIndex = indexes & 0xffff; int wakeReasonIndex = (indexes >> 16) & 0xffff; if (wakeLockIndex != 0xffff) { cur.wakelockTag = cur.localWakelockTag; readHistoryTag(wakeLockIndex, cur.wakelockTag); if (DEBUG) { Slog.i(TAG, "READ DELTA: wakelockTag=#" + cur.wakelockTag.poolIdx + " " + cur.wakelockTag.uid + ":" + cur.wakelockTag.string); } } else { cur.wakelockTag = null; } if (wakeReasonIndex != 0xffff) { cur.wakeReasonTag = cur.localWakeReasonTag; readHistoryTag(wakeReasonIndex, cur.wakeReasonTag); if (DEBUG) { Slog.i(TAG, "READ DELTA: wakeReasonTag=#" + cur.wakeReasonTag.poolIdx + " " + cur.wakeReasonTag.uid + ":" + cur.wakeReasonTag.string); } } else { cur.wakeReasonTag = null; } cur.numReadInts += 1; } else { cur.wakelockTag = null; cur.wakeReasonTag = null; } if ((firstToken & BatteryStatsImpl.DELTA_EVENT_FLAG) != 0) { cur.eventTag = cur.localEventTag; final int codeAndIndex = src.readInt(); cur.eventCode = (codeAndIndex & 0xffff); final int index = ((codeAndIndex >> 16) & 0xffff); readHistoryTag(index, cur.eventTag); cur.numReadInts += 1; if (DEBUG) { Slog.i(TAG, "READ DELTA: event=" + cur.eventCode + " tag=#" + cur.eventTag.poolIdx + " " + cur.eventTag.uid + ":" + cur.eventTag.string); } } else { cur.eventCode = BatteryStats.HistoryItem.EVENT_NONE; } if ((batteryLevelInt & BatteryStatsImpl.BATTERY_DELTA_LEVEL_FLAG) != 0) { cur.stepDetails = mReadHistoryStepDetails; cur.stepDetails.readFromParcel(src); } else { cur.stepDetails = null; } if ((firstToken & BatteryStatsImpl.DELTA_BATTERY_CHARGE_FLAG) != 0) { cur.batteryChargeUah = src.readInt(); } cur.modemRailChargeMah = src.readDouble(); cur.wifiRailChargeMah = src.readDouble(); } int getHistoryStringPoolSize() { return mReadHistoryStrings.length; } int getHistoryStringPoolBytes() { int totalChars = 0; for (int i = mReadHistoryStrings.length - 1; i >= 0; i--) { if (mReadHistoryStrings[i] != null) { totalChars += mReadHistoryStrings[i].length() + 1; } } // Each entry is a fixed 12 bytes: 4 for index, 4 for uid, 4 for string size // Each string character is 2 bytes. return (mReadHistoryStrings.length * 12) + (totalChars * 2); } String getHistoryTagPoolString(int index) { return mReadHistoryStrings[index]; } int getHistoryTagPoolUid(int index) { return mReadHistoryUids[index]; } private void readHistoryTag(int index, BatteryStats.HistoryTag tag) { if (index < mReadHistoryStrings.length) { tag.string = mReadHistoryStrings[index]; tag.uid = mReadHistoryUids[index]; } else { tag.string = null; tag.uid = 0; } tag.poolIdx = index; } private static void readBatteryLevelInt(int batteryLevelInt, BatteryStats.HistoryItem out) { out.batteryLevel = (byte) ((batteryLevelInt & 0xfe000000) >>> 25); out.batteryTemperature = (short) ((batteryLevelInt & 0x01ff8000) >>> 15); out.batteryVoltage = (char) ((batteryLevelInt & 0x00007ffe) >>> 1); } }
core/java/com/android/internal/os/BatteryStatsImpl.java +29 −185 File changed.Preview size limit exceeded, changes collapsed. Show changes
core/tests/coretests/src/com/android/internal/os/BatteryStatsHistoryIteratorTest.java 0 → 100644 +115 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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.internal.os; import static com.google.common.truth.Truth.assertThat; import android.os.BatteryManager; import android.os.BatteryStats; import android.os.Process; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) @SmallTest public class BatteryStatsHistoryIteratorTest { private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42; @Rule public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule(); @Test public void testIterator() { MockBatteryStatsImpl batteryStats = mStatsRule.getBatteryStats(); batteryStats.setRecordAllHistoryLocked(true); batteryStats.forceRecordAllHistory(); mStatsRule.setTime(1000, 1000); batteryStats.setNoAutoReset(true); batteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING, 100, /* plugType */ 0, 90, 72, 3700, 3_600_000, 4_000_000, 0, 1_000_000, 1_000_000, 1_000_000); batteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING, 100, /* plugType */ 0, 80, 72, 3700, 2_400_000, 4_000_000, 0, 2_000_000, 2_000_000, 2_000_000); batteryStats.noteAlarmStartLocked("foo", null, APP_UID, 3_000_000, 2_000_000); batteryStats.noteAlarmFinishLocked("foo", null, APP_UID, 3_001_000, 2_001_000); final BatteryStatsHistoryIterator iterator = batteryStats.createBatteryStatsHistoryIterator(); BatteryStats.HistoryItem item = new BatteryStats.HistoryItem(); assertThat(iterator.next(item)).isTrue(); assertHistoryItem(item, BatteryStats.HistoryItem.CMD_RESET, BatteryStats.HistoryItem.EVENT_NONE, null, 0, 3_600_000, 90, 1_000_000); assertThat(iterator.next(item)).isTrue(); assertHistoryItem(item, BatteryStats.HistoryItem.CMD_UPDATE, BatteryStats.HistoryItem.EVENT_NONE, null, 0, 3_600_000, 90, 1_000_000); assertThat(iterator.next(item)).isTrue(); assertHistoryItem(item, BatteryStats.HistoryItem.CMD_UPDATE, BatteryStats.HistoryItem.EVENT_NONE, null, 0, 2_400_000, 80, 2_000_000); assertThat(iterator.next(item)).isTrue(); assertHistoryItem(item, BatteryStats.HistoryItem.CMD_UPDATE, BatteryStats.HistoryItem.EVENT_NONE, null, 0, 2_400_000, 80, 2_000_000); assertThat(iterator.next(item)).isTrue(); assertHistoryItem(item, BatteryStats.HistoryItem.CMD_UPDATE, BatteryStats.HistoryItem.EVENT_ALARM | BatteryStats.HistoryItem.EVENT_FLAG_START, "foo", APP_UID, 2_400_000, 80, 3_000_000); assertThat(iterator.next(item)).isTrue(); assertHistoryItem(item, BatteryStats.HistoryItem.CMD_UPDATE, BatteryStats.HistoryItem.EVENT_ALARM | BatteryStats.HistoryItem.EVENT_FLAG_FINISH, "foo", APP_UID, 2_400_000, 80, 3_001_000); assertThat(iterator.next(item)).isFalse(); } private void assertHistoryItem(BatteryStats.HistoryItem item, int command, int eventCode, String tag, int uid, int batteryChargeUah, int batteryLevel, long elapsedTimeMs) { assertThat(item.cmd).isEqualTo(command); assertThat(item.eventCode).isEqualTo(eventCode); if (tag == null) { assertThat(item.eventTag).isNull(); } else { assertThat(item.eventTag.string).isEqualTo(tag); assertThat(item.eventTag.uid).isEqualTo(uid); } assertThat(item.batteryChargeUah).isEqualTo(batteryChargeUah); assertThat(item.batteryLevel).isEqualTo(batteryLevel); assertThat(item.time).isEqualTo(elapsedTimeMs); } }
core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java +1 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import org.junit.runners.Suite; BatteryStatsDualTimerTest.class, BatteryStatsDurationTimerTest.class, BatteryStatsHelperTest.class, BatteryStatsHistoryIteratorTest.class, BatteryStatsHistoryTest.class, BatteryStatsImplTest.class, BatteryStatsNoteTest.class, Loading