blob: 1871ac5074c90fecb6583e5a12dc6fa1fe3f0513 [file] [log] [blame]
/*
* 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;
public 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);
}
}