Merge "Break out battery history reading into a separate class" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
cda90b4cf5
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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.
|
||||
|
||||
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
@@ -737,14 +737,11 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
protected boolean mRecordingHistory = false;
|
||||
int mNumHistoryItems;
|
||||
|
||||
final HashMap<HistoryTag, Integer> mHistoryTagPool = new HashMap<>();
|
||||
final Parcel mHistoryBuffer = Parcel.obtain();
|
||||
final HistoryItem mHistoryLastWritten = new HistoryItem();
|
||||
final HistoryItem mHistoryLastLastWritten = new HistoryItem();
|
||||
final HistoryItem mHistoryAddTmp = new HistoryItem();
|
||||
final HashMap<HistoryTag, Integer> mHistoryTagPool = new HashMap<>();
|
||||
String[] mReadHistoryStrings;
|
||||
int[] mReadHistoryUids;
|
||||
int mReadHistoryChars;
|
||||
int mNextHistoryTagIdx = 0;
|
||||
int mNumHistoryTagChars = 0;
|
||||
int mHistoryBufferLastPos = -1;
|
||||
@@ -785,6 +782,7 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
private final HashMap<Integer, PowerForUid> mUidToPower = ENABLE_FOREGROUND_STATS_COLLECTION
|
||||
? new HashMap<>() : null;
|
||||
|
||||
@NonNull
|
||||
final BatteryStatsHistory mBatteryStatsHistory;
|
||||
|
||||
final HistoryItem mHistoryCur = new HistoryItem();
|
||||
@@ -827,9 +825,9 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
long mCurStepStatSoftIrqTimeMs;
|
||||
long mCurStepStatIdleTimeMs;
|
||||
|
||||
private BatteryStatsHistoryIterator mBatteryStatsHistoryIterator;
|
||||
private HistoryItem mHistoryIterator;
|
||||
private boolean mReadOverflow;
|
||||
private boolean mIteratingHistory;
|
||||
|
||||
int mStartCount;
|
||||
|
||||
@@ -1193,7 +1191,7 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
mStatsFile = null;
|
||||
mCheckinFile = null;
|
||||
mDailyFile = null;
|
||||
mBatteryStatsHistory = null;
|
||||
mBatteryStatsHistory = new BatteryStatsHistory(mHistoryBuffer);
|
||||
mHandler = null;
|
||||
mPlatformIdleStateCallback = null;
|
||||
mMeasuredEnergyRetriever = null;
|
||||
@@ -3240,17 +3238,6 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
return idx;
|
||||
}
|
||||
|
||||
private void readHistoryTag(int index, HistoryTag tag) {
|
||||
if (index < mReadHistoryStrings.length) {
|
||||
tag.string = mReadHistoryStrings[index];
|
||||
tag.uid = mReadHistoryUids[index];
|
||||
} else {
|
||||
tag.string = null;
|
||||
tag.uid = 0;
|
||||
}
|
||||
tag.poolIdx = index;
|
||||
}
|
||||
|
||||
/*
|
||||
The history delta format uses flags to denote further data in subsequent ints in the parcel.
|
||||
|
||||
@@ -3627,137 +3614,6 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
mLastStepStatIdleTimeMs = mCurStepStatIdleTimeMs;
|
||||
}
|
||||
|
||||
public void readHistoryDelta(Parcel src, HistoryItem cur) {
|
||||
int firstToken = src.readInt();
|
||||
int deltaTimeToken = firstToken&DELTA_TIME_MASK;
|
||||
cur.cmd = HistoryItem.CMD_UPDATE;
|
||||
cur.numReadInts = 1;
|
||||
if (DEBUG) Slog.i(TAG, "READ DELTA: firstToken=0x" + Integer.toHexString(firstToken)
|
||||
+ " deltaTimeToken=" + deltaTimeToken);
|
||||
|
||||
if (deltaTimeToken < DELTA_TIME_ABS) {
|
||||
cur.time += deltaTimeToken;
|
||||
} else if (deltaTimeToken == DELTA_TIME_ABS) {
|
||||
cur.readFromParcel(src);
|
||||
if (DEBUG) Slog.i(TAG, "READ DELTA: ABS time=" + cur.time);
|
||||
return;
|
||||
} else if (deltaTimeToken == 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&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&DELTA_STATE_FLAG) != 0) {
|
||||
int stateInt = src.readInt();
|
||||
cur.states = (firstToken&DELTA_STATE_MASK) | (stateInt&(~STATE_BATTERY_MASK));
|
||||
cur.batteryStatus = (byte)((stateInt>>STATE_BATTERY_STATUS_SHIFT)
|
||||
& STATE_BATTERY_STATUS_MASK);
|
||||
cur.batteryHealth = (byte)((stateInt>>STATE_BATTERY_HEALTH_SHIFT)
|
||||
& STATE_BATTERY_HEALTH_MASK);
|
||||
cur.batteryPlugType = (byte)((stateInt>>STATE_BATTERY_PLUG_SHIFT)
|
||||
& 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&DELTA_STATE_MASK) | (cur.states&(~STATE_BATTERY_MASK));
|
||||
}
|
||||
|
||||
if ((firstToken&DELTA_STATE2_FLAG) != 0) {
|
||||
cur.states2 = src.readInt();
|
||||
if (DEBUG) Slog.i(TAG, "READ DELTA: states2=0x"
|
||||
+ Integer.toHexString(cur.states2));
|
||||
}
|
||||
|
||||
if ((firstToken&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&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 = HistoryItem.EVENT_NONE;
|
||||
}
|
||||
|
||||
if ((batteryLevelInt&BATTERY_DELTA_LEVEL_FLAG) != 0) {
|
||||
cur.stepDetails = mReadHistoryStepDetails;
|
||||
cur.stepDetails.readFromParcel(src);
|
||||
} else {
|
||||
cur.stepDetails = null;
|
||||
}
|
||||
|
||||
if ((firstToken&DELTA_BATTERY_CHARGE_FLAG) != 0) {
|
||||
cur.batteryChargeUah = src.readInt();
|
||||
}
|
||||
cur.modemRailChargeMah = src.readDouble();
|
||||
cur.wifiRailChargeMah = src.readDouble();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void commitCurrentHistoryBatchLocked() {
|
||||
mHistoryLastWritten.cmd = HistoryItem.CMD_NULL;
|
||||
@@ -3869,7 +3725,7 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
}
|
||||
|
||||
private void addHistoryBufferLocked(long elapsedRealtimeMs, byte cmd, HistoryItem cur) {
|
||||
if (mIteratingHistory) {
|
||||
if (mBatteryStatsHistoryIterator != null) {
|
||||
throw new IllegalStateException("Can't do this while iterating history!");
|
||||
}
|
||||
mHistoryBufferLastPos = mHistoryBuffer.dataPosition();
|
||||
@@ -10680,7 +10536,7 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
|
||||
if (systemDir == null) {
|
||||
mStatsFile = null;
|
||||
mBatteryStatsHistory = new BatteryStatsHistory(this, mHistoryBuffer);
|
||||
mBatteryStatsHistory = new BatteryStatsHistory(mHistoryBuffer);
|
||||
} else {
|
||||
mStatsFile = new AtomicFile(new File(systemDir, "batterystats.bin"));
|
||||
mBatteryStatsHistory = new BatteryStatsHistory(this, systemDir, mHistoryBuffer);
|
||||
@@ -10802,7 +10658,7 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
mExternalSync = null;
|
||||
mConstants = new Constants(mHandler);
|
||||
clearHistoryLocked();
|
||||
mBatteryStatsHistory = new BatteryStatsHistory(this, mHistoryBuffer);
|
||||
mBatteryStatsHistory = new BatteryStatsHistory(mHistoryBuffer);
|
||||
readFromParcel(p);
|
||||
mPlatformIdleStateCallback = null;
|
||||
mMeasuredEnergyRetriever = null;
|
||||
@@ -11180,67 +11036,55 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
@Override
|
||||
@UnsupportedAppUsage
|
||||
public boolean startIteratingHistoryLocked() {
|
||||
mBatteryStatsHistory.startIteratingHistory();
|
||||
mReadOverflow = false;
|
||||
mIteratingHistory = true;
|
||||
mReadHistoryStrings = new String[mHistoryTagPool.size()];
|
||||
mReadHistoryUids = new int[mHistoryTagPool.size()];
|
||||
mReadHistoryChars = 0;
|
||||
for (HashMap.Entry<HistoryTag, Integer> ent : mHistoryTagPool.entrySet()) {
|
||||
final HistoryTag tag = ent.getKey();
|
||||
final int idx = ent.getValue();
|
||||
mReadHistoryStrings[idx] = tag.string;
|
||||
mReadHistoryUids[idx] = tag.uid;
|
||||
mReadHistoryChars += tag.string.length() + 1;
|
||||
}
|
||||
mBatteryStatsHistoryIterator = createBatteryStatsHistoryIterator();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an iterator for battery stats history.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public BatteryStatsHistoryIterator createBatteryStatsHistoryIterator() {
|
||||
ArrayList<HistoryTag> tags = new ArrayList<>(mHistoryTagPool.size());
|
||||
for (Map.Entry<HistoryTag, Integer> entry: mHistoryTagPool.entrySet()) {
|
||||
final HistoryTag tag = entry.getKey();
|
||||
tag.poolIdx = entry.getValue();
|
||||
tags.add(tag);
|
||||
}
|
||||
|
||||
return new BatteryStatsHistoryIterator(mBatteryStatsHistory, tags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHistoryStringPoolSize() {
|
||||
return mReadHistoryStrings.length;
|
||||
return mBatteryStatsHistoryIterator.getHistoryStringPoolSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHistoryStringPoolBytes() {
|
||||
// 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) + (mReadHistoryChars * 2);
|
||||
return mBatteryStatsHistoryIterator.getHistoryStringPoolBytes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHistoryTagPoolString(int index) {
|
||||
return mReadHistoryStrings[index];
|
||||
return mBatteryStatsHistoryIterator.getHistoryTagPoolString(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHistoryTagPoolUid(int index) {
|
||||
return mReadHistoryUids[index];
|
||||
return mBatteryStatsHistoryIterator.getHistoryTagPoolUid(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
@UnsupportedAppUsage
|
||||
public boolean getNextHistoryLocked(HistoryItem out) {
|
||||
Parcel p = mBatteryStatsHistory.getNextParcel(out);
|
||||
if (p == null) {
|
||||
return false;
|
||||
}
|
||||
final long lastRealtimeMs = out.time;
|
||||
final long lastWalltimeMs = out.currentTime;
|
||||
readHistoryDelta(p, out);
|
||||
if (out.cmd != HistoryItem.CMD_CURRENT_TIME
|
||||
&& out.cmd != HistoryItem.CMD_RESET && lastWalltimeMs != 0) {
|
||||
out.currentTime = lastWalltimeMs + (out.time - lastRealtimeMs);
|
||||
}
|
||||
return true;
|
||||
return mBatteryStatsHistoryIterator.next(out);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishIteratingHistoryLocked() {
|
||||
mBatteryStatsHistory.finishIteratingHistory();
|
||||
mIteratingHistory = false;
|
||||
mReadHistoryStrings = null;
|
||||
mReadHistoryUids = null;
|
||||
mBatteryStatsHistoryIterator = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,7 @@ import org.junit.runners.Suite;
|
||||
BatteryStatsDualTimerTest.class,
|
||||
BatteryStatsDurationTimerTest.class,
|
||||
BatteryStatsHelperTest.class,
|
||||
BatteryStatsHistoryIteratorTest.class,
|
||||
BatteryStatsHistoryTest.class,
|
||||
BatteryStatsImplTest.class,
|
||||
BatteryStatsNoteTest.class,
|
||||
|
||||
Reference in New Issue
Block a user