Use CursorWindow to hold BatteryConsumer data
Bug: 192004350
Test: atest BatteryUsageStatsProtoTests:BatteryUsageStatsPulledTest
atest FrameworksCoreTests:BatteryUsageStatsTest
Change-Id: I2a285de7ceeb2297ab950b114da45d537ad22706
This commit is contained in:
@@ -31,18 +31,23 @@ import java.io.PrintWriter;
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
public final class AggregateBatteryConsumer extends BatteryConsumer implements Parcelable {
|
||||
public final class AggregateBatteryConsumer extends BatteryConsumer {
|
||||
static final int CONSUMER_TYPE_AGGREGATE = 0;
|
||||
|
||||
private final double mConsumedPowerMah;
|
||||
static final int COLUMN_INDEX_SCOPE = BatteryConsumer.COLUMN_COUNT;
|
||||
static final int COLUMN_INDEX_CONSUMED_POWER = COLUMN_INDEX_SCOPE + 1;
|
||||
static final int COLUMN_COUNT = BatteryConsumer.COLUMN_COUNT + 2;
|
||||
|
||||
public AggregateBatteryConsumer(@NonNull Builder builder) {
|
||||
super(builder.mPowerComponentsBuilder.build());
|
||||
mConsumedPowerMah = builder.mConsumedPowerMah;
|
||||
AggregateBatteryConsumer(BatteryConsumerData data) {
|
||||
super(data);
|
||||
}
|
||||
|
||||
private AggregateBatteryConsumer(@NonNull Parcel source) {
|
||||
super(new PowerComponents(source));
|
||||
mConsumedPowerMah = source.readDouble();
|
||||
private AggregateBatteryConsumer(@NonNull Builder builder) {
|
||||
super(builder.mData, builder.mPowerComponentsBuilder.build());
|
||||
}
|
||||
|
||||
int getScope() {
|
||||
return mData.getInt(COLUMN_INDEX_SCOPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -50,32 +55,9 @@ public final class AggregateBatteryConsumer extends BatteryConsumer implements P
|
||||
mPowerComponents.dump(pw, skipEmptyComponents);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
dest.writeDouble(mConsumedPowerMah);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static final Creator<AggregateBatteryConsumer> CREATOR =
|
||||
new Creator<AggregateBatteryConsumer>() {
|
||||
public AggregateBatteryConsumer createFromParcel(@NonNull Parcel source) {
|
||||
return new AggregateBatteryConsumer(source);
|
||||
}
|
||||
|
||||
public AggregateBatteryConsumer[] newArray(int size) {
|
||||
return new AggregateBatteryConsumer[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public double getConsumedPower() {
|
||||
return mConsumedPowerMah;
|
||||
return mData.getDouble(COLUMN_INDEX_CONSUMED_POWER);
|
||||
}
|
||||
|
||||
/** Serializes this object to XML */
|
||||
@@ -83,7 +65,7 @@ public final class AggregateBatteryConsumer extends BatteryConsumer implements P
|
||||
@BatteryUsageStats.AggregateBatteryConsumerScope int scope) throws IOException {
|
||||
serializer.startTag(null, BatteryUsageStats.XML_TAG_AGGREGATE);
|
||||
serializer.attributeInt(null, BatteryUsageStats.XML_ATTR_SCOPE, scope);
|
||||
serializer.attributeDouble(null, BatteryUsageStats.XML_ATTR_POWER, mConsumedPowerMah);
|
||||
serializer.attributeDouble(null, BatteryUsageStats.XML_ATTR_POWER, getConsumedPower());
|
||||
mPowerComponents.writeToXml(serializer);
|
||||
serializer.endTag(null, BatteryUsageStats.XML_TAG_AGGREGATE);
|
||||
}
|
||||
@@ -119,17 +101,16 @@ public final class AggregateBatteryConsumer extends BatteryConsumer implements P
|
||||
* Builder for DeviceBatteryConsumer.
|
||||
*/
|
||||
public static final class Builder extends BaseBuilder<AggregateBatteryConsumer.Builder> {
|
||||
private double mConsumedPowerMah;
|
||||
|
||||
public Builder(@NonNull String[] customPowerComponentNames, boolean includePowerModels) {
|
||||
super(customPowerComponentNames, includePowerModels);
|
||||
public Builder(BatteryConsumer.BatteryConsumerData data, int scope) {
|
||||
super(data, CONSUMER_TYPE_AGGREGATE);
|
||||
data.putInt(COLUMN_INDEX_SCOPE, scope);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the total power included in this aggregate.
|
||||
*/
|
||||
public Builder setConsumedPower(double consumedPowerMah) {
|
||||
mConsumedPowerMah = consumedPowerMah;
|
||||
mData.putDouble(COLUMN_INDEX_CONSUMED_POWER, consumedPowerMah);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -137,7 +118,8 @@ public final class AggregateBatteryConsumer extends BatteryConsumer implements P
|
||||
* Adds power and usage duration from the supplied AggregateBatteryConsumer.
|
||||
*/
|
||||
public void add(AggregateBatteryConsumer aggregateBatteryConsumer) {
|
||||
mConsumedPowerMah += aggregateBatteryConsumer.mConsumedPowerMah;
|
||||
setConsumedPower(mData.getDouble(COLUMN_INDEX_CONSUMED_POWER)
|
||||
+ aggregateBatteryConsumer.getConsumedPower());
|
||||
mPowerComponentsBuilder.addPowerAndDuration(aggregateBatteryConsumer.mPowerComponents);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@ package android.os;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.database.CursorWindow;
|
||||
import android.util.Slog;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
@@ -32,6 +34,8 @@ import java.lang.annotation.RetentionPolicy;
|
||||
*/
|
||||
public abstract class BatteryConsumer {
|
||||
|
||||
private static final String TAG = "BatteryConsumer";
|
||||
|
||||
/**
|
||||
* Power usage component, describing the particular part of the system
|
||||
* responsible for power drain.
|
||||
@@ -147,12 +151,22 @@ public abstract class BatteryConsumer {
|
||||
*/
|
||||
public static final int POWER_MODEL_MEASURED_ENERGY = 2;
|
||||
|
||||
static final int COLUMN_INDEX_BATTERY_CONSUMER_TYPE = 0;
|
||||
static final int COLUMN_COUNT = 1;
|
||||
|
||||
protected final BatteryConsumerData mData;
|
||||
protected final PowerComponents mPowerComponents;
|
||||
|
||||
protected BatteryConsumer(@NonNull PowerComponents powerComponents) {
|
||||
protected BatteryConsumer(BatteryConsumerData data, @NonNull PowerComponents powerComponents) {
|
||||
mData = data;
|
||||
mPowerComponents = powerComponents;
|
||||
}
|
||||
|
||||
public BatteryConsumer(BatteryConsumerData data) {
|
||||
mData = data;
|
||||
mPowerComponents = new PowerComponents(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Total power consumed by this consumer, in mAh.
|
||||
*/
|
||||
@@ -192,11 +206,7 @@ public abstract class BatteryConsumer {
|
||||
}
|
||||
|
||||
public int getCustomPowerComponentCount() {
|
||||
return mPowerComponents.getCustomPowerComponentCount();
|
||||
}
|
||||
|
||||
void setCustomPowerComponentNames(String[] customPowerComponentNames) {
|
||||
mPowerComponents.setCustomPowerComponentNames(customPowerComponentNames);
|
||||
return mData.layout.customPowerComponentCount;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -231,10 +241,6 @@ public abstract class BatteryConsumer {
|
||||
return mPowerComponents.getUsageDurationForCustomComponentMillis(componentId);
|
||||
}
|
||||
|
||||
protected void writeToParcel(Parcel dest, int flags) {
|
||||
mPowerComponents.writeToParcel(dest, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the specified component. Intended for logging and debugging.
|
||||
*/
|
||||
@@ -318,13 +324,151 @@ public abstract class BatteryConsumer {
|
||||
return (long) (powerMah * (10 * 3600 / 1000) + 0.5);
|
||||
}
|
||||
|
||||
protected abstract static class BaseBuilder<T extends BaseBuilder<?>> {
|
||||
final PowerComponents.Builder mPowerComponentsBuilder;
|
||||
static class BatteryConsumerData {
|
||||
private final CursorWindow mCursorWindow;
|
||||
private final int mCursorRow;
|
||||
public final BatteryConsumerDataLayout layout;
|
||||
|
||||
public BaseBuilder(@NonNull String[] customPowerComponentNames,
|
||||
boolean includePowerModels) {
|
||||
mPowerComponentsBuilder = new PowerComponents.Builder(customPowerComponentNames,
|
||||
includePowerModels);
|
||||
BatteryConsumerData(CursorWindow cursorWindow, int cursorRow,
|
||||
BatteryConsumerDataLayout layout) {
|
||||
mCursorWindow = cursorWindow;
|
||||
mCursorRow = cursorRow;
|
||||
this.layout = layout;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static BatteryConsumerData create(CursorWindow cursorWindow,
|
||||
BatteryConsumerDataLayout layout) {
|
||||
int cursorRow = cursorWindow.getNumRows();
|
||||
if (!cursorWindow.allocRow()) {
|
||||
Slog.e(TAG, "Cannot allocate BatteryConsumerData: too many UIDs: " + cursorRow);
|
||||
cursorRow = -1;
|
||||
}
|
||||
return new BatteryConsumerData(cursorWindow, cursorRow, layout);
|
||||
}
|
||||
|
||||
void putInt(int columnIndex, int value) {
|
||||
if (mCursorRow == -1) {
|
||||
return;
|
||||
}
|
||||
mCursorWindow.putLong(value, mCursorRow, columnIndex);
|
||||
}
|
||||
|
||||
int getInt(int columnIndex) {
|
||||
if (mCursorRow == -1) {
|
||||
return 0;
|
||||
}
|
||||
return mCursorWindow.getInt(mCursorRow, columnIndex);
|
||||
}
|
||||
|
||||
void putDouble(int columnIndex, double value) {
|
||||
if (mCursorRow == -1) {
|
||||
return;
|
||||
}
|
||||
mCursorWindow.putDouble(value, mCursorRow, columnIndex);
|
||||
}
|
||||
|
||||
double getDouble(int columnIndex) {
|
||||
if (mCursorRow == -1) {
|
||||
return 0;
|
||||
}
|
||||
return mCursorWindow.getDouble(mCursorRow, columnIndex);
|
||||
}
|
||||
|
||||
void putLong(int columnIndex, long value) {
|
||||
if (mCursorRow == -1) {
|
||||
return;
|
||||
}
|
||||
mCursorWindow.putLong(value, mCursorRow, columnIndex);
|
||||
}
|
||||
|
||||
long getLong(int columnIndex) {
|
||||
if (mCursorRow == -1) {
|
||||
return 0;
|
||||
}
|
||||
return mCursorWindow.getLong(mCursorRow, columnIndex);
|
||||
}
|
||||
|
||||
void putString(int columnIndex, String value) {
|
||||
if (mCursorRow == -1) {
|
||||
return;
|
||||
}
|
||||
mCursorWindow.putString(value, mCursorRow, columnIndex);
|
||||
}
|
||||
|
||||
String getString(int columnIndex) {
|
||||
if (mCursorRow == -1) {
|
||||
return null;
|
||||
}
|
||||
return mCursorWindow.getString(mCursorRow, columnIndex);
|
||||
}
|
||||
}
|
||||
|
||||
static class BatteryConsumerDataLayout {
|
||||
public final String[] customPowerComponentNames;
|
||||
public final int customPowerComponentCount;
|
||||
public final boolean powerModelsIncluded;
|
||||
|
||||
public final int consumedPowerColumn;
|
||||
public final int firstConsumedPowerColumn;
|
||||
public final int firstCustomConsumedPowerColumn;
|
||||
public final int firstUsageDurationColumn;
|
||||
public final int firstCustomUsageDurationColumn;
|
||||
public final int firstPowerModelColumn;
|
||||
public final int columnCount;
|
||||
|
||||
private BatteryConsumerDataLayout(int firstColumn, String[] customPowerComponentNames,
|
||||
boolean powerModelsIncluded) {
|
||||
this.customPowerComponentNames = customPowerComponentNames;
|
||||
this.customPowerComponentCount = customPowerComponentNames.length;
|
||||
this.powerModelsIncluded = powerModelsIncluded;
|
||||
|
||||
int columnIndex = firstColumn;
|
||||
consumedPowerColumn = columnIndex++;
|
||||
|
||||
firstConsumedPowerColumn = columnIndex;
|
||||
columnIndex += BatteryConsumer.POWER_COMPONENT_COUNT;
|
||||
|
||||
firstCustomConsumedPowerColumn = columnIndex;
|
||||
columnIndex += customPowerComponentCount;
|
||||
|
||||
firstUsageDurationColumn = columnIndex;
|
||||
columnIndex += BatteryConsumer.POWER_COMPONENT_COUNT;
|
||||
|
||||
firstCustomUsageDurationColumn = columnIndex;
|
||||
columnIndex += customPowerComponentCount;
|
||||
|
||||
if (powerModelsIncluded) {
|
||||
firstPowerModelColumn = columnIndex;
|
||||
columnIndex += BatteryConsumer.POWER_COMPONENT_COUNT;
|
||||
} else {
|
||||
firstPowerModelColumn = -1;
|
||||
}
|
||||
|
||||
columnCount = columnIndex;
|
||||
}
|
||||
}
|
||||
|
||||
static BatteryConsumerDataLayout createBatteryConsumerDataLayout(
|
||||
String[] customPowerComponentNames, boolean includePowerModels) {
|
||||
int columnCount = BatteryConsumer.COLUMN_COUNT;
|
||||
columnCount = Math.max(columnCount, AggregateBatteryConsumer.COLUMN_COUNT);
|
||||
columnCount = Math.max(columnCount, UidBatteryConsumer.COLUMN_COUNT);
|
||||
columnCount = Math.max(columnCount, UserBatteryConsumer.COLUMN_COUNT);
|
||||
|
||||
return new BatteryConsumerDataLayout(columnCount, customPowerComponentNames,
|
||||
includePowerModels);
|
||||
}
|
||||
|
||||
protected abstract static class BaseBuilder<T extends BaseBuilder<?>> {
|
||||
protected final BatteryConsumer.BatteryConsumerData mData;
|
||||
protected final PowerComponents.Builder mPowerComponentsBuilder;
|
||||
|
||||
public BaseBuilder(BatteryConsumer.BatteryConsumerData data, int consumerType) {
|
||||
mData = data;
|
||||
data.putLong(COLUMN_INDEX_BATTERY_CONSUMER_TYPE, consumerType);
|
||||
|
||||
mPowerComponentsBuilder = new PowerComponents.Builder(data);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,6 +18,8 @@ package android.os;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.database.Cursor;
|
||||
import android.database.CursorWindow;
|
||||
import android.util.Range;
|
||||
import android.util.SparseArray;
|
||||
import android.util.TypedXmlPullParser;
|
||||
@@ -31,6 +33,7 @@ import com.android.internal.os.PowerCalculator;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.annotation.Retention;
|
||||
@@ -51,7 +54,7 @@ import java.util.List;
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final class BatteryUsageStats implements Parcelable {
|
||||
public final class BatteryUsageStats implements Parcelable, Closeable {
|
||||
|
||||
/**
|
||||
* Scope of battery stats included in a BatteryConsumer: the entire device, just
|
||||
@@ -110,6 +113,9 @@ public final class BatteryUsageStats implements Parcelable {
|
||||
static final String XML_ATTR_TIME_IN_FOREGROUND = "time_in_foreground";
|
||||
static final String XML_ATTR_TIME_IN_BACKGROUND = "time_in_background";
|
||||
|
||||
// We need about 700 bytes per UID
|
||||
private static final long BATTERY_CONSUMER_CURSOR_WINDOW_SIZE = 5_000 * 700;
|
||||
|
||||
private static final int STATSD_PULL_ATOM_MAX_BYTES = 45000;
|
||||
|
||||
private final int mDischargePercentage;
|
||||
@@ -122,11 +128,13 @@ public final class BatteryUsageStats implements Parcelable {
|
||||
private final long mBatteryTimeRemainingMs;
|
||||
private final long mChargeTimeRemainingMs;
|
||||
private final String[] mCustomPowerComponentNames;
|
||||
private final boolean mIncludesPowerModels;
|
||||
private final List<UidBatteryConsumer> mUidBatteryConsumers;
|
||||
private final List<UserBatteryConsumer> mUserBatteryConsumers;
|
||||
private final AggregateBatteryConsumer[] mAggregateBatteryConsumers;
|
||||
private final Parcel mHistoryBuffer;
|
||||
private final List<BatteryStats.HistoryTag> mHistoryTagPool;
|
||||
private CursorWindow mBatteryConsumersCursorWindow;
|
||||
|
||||
private BatteryUsageStats(@NonNull Builder builder) {
|
||||
mStatsStartTimestampMs = builder.mStatsStartTimestampMs;
|
||||
@@ -141,6 +149,8 @@ public final class BatteryUsageStats implements Parcelable {
|
||||
mBatteryTimeRemainingMs = builder.mBatteryTimeRemainingMs;
|
||||
mChargeTimeRemainingMs = builder.mChargeTimeRemainingMs;
|
||||
mCustomPowerComponentNames = builder.mCustomPowerComponentNames;
|
||||
mIncludesPowerModels = builder.mIncludePowerModels;
|
||||
mBatteryConsumersCursorWindow = builder.mBatteryConsumersCursorWindow;
|
||||
|
||||
double totalPowerMah = 0;
|
||||
final int uidBatteryConsumerCount = builder.mUidBatteryConsumerBuilders.size();
|
||||
@@ -309,38 +319,43 @@ public final class BatteryUsageStats implements Parcelable {
|
||||
mBatteryTimeRemainingMs = source.readLong();
|
||||
mChargeTimeRemainingMs = source.readLong();
|
||||
mCustomPowerComponentNames = source.readStringArray();
|
||||
mIncludesPowerModels = source.readBoolean();
|
||||
|
||||
mBatteryConsumersCursorWindow = CursorWindow.newFromParcel(source);
|
||||
BatteryConsumer.BatteryConsumerDataLayout dataLayout =
|
||||
BatteryConsumer.createBatteryConsumerDataLayout(mCustomPowerComponentNames,
|
||||
mIncludesPowerModels);
|
||||
|
||||
final int numRows = mBatteryConsumersCursorWindow.getNumRows();
|
||||
|
||||
mAggregateBatteryConsumers =
|
||||
new AggregateBatteryConsumer[AGGREGATE_BATTERY_CONSUMER_SCOPE_COUNT];
|
||||
for (int i = 0; i < AGGREGATE_BATTERY_CONSUMER_SCOPE_COUNT; i++) {
|
||||
mAggregateBatteryConsumers[i] =
|
||||
AggregateBatteryConsumer.CREATOR.createFromParcel(source);
|
||||
mAggregateBatteryConsumers[i].setCustomPowerComponentNames(mCustomPowerComponentNames);
|
||||
mUidBatteryConsumers = new ArrayList<>(numRows);
|
||||
mUserBatteryConsumers = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < numRows; i++) {
|
||||
final BatteryConsumer.BatteryConsumerData data =
|
||||
new BatteryConsumer.BatteryConsumerData(mBatteryConsumersCursorWindow, i,
|
||||
dataLayout);
|
||||
|
||||
int consumerType = mBatteryConsumersCursorWindow.getInt(i,
|
||||
BatteryConsumer.COLUMN_INDEX_BATTERY_CONSUMER_TYPE);
|
||||
switch (consumerType) {
|
||||
case AggregateBatteryConsumer.CONSUMER_TYPE_AGGREGATE: {
|
||||
final AggregateBatteryConsumer consumer = new AggregateBatteryConsumer(data);
|
||||
mAggregateBatteryConsumers[consumer.getScope()] = consumer;
|
||||
break;
|
||||
}
|
||||
case UidBatteryConsumer.CONSUMER_TYPE_UID: {
|
||||
mUidBatteryConsumers.add(new UidBatteryConsumer(data));
|
||||
break;
|
||||
}
|
||||
case UserBatteryConsumer.CONSUMER_TYPE_USER:
|
||||
mUserBatteryConsumers.add(new UserBatteryConsumer(data));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// UidBatteryConsumers are included as a blob to avoid a TransactionTooLargeException
|
||||
final Parcel blob = Parcel.obtain();
|
||||
final byte[] bytes = source.readBlob();
|
||||
blob.unmarshall(bytes, 0, bytes.length);
|
||||
blob.setDataPosition(0);
|
||||
|
||||
final int uidCount = blob.readInt();
|
||||
mUidBatteryConsumers = new ArrayList<>(uidCount);
|
||||
for (int i = 0; i < uidCount; i++) {
|
||||
final UidBatteryConsumer consumer =
|
||||
UidBatteryConsumer.CREATOR.createFromParcel(blob);
|
||||
consumer.setCustomPowerComponentNames(mCustomPowerComponentNames);
|
||||
mUidBatteryConsumers.add(consumer);
|
||||
}
|
||||
blob.recycle();
|
||||
|
||||
int userCount = source.readInt();
|
||||
mUserBatteryConsumers = new ArrayList<>(userCount);
|
||||
for (int i = 0; i < userCount; i++) {
|
||||
final UserBatteryConsumer consumer =
|
||||
UserBatteryConsumer.CREATOR.createFromParcel(source);
|
||||
consumer.setCustomPowerComponentNames(mCustomPowerComponentNames);
|
||||
mUserBatteryConsumers.add(consumer);
|
||||
}
|
||||
if (source.readBoolean()) {
|
||||
final byte[] historyBlob = source.readBlob();
|
||||
|
||||
@@ -374,26 +389,9 @@ public final class BatteryUsageStats implements Parcelable {
|
||||
dest.writeLong(mBatteryTimeRemainingMs);
|
||||
dest.writeLong(mChargeTimeRemainingMs);
|
||||
dest.writeStringArray(mCustomPowerComponentNames);
|
||||
for (int i = 0; i < AGGREGATE_BATTERY_CONSUMER_SCOPE_COUNT; i++) {
|
||||
mAggregateBatteryConsumers[i].writeToParcel(dest, flags);
|
||||
}
|
||||
dest.writeBoolean(mIncludesPowerModels);
|
||||
mBatteryConsumersCursorWindow.writeToParcel(dest, flags);
|
||||
|
||||
// UidBatteryConsumers are included as a blob, because each UidBatteryConsumer
|
||||
// takes > 300 bytes, so a typical number of UIDs in the system, 300 would result
|
||||
// in a 90 kB Parcel, which is not safe to pass in a binder transaction because
|
||||
// of the possibility of TransactionTooLargeException
|
||||
final Parcel blob = Parcel.obtain();
|
||||
blob.writeInt(mUidBatteryConsumers.size());
|
||||
for (int i = mUidBatteryConsumers.size() - 1; i >= 0; i--) {
|
||||
mUidBatteryConsumers.get(i).writeToParcel(blob, flags);
|
||||
}
|
||||
dest.writeBlob(blob.marshall());
|
||||
blob.recycle();
|
||||
|
||||
dest.writeInt(mUserBatteryConsumers.size());
|
||||
for (int i = mUserBatteryConsumers.size() - 1; i >= 0; i--) {
|
||||
mUserBatteryConsumers.get(i).writeToParcel(dest, flags);
|
||||
}
|
||||
if (mHistoryBuffer != null) {
|
||||
dest.writeBoolean(true);
|
||||
dest.writeBlob(mHistoryBuffer.marshall());
|
||||
@@ -682,8 +680,7 @@ public final class BatteryUsageStats implements Parcelable {
|
||||
i++;
|
||||
}
|
||||
|
||||
builder = new Builder(
|
||||
customComponentNames.toArray(new String[0]), true);
|
||||
builder = new Builder(customComponentNames.toArray(new String[0]), true);
|
||||
|
||||
builder.setStatsStartTimestamp(
|
||||
parser.getAttributeLong(null, XML_ATTR_START_TIMESTAMP));
|
||||
@@ -733,13 +730,29 @@ public final class BatteryUsageStats implements Parcelable {
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
mBatteryConsumersCursorWindow.close();
|
||||
mBatteryConsumersCursorWindow = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
if (mBatteryConsumersCursorWindow != null) {
|
||||
mBatteryConsumersCursorWindow.close();
|
||||
}
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for BatteryUsageStats.
|
||||
*/
|
||||
public static final class Builder {
|
||||
private final CursorWindow mBatteryConsumersCursorWindow;
|
||||
@NonNull
|
||||
private final String[] mCustomPowerComponentNames;
|
||||
private final boolean mIncludePowerModels;
|
||||
private final BatteryConsumer.BatteryConsumerDataLayout mBatteryConsumerDataLayout;
|
||||
private long mStatsStartTimestampMs;
|
||||
private long mStatsEndTimestampMs;
|
||||
private long mStatsDurationMs = -1;
|
||||
@@ -762,12 +775,22 @@ public final class BatteryUsageStats implements Parcelable {
|
||||
this(customPowerComponentNames, false);
|
||||
}
|
||||
|
||||
public Builder(@NonNull String[] customPowerComponentNames, boolean includePowerModels) {
|
||||
public Builder(@NonNull String[] customPowerComponentNames, boolean includePowerModels) {
|
||||
mBatteryConsumersCursorWindow =
|
||||
new CursorWindow(null, BATTERY_CONSUMER_CURSOR_WINDOW_SIZE);
|
||||
mBatteryConsumerDataLayout =
|
||||
BatteryConsumer.createBatteryConsumerDataLayout(customPowerComponentNames,
|
||||
includePowerModels);
|
||||
mBatteryConsumersCursorWindow.setNumColumns(mBatteryConsumerDataLayout.columnCount);
|
||||
|
||||
mCustomPowerComponentNames = customPowerComponentNames;
|
||||
mIncludePowerModels = includePowerModels;
|
||||
for (int i = 0; i < AGGREGATE_BATTERY_CONSUMER_SCOPE_COUNT; i++) {
|
||||
mAggregateBatteryConsumersBuilders[i] = new AggregateBatteryConsumer.Builder(
|
||||
customPowerComponentNames, includePowerModels);
|
||||
for (int scope = 0; scope < AGGREGATE_BATTERY_CONSUMER_SCOPE_COUNT; scope++) {
|
||||
final BatteryConsumer.BatteryConsumerData data =
|
||||
BatteryConsumer.BatteryConsumerData.create(mBatteryConsumersCursorWindow,
|
||||
mBatteryConsumerDataLayout);
|
||||
mAggregateBatteryConsumersBuilders[scope] =
|
||||
new AggregateBatteryConsumer.Builder(data, scope);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -892,8 +915,10 @@ public final class BatteryUsageStats implements Parcelable {
|
||||
int uid = batteryStatsUid.getUid();
|
||||
UidBatteryConsumer.Builder builder = mUidBatteryConsumerBuilders.get(uid);
|
||||
if (builder == null) {
|
||||
builder = new UidBatteryConsumer.Builder(mCustomPowerComponentNames,
|
||||
mIncludePowerModels, batteryStatsUid);
|
||||
final BatteryConsumer.BatteryConsumerData data =
|
||||
BatteryConsumer.BatteryConsumerData.create(mBatteryConsumersCursorWindow,
|
||||
mBatteryConsumerDataLayout);
|
||||
builder = new UidBatteryConsumer.Builder(data, batteryStatsUid);
|
||||
mUidBatteryConsumerBuilders.put(uid, builder);
|
||||
}
|
||||
return builder;
|
||||
@@ -908,8 +933,10 @@ public final class BatteryUsageStats implements Parcelable {
|
||||
public UidBatteryConsumer.Builder getOrCreateUidBatteryConsumerBuilder(int uid) {
|
||||
UidBatteryConsumer.Builder builder = mUidBatteryConsumerBuilders.get(uid);
|
||||
if (builder == null) {
|
||||
builder = new UidBatteryConsumer.Builder(mCustomPowerComponentNames,
|
||||
mIncludePowerModels, uid);
|
||||
final BatteryConsumer.BatteryConsumerData data =
|
||||
BatteryConsumer.BatteryConsumerData.create(mBatteryConsumersCursorWindow,
|
||||
mBatteryConsumerDataLayout);
|
||||
builder = new UidBatteryConsumer.Builder(data, uid);
|
||||
mUidBatteryConsumerBuilders.put(uid, builder);
|
||||
}
|
||||
return builder;
|
||||
@@ -923,8 +950,10 @@ public final class BatteryUsageStats implements Parcelable {
|
||||
public UserBatteryConsumer.Builder getOrCreateUserBatteryConsumerBuilder(int userId) {
|
||||
UserBatteryConsumer.Builder builder = mUserBatteryConsumerBuilders.get(userId);
|
||||
if (builder == null) {
|
||||
builder = new UserBatteryConsumer.Builder(mCustomPowerComponentNames,
|
||||
mIncludePowerModels, userId);
|
||||
final BatteryConsumer.BatteryConsumerData data =
|
||||
BatteryConsumer.BatteryConsumerData.create(mBatteryConsumersCursorWindow,
|
||||
mBatteryConsumerDataLayout);
|
||||
builder = new UserBatteryConsumer.Builder(data, userId);
|
||||
mUserBatteryConsumerBuilders.put(userId, builder);
|
||||
}
|
||||
return builder;
|
||||
@@ -988,5 +1017,38 @@ public final class BatteryUsageStats implements Parcelable {
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps raw contents of the cursor window for debugging.
|
||||
*/
|
||||
void dump(PrintWriter writer) {
|
||||
final int numRows = mBatteryConsumersCursorWindow.getNumRows();
|
||||
int numColumns = mBatteryConsumerDataLayout.columnCount;
|
||||
for (int i = 0; i < numRows; i++) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int j = 0; j < numColumns; j++) {
|
||||
final int type = mBatteryConsumersCursorWindow.getType(i, j);
|
||||
switch (type) {
|
||||
case Cursor.FIELD_TYPE_NULL:
|
||||
sb.append("null, ");
|
||||
break;
|
||||
case Cursor.FIELD_TYPE_INTEGER:
|
||||
sb.append(mBatteryConsumersCursorWindow.getInt(i, j)).append(", ");
|
||||
break;
|
||||
case Cursor.FIELD_TYPE_FLOAT:
|
||||
sb.append(mBatteryConsumersCursorWindow.getFloat(i, j)).append(", ");
|
||||
break;
|
||||
case Cursor.FIELD_TYPE_STRING:
|
||||
sb.append(mBatteryConsumersCursorWindow.getString(i, j)).append(", ");
|
||||
break;
|
||||
case Cursor.FIELD_TYPE_BLOB:
|
||||
sb.append("BLOB, ");
|
||||
break;
|
||||
}
|
||||
}
|
||||
sb.setLength(sb.length() - 2);
|
||||
writer.println(sb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,6 @@ import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Contains details of battery attribution data broken down to individual power drain types
|
||||
@@ -39,61 +38,21 @@ import java.util.Arrays;
|
||||
* @hide
|
||||
*/
|
||||
class PowerComponents {
|
||||
private static final int CUSTOM_POWER_COMPONENT_OFFSET = BatteryConsumer.POWER_COMPONENT_COUNT
|
||||
- BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID;
|
||||
|
||||
private final double mConsumedPowerMah;
|
||||
@NonNull
|
||||
private final double[] mPowerComponentsMah;
|
||||
@NonNull
|
||||
private final long[] mUsageDurationsMs;
|
||||
private final int mCustomPowerComponentCount;
|
||||
@Nullable
|
||||
private final byte[] mPowerModels;
|
||||
// Not written to Parcel and must be explicitly restored during the parent object's unparceling
|
||||
private String[] mCustomPowerComponentNames;
|
||||
private final BatteryConsumer.BatteryConsumerData mData;
|
||||
|
||||
PowerComponents(@NonNull Builder builder) {
|
||||
mCustomPowerComponentNames = builder.mCustomPowerComponentNames;
|
||||
mCustomPowerComponentCount = mCustomPowerComponentNames.length;
|
||||
mPowerComponentsMah = builder.mPowerComponentsMah;
|
||||
mUsageDurationsMs = builder.mUsageDurationsMs;
|
||||
mConsumedPowerMah = builder.getTotalPower();
|
||||
mPowerModels = builder.getPowerModels();
|
||||
mData = builder.mData;
|
||||
}
|
||||
|
||||
PowerComponents(@NonNull Parcel source) {
|
||||
mConsumedPowerMah = source.readDouble();
|
||||
mCustomPowerComponentCount = source.readInt();
|
||||
mPowerComponentsMah = source.createDoubleArray();
|
||||
mUsageDurationsMs = source.createLongArray();
|
||||
if (source.readBoolean()) {
|
||||
mPowerModels = new byte[BatteryConsumer.POWER_COMPONENT_COUNT];
|
||||
source.readByteArray(mPowerModels);
|
||||
} else {
|
||||
mPowerModels = null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Writes contents to Parcel */
|
||||
void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeDouble(mConsumedPowerMah);
|
||||
dest.writeInt(mCustomPowerComponentCount);
|
||||
dest.writeDoubleArray(mPowerComponentsMah);
|
||||
dest.writeLongArray(mUsageDurationsMs);
|
||||
if (mPowerModels != null) {
|
||||
dest.writeBoolean(true);
|
||||
dest.writeByteArray(mPowerModels);
|
||||
} else {
|
||||
dest.writeBoolean(false);
|
||||
}
|
||||
PowerComponents(BatteryConsumer.BatteryConsumerData data) {
|
||||
mData = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Total power consumed by this consumer, in mAh.
|
||||
*/
|
||||
public double getConsumedPower() {
|
||||
return mConsumedPowerMah;
|
||||
return mData.getDouble(mData.layout.consumedPowerColumn);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,11 +67,7 @@ class PowerComponents {
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupported power component ID: " + componentId);
|
||||
}
|
||||
try {
|
||||
return mPowerComponentsMah[componentId];
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
throw new IllegalArgumentException("Unsupported power component ID: " + componentId);
|
||||
}
|
||||
return mData.getDouble(mData.layout.firstConsumedPowerColumn + componentId);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -122,30 +77,20 @@ class PowerComponents {
|
||||
* @return Amount of consumed power in mAh.
|
||||
*/
|
||||
public double getConsumedPowerForCustomComponent(int componentId) {
|
||||
if (componentId >= BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID
|
||||
&& componentId < BatteryConsumer.LAST_CUSTOM_POWER_COMPONENT_ID) {
|
||||
try {
|
||||
return mPowerComponentsMah[CUSTOM_POWER_COMPONENT_OFFSET + componentId];
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupported custom power component ID: " + componentId);
|
||||
}
|
||||
final int index = componentId - BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID;
|
||||
if (index >= 0 && index < mData.layout.customPowerComponentCount) {
|
||||
return mData.getDouble(mData.layout.firstCustomConsumedPowerColumn + index);
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupported custom power component ID: " + componentId);
|
||||
}
|
||||
}
|
||||
|
||||
void setCustomPowerComponentNames(String[] customPowerComponentNames) {
|
||||
mCustomPowerComponentNames = customPowerComponentNames;
|
||||
}
|
||||
|
||||
public String getCustomPowerComponentName(int componentId) {
|
||||
if (componentId >= BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID
|
||||
&& componentId < BatteryConsumer.LAST_CUSTOM_POWER_COMPONENT_ID) {
|
||||
final int index = componentId - BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID;
|
||||
if (index >= 0 && index < mData.layout.customPowerComponentCount) {
|
||||
try {
|
||||
return mCustomPowerComponentNames[componentId
|
||||
- BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID];
|
||||
return mData.layout.customPowerComponentNames[index];
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupported custom power component ID: " + componentId);
|
||||
@@ -156,17 +101,13 @@ class PowerComponents {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasPowerModels() {
|
||||
return mPowerModels != null;
|
||||
}
|
||||
|
||||
@BatteryConsumer.PowerModel
|
||||
int getPowerModel(@BatteryConsumer.PowerComponent int component) {
|
||||
if (!hasPowerModels()) {
|
||||
int getPowerModel(@BatteryConsumer.PowerComponent int componentId) {
|
||||
if (!mData.layout.powerModelsIncluded) {
|
||||
throw new IllegalStateException(
|
||||
"Power model IDs were not requested in the BatteryUsageStatsQuery");
|
||||
}
|
||||
return mPowerModels[component];
|
||||
return mData.getInt(mData.layout.firstPowerModelColumn + componentId);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -181,11 +122,7 @@ class PowerComponents {
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupported power component ID: " + componentId);
|
||||
}
|
||||
try {
|
||||
return mUsageDurationsMs[componentId];
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
throw new IllegalArgumentException("Unsupported power component ID: " + componentId);
|
||||
}
|
||||
return mData.getLong(mData.layout.firstUsageDurationColumn + componentId);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -195,33 +132,13 @@ class PowerComponents {
|
||||
* @return Amount of time in milliseconds.
|
||||
*/
|
||||
public long getUsageDurationForCustomComponentMillis(int componentId) {
|
||||
if (componentId < BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID) {
|
||||
final int index = componentId - BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID;
|
||||
if (index >= 0 && index < mData.layout.customPowerComponentCount) {
|
||||
return mData.getLong(mData.layout.firstCustomUsageDurationColumn + index);
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupported custom power component ID: " + componentId);
|
||||
}
|
||||
try {
|
||||
return mUsageDurationsMs[CUSTOM_POWER_COMPONENT_OFFSET + componentId];
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupported custom power component ID: " + componentId);
|
||||
}
|
||||
}
|
||||
|
||||
public int getCustomPowerComponentCount() {
|
||||
return mCustomPowerComponentCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the largest usage duration among all power components.
|
||||
*/
|
||||
public long getMaxComponentUsageDurationMillis() {
|
||||
long max = 0;
|
||||
for (int i = mUsageDurationsMs.length - 1; i >= 0; i--) {
|
||||
if (mUsageDurationsMs[i] > max) {
|
||||
max = mUsageDurationsMs[i];
|
||||
}
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
public void dump(PrintWriter pw, boolean skipEmptyComponents) {
|
||||
@@ -232,13 +149,14 @@ class PowerComponents {
|
||||
if (skipEmptyComponents && componentPower == 0) {
|
||||
continue;
|
||||
}
|
||||
pw.print(separator); separator = " ";
|
||||
pw.print(separator);
|
||||
separator = " ";
|
||||
pw.print(BatteryConsumer.powerComponentIdToString(componentId));
|
||||
pw.print("=");
|
||||
PowerCalculator.printPowerMah(pw, componentPower);
|
||||
}
|
||||
|
||||
final int customComponentCount = getCustomPowerComponentCount();
|
||||
final int customComponentCount = mData.layout.customPowerComponentCount;
|
||||
for (int customComponentId = BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID;
|
||||
customComponentId < BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID
|
||||
+ customComponentCount;
|
||||
@@ -248,7 +166,8 @@ class PowerComponents {
|
||||
if (skipEmptyComponents && customComponentPower == 0) {
|
||||
continue;
|
||||
}
|
||||
pw.print(separator); separator = " ";
|
||||
pw.print(separator);
|
||||
separator = " ";
|
||||
pw.print(getCustomPowerComponentName(customComponentId));
|
||||
pw.print("=");
|
||||
PowerCalculator.printPowerMah(pw, customComponentPower);
|
||||
@@ -272,11 +191,10 @@ class PowerComponents {
|
||||
private boolean writeStatsProtoImpl(@Nullable ProtoOutputStream proto) {
|
||||
boolean interestingData = false;
|
||||
|
||||
for (int idx = 0; idx < mPowerComponentsMah.length; idx++) {
|
||||
final int componentId = idx < BatteryConsumer.POWER_COMPONENT_COUNT ?
|
||||
idx : idx - CUSTOM_POWER_COMPONENT_OFFSET;
|
||||
final long powerDeciCoulombs = convertMahToDeciCoulombs(mPowerComponentsMah[idx]);
|
||||
final long durationMs = mUsageDurationsMs[idx];
|
||||
for (int componentId = 0; componentId < BatteryConsumer.POWER_COMPONENT_COUNT;
|
||||
componentId++) {
|
||||
final long powerDeciCoulombs = convertMahToDeciCoulombs(getConsumedPower(componentId));
|
||||
final long durationMs = getUsageDurationMillis(componentId);
|
||||
|
||||
if (powerDeciCoulombs == 0 && durationMs == 0) {
|
||||
// No interesting data. Make sure not to even write the COMPONENT int.
|
||||
@@ -289,25 +207,49 @@ class PowerComponents {
|
||||
return true;
|
||||
}
|
||||
|
||||
final long token =
|
||||
proto.start(BatteryUsageStatsAtomsProto.BatteryConsumerData.POWER_COMPONENTS);
|
||||
proto.write(
|
||||
BatteryUsageStatsAtomsProto.BatteryConsumerData.PowerComponentUsage
|
||||
.COMPONENT,
|
||||
componentId);
|
||||
proto.write(
|
||||
BatteryUsageStatsAtomsProto.BatteryConsumerData.PowerComponentUsage
|
||||
.POWER_DECI_COULOMBS,
|
||||
powerDeciCoulombs);
|
||||
proto.write(
|
||||
BatteryUsageStatsAtomsProto.BatteryConsumerData.PowerComponentUsage
|
||||
.DURATION_MILLIS,
|
||||
durationMs);
|
||||
proto.end(token);
|
||||
writePowerComponent(proto, componentId, powerDeciCoulombs, durationMs);
|
||||
}
|
||||
for (int idx = 0; idx < mData.layout.customPowerComponentCount; idx++) {
|
||||
final int componentId = BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + idx;
|
||||
final long powerDeciCoulombs =
|
||||
convertMahToDeciCoulombs(getConsumedPowerForCustomComponent(componentId));
|
||||
final long durationMs = getUsageDurationForCustomComponentMillis(componentId);
|
||||
|
||||
if (powerDeciCoulombs == 0 && durationMs == 0) {
|
||||
// No interesting data. Make sure not to even write the COMPONENT int.
|
||||
continue;
|
||||
}
|
||||
|
||||
interestingData = true;
|
||||
if (proto == null) {
|
||||
// We're just asked whether there is data, not to actually write it. And there is.
|
||||
return true;
|
||||
}
|
||||
|
||||
writePowerComponent(proto, componentId, powerDeciCoulombs, durationMs);
|
||||
}
|
||||
return interestingData;
|
||||
}
|
||||
|
||||
private void writePowerComponent(ProtoOutputStream proto, int componentId,
|
||||
long powerDeciCoulombs, long durationMs) {
|
||||
final long token =
|
||||
proto.start(BatteryUsageStatsAtomsProto.BatteryConsumerData.POWER_COMPONENTS);
|
||||
proto.write(
|
||||
BatteryUsageStatsAtomsProto.BatteryConsumerData.PowerComponentUsage
|
||||
.COMPONENT,
|
||||
componentId);
|
||||
proto.write(
|
||||
BatteryUsageStatsAtomsProto.BatteryConsumerData.PowerComponentUsage
|
||||
.POWER_DECI_COULOMBS,
|
||||
powerDeciCoulombs);
|
||||
proto.write(
|
||||
BatteryUsageStatsAtomsProto.BatteryConsumerData.PowerComponentUsage
|
||||
.DURATION_MILLIS,
|
||||
durationMs);
|
||||
proto.end(token);
|
||||
}
|
||||
|
||||
void writeToXml(TypedXmlSerializer serializer) throws IOException {
|
||||
serializer.startTag(null, BatteryUsageStats.XML_TAG_POWER_COMPONENTS);
|
||||
for (int componentId = 0; componentId < BatteryConsumer.POWER_COMPONENT_COUNT;
|
||||
@@ -326,15 +268,15 @@ class PowerComponents {
|
||||
if (durationMs != 0) {
|
||||
serializer.attributeLong(null, BatteryUsageStats.XML_ATTR_DURATION, durationMs);
|
||||
}
|
||||
if (mPowerModels != null) {
|
||||
if (mData.layout.powerModelsIncluded) {
|
||||
serializer.attributeInt(null, BatteryUsageStats.XML_ATTR_MODEL,
|
||||
mPowerModels[componentId]);
|
||||
getPowerModel(componentId));
|
||||
}
|
||||
serializer.endTag(null, BatteryUsageStats.XML_TAG_COMPONENT);
|
||||
}
|
||||
|
||||
final int customComponentEnd =
|
||||
BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + mCustomPowerComponentCount;
|
||||
final int customComponentEnd = BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID
|
||||
+ mData.layout.customPowerComponentCount;
|
||||
for (int componentId = BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID;
|
||||
componentId < customComponentEnd;
|
||||
componentId++) {
|
||||
@@ -430,22 +372,15 @@ class PowerComponents {
|
||||
static final class Builder {
|
||||
private static final byte POWER_MODEL_UNINITIALIZED = -1;
|
||||
|
||||
private final double[] mPowerComponentsMah;
|
||||
private final String[] mCustomPowerComponentNames;
|
||||
private final long[] mUsageDurationsMs;
|
||||
private final byte[] mPowerModels;
|
||||
private final BatteryConsumer.BatteryConsumerData mData;
|
||||
|
||||
Builder(@NonNull String[] customPowerComponentNames, boolean includePowerModels) {
|
||||
mCustomPowerComponentNames = customPowerComponentNames;
|
||||
int powerComponentCount =
|
||||
BatteryConsumer.POWER_COMPONENT_COUNT + mCustomPowerComponentNames.length;
|
||||
mPowerComponentsMah = new double[powerComponentCount];
|
||||
mUsageDurationsMs = new long[powerComponentCount];
|
||||
if (includePowerModels) {
|
||||
mPowerModels = new byte[BatteryConsumer.POWER_COMPONENT_COUNT];
|
||||
Arrays.fill(mPowerModels, POWER_MODEL_UNINITIALIZED);
|
||||
} else {
|
||||
mPowerModels = null;
|
||||
Builder(BatteryConsumer.BatteryConsumerData data) {
|
||||
mData = data;
|
||||
if (mData.layout.powerModelsIncluded) {
|
||||
for (int i = 0; i < BatteryConsumer.POWER_COMPONENT_COUNT; i++) {
|
||||
mData.putLong(mData.layout.firstPowerModelColumn + i,
|
||||
POWER_MODEL_UNINITIALIZED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -463,15 +398,11 @@ class PowerComponents {
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupported power component ID: " + componentId);
|
||||
}
|
||||
try {
|
||||
mPowerComponentsMah[componentId] = componentPower;
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupported power component ID: " + componentId);
|
||||
}
|
||||
if (mPowerModels != null) {
|
||||
mPowerModels[componentId] = (byte) powerModel;
|
||||
mData.putDouble(mData.layout.firstConsumedPowerColumn + componentId, componentPower);
|
||||
if (mData.layout.powerModelsIncluded) {
|
||||
mData.putLong(mData.layout.firstPowerModelColumn + componentId, powerModel);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -483,19 +414,12 @@ class PowerComponents {
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setConsumedPowerForCustomComponent(int componentId, double componentPower) {
|
||||
if (componentId >= BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID
|
||||
&& componentId < BatteryConsumer.LAST_CUSTOM_POWER_COMPONENT_ID) {
|
||||
try {
|
||||
mPowerComponentsMah[CUSTOM_POWER_COMPONENT_OFFSET + componentId] =
|
||||
componentPower;
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupported custom power component ID: " + componentId);
|
||||
}
|
||||
} else {
|
||||
final int index = componentId - BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID;
|
||||
if (index < 0 || index >= mData.layout.customPowerComponentCount) {
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupported custom power component ID: " + componentId);
|
||||
}
|
||||
mData.putDouble(mData.layout.firstCustomConsumedPowerColumn + index, componentPower);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -513,12 +437,8 @@ class PowerComponents {
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupported power component ID: " + componentId);
|
||||
}
|
||||
try {
|
||||
mUsageDurationsMs[componentId] = componentUsageDurationMillis;
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupported power component ID: " + componentId);
|
||||
}
|
||||
mData.putLong(mData.layout.firstUsageDurationColumn + componentId,
|
||||
componentUsageDurationMillis);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -531,51 +451,67 @@ class PowerComponents {
|
||||
@NonNull
|
||||
public Builder setUsageDurationForCustomComponentMillis(int componentId,
|
||||
long componentUsageDurationMillis) {
|
||||
if (componentId < BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID) {
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupported custom power component ID: " + componentId);
|
||||
}
|
||||
try {
|
||||
mUsageDurationsMs[CUSTOM_POWER_COMPONENT_OFFSET + componentId] =
|
||||
componentUsageDurationMillis;
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
final int index = componentId - BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID;
|
||||
if (index < 0 || index >= mData.layout.customPowerComponentCount) {
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupported custom power component ID: " + componentId);
|
||||
}
|
||||
|
||||
mData.putLong(mData.layout.firstCustomUsageDurationColumn + index,
|
||||
componentUsageDurationMillis);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void addPowerAndDuration(PowerComponents.Builder other) {
|
||||
addPowerAndDuration(other.mPowerComponentsMah, other.mUsageDurationsMs,
|
||||
other.mPowerModels);
|
||||
addPowerAndDuration(other.mData);
|
||||
}
|
||||
|
||||
public void addPowerAndDuration(PowerComponents other) {
|
||||
addPowerAndDuration(other.mPowerComponentsMah, other.mUsageDurationsMs,
|
||||
other.mPowerModels);
|
||||
addPowerAndDuration(other.mData);
|
||||
}
|
||||
|
||||
private void addPowerAndDuration(double[] powerComponentsMah,
|
||||
long[] usageDurationsMs, byte[] powerModels) {
|
||||
if (mPowerComponentsMah.length != powerComponentsMah.length) {
|
||||
private void addPowerAndDuration(BatteryConsumer.BatteryConsumerData otherData) {
|
||||
if (mData.layout.customPowerComponentCount
|
||||
!= otherData.layout.customPowerComponentCount) {
|
||||
throw new IllegalArgumentException(
|
||||
"Number of power components does not match: " + powerComponentsMah.length
|
||||
+ ", expected: " + mPowerComponentsMah.length);
|
||||
"Number of power components does not match: "
|
||||
+ otherData.layout.customPowerComponentCount
|
||||
+ ", expected: " + mData.layout.customPowerComponentCount);
|
||||
}
|
||||
|
||||
for (int i = mPowerComponentsMah.length - 1; i >= 0; i--) {
|
||||
mPowerComponentsMah[i] += powerComponentsMah[i];
|
||||
for (int i = BatteryConsumer.POWER_COMPONENT_COUNT - 1; i >= 0; i--) {
|
||||
final int powerColumnIndex = mData.layout.firstConsumedPowerColumn + i;
|
||||
mData.putDouble(powerColumnIndex,
|
||||
mData.getDouble(powerColumnIndex)
|
||||
+ otherData.getDouble(powerColumnIndex));
|
||||
|
||||
final int durationColumnIndex = mData.layout.firstUsageDurationColumn + i;
|
||||
mData.putLong(durationColumnIndex,
|
||||
mData.getLong(durationColumnIndex)
|
||||
+ otherData.getLong(durationColumnIndex));
|
||||
}
|
||||
for (int i = mUsageDurationsMs.length - 1; i >= 0; i--) {
|
||||
mUsageDurationsMs[i] += usageDurationsMs[i];
|
||||
|
||||
for (int i = mData.layout.customPowerComponentCount - 1; i >= 0; i--) {
|
||||
final int powerColumnIndex = mData.layout.firstCustomConsumedPowerColumn + i;
|
||||
mData.putDouble(powerColumnIndex,
|
||||
mData.getDouble(powerColumnIndex) + otherData.getDouble(powerColumnIndex));
|
||||
|
||||
final int usageColumnIndex = mData.layout.firstCustomUsageDurationColumn + i;
|
||||
mData.putLong(usageColumnIndex,
|
||||
mData.getLong(usageColumnIndex) + otherData.getLong(usageColumnIndex)
|
||||
);
|
||||
}
|
||||
if (mPowerModels != null && powerModels != null) {
|
||||
for (int i = mPowerModels.length - 1; i >= 0; i--) {
|
||||
if (mPowerModels[i] == POWER_MODEL_UNINITIALIZED) {
|
||||
mPowerModels[i] = powerModels[i];
|
||||
} else if (mPowerModels[i] != powerModels[i]
|
||||
&& powerModels[i] != POWER_MODEL_UNINITIALIZED) {
|
||||
mPowerModels[i] = BatteryConsumer.POWER_MODEL_UNDEFINED;
|
||||
|
||||
if (mData.layout.powerModelsIncluded && otherData.layout.powerModelsIncluded) {
|
||||
for (int i = BatteryConsumer.POWER_COMPONENT_COUNT - 1; i >= 0; i--) {
|
||||
final int columnIndex = mData.layout.firstPowerModelColumn + i;
|
||||
int powerModel = mData.getInt(columnIndex);
|
||||
int otherPowerModel = otherData.getInt(columnIndex);
|
||||
if (powerModel == POWER_MODEL_UNINITIALIZED) {
|
||||
mData.putLong(columnIndex, otherPowerModel);
|
||||
} else if (powerModel != otherPowerModel
|
||||
&& otherPowerModel != POWER_MODEL_UNINITIALIZED) {
|
||||
mData.putLong(columnIndex, BatteryConsumer.POWER_MODEL_UNDEFINED);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -587,30 +523,34 @@ class PowerComponents {
|
||||
*/
|
||||
public double getTotalPower() {
|
||||
double totalPowerMah = 0;
|
||||
for (int i = mPowerComponentsMah.length - 1; i >= 0; i--) {
|
||||
totalPowerMah += mPowerComponentsMah[i];
|
||||
for (int componentId = 0; componentId < BatteryConsumer.POWER_COMPONENT_COUNT;
|
||||
componentId++) {
|
||||
totalPowerMah +=
|
||||
mData.getDouble(mData.layout.firstConsumedPowerColumn + componentId);
|
||||
}
|
||||
for (int i = 0; i < mData.layout.customPowerComponentCount; i++) {
|
||||
totalPowerMah += mData.getDouble(mData.layout.firstCustomConsumedPowerColumn + i);
|
||||
}
|
||||
return totalPowerMah;
|
||||
}
|
||||
|
||||
private byte[] getPowerModels() {
|
||||
if (mPowerModels == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] powerModels = new byte[mPowerModels.length];
|
||||
for (int i = mPowerModels.length - 1; i >= 0; i--) {
|
||||
powerModels[i] = mPowerModels[i] != POWER_MODEL_UNINITIALIZED ? mPowerModels[i]
|
||||
: BatteryConsumer.POWER_MODEL_UNDEFINED;
|
||||
}
|
||||
return powerModels;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a read-only object out of the Builder values.
|
||||
*/
|
||||
@NonNull
|
||||
public PowerComponents build() {
|
||||
mData.putDouble(mData.layout.consumedPowerColumn, getTotalPower());
|
||||
|
||||
if (mData.layout.powerModelsIncluded) {
|
||||
for (int i = BatteryConsumer.POWER_COMPONENT_COUNT - 1; i >= 0; i--) {
|
||||
final int powerModel = mData.getInt(mData.layout.firstPowerModelColumn + i);
|
||||
if (powerModel == POWER_MODEL_UNINITIALIZED) {
|
||||
mData.putInt(mData.layout.firstPowerModelColumn + i,
|
||||
BatteryConsumer.POWER_MODEL_UNDEFINED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new PowerComponents(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,9 @@ import java.lang.annotation.RetentionPolicy;
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final class UidBatteryConsumer extends BatteryConsumer implements Parcelable {
|
||||
public final class UidBatteryConsumer extends BatteryConsumer {
|
||||
|
||||
static final int CONSUMER_TYPE_UID = 1;
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({
|
||||
@@ -66,19 +68,27 @@ public final class UidBatteryConsumer extends BatteryConsumer implements Parcela
|
||||
*/
|
||||
public static final int STATE_BACKGROUND = 1;
|
||||
|
||||
private final int mUid;
|
||||
@Nullable
|
||||
private final String mPackageWithHighestDrain;
|
||||
private final long mTimeInForegroundMs;
|
||||
private final long mTimeInBackgroundMs;
|
||||
static final int COLUMN_INDEX_UID = BatteryConsumer.COLUMN_COUNT;
|
||||
static final int COLUMN_INDEX_PACKAGE_WITH_HIGHEST_DRAIN = COLUMN_INDEX_UID + 1;
|
||||
static final int COLUMN_INDEX_TIME_IN_FOREGROUND = COLUMN_INDEX_UID + 2;
|
||||
static final int COLUMN_INDEX_TIME_IN_BACKGROUND = COLUMN_INDEX_UID + 3;
|
||||
static final int COLUMN_COUNT = BatteryConsumer.COLUMN_COUNT + 4;
|
||||
|
||||
UidBatteryConsumer(BatteryConsumerData data) {
|
||||
super(data);
|
||||
}
|
||||
|
||||
private UidBatteryConsumer(@NonNull Builder builder) {
|
||||
super(builder.mData, builder.mPowerComponentsBuilder.build());
|
||||
}
|
||||
|
||||
public int getUid() {
|
||||
return mUid;
|
||||
return mData.getInt(COLUMN_INDEX_UID);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getPackageWithHighestDrain() {
|
||||
return mPackageWithHighestDrain;
|
||||
return mData.getString(COLUMN_INDEX_PACKAGE_WITH_HIGHEST_DRAIN);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -87,41 +97,13 @@ public final class UidBatteryConsumer extends BatteryConsumer implements Parcela
|
||||
public long getTimeInStateMs(@State int state) {
|
||||
switch (state) {
|
||||
case STATE_BACKGROUND:
|
||||
return mTimeInBackgroundMs;
|
||||
return mData.getInt(COLUMN_INDEX_TIME_IN_BACKGROUND);
|
||||
case STATE_FOREGROUND:
|
||||
return mTimeInForegroundMs;
|
||||
return mData.getInt(COLUMN_INDEX_TIME_IN_FOREGROUND);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private UidBatteryConsumer(@NonNull Builder builder) {
|
||||
super(builder.mPowerComponentsBuilder.build());
|
||||
mUid = builder.mUid;
|
||||
mPackageWithHighestDrain = builder.mPackageWithHighestDrain;
|
||||
mTimeInForegroundMs = builder.mTimeInForegroundMs;
|
||||
mTimeInBackgroundMs = builder.mTimeInBackgroundMs;
|
||||
}
|
||||
|
||||
private UidBatteryConsumer(@NonNull Parcel source) {
|
||||
super(new PowerComponents(source));
|
||||
mUid = source.readInt();
|
||||
mPackageWithHighestDrain = source.readString();
|
||||
mTimeInForegroundMs = source.readLong();
|
||||
mTimeInBackgroundMs = source.readLong();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the contents into a Parcel.
|
||||
*/
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
dest.writeInt(mUid);
|
||||
dest.writeString(mPackageWithHighestDrain);
|
||||
dest.writeLong(mTimeInForegroundMs);
|
||||
dest.writeLong(mTimeInBackgroundMs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(PrintWriter pw, boolean skipEmptyComponents) {
|
||||
final double consumedPower = getConsumedPower();
|
||||
@@ -134,20 +116,8 @@ public final class UidBatteryConsumer extends BatteryConsumer implements Parcela
|
||||
pw.print(" ) ");
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static final Creator<UidBatteryConsumer> CREATOR = new Creator<UidBatteryConsumer>() {
|
||||
public UidBatteryConsumer createFromParcel(@NonNull Parcel source) {
|
||||
return new UidBatteryConsumer(source);
|
||||
}
|
||||
|
||||
public UidBatteryConsumer[] newArray(int size) {
|
||||
return new UidBatteryConsumer[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
static UidBatteryConsumer create(BatteryConsumerData data) {
|
||||
return new UidBatteryConsumer(data);
|
||||
}
|
||||
|
||||
/** Serializes this object to XML */
|
||||
@@ -158,14 +128,15 @@ public final class UidBatteryConsumer extends BatteryConsumer implements Parcela
|
||||
|
||||
serializer.startTag(null, BatteryUsageStats.XML_TAG_UID);
|
||||
serializer.attributeInt(null, BatteryUsageStats.XML_ATTR_UID, getUid());
|
||||
if (!TextUtils.isEmpty(mPackageWithHighestDrain)) {
|
||||
final String packageWithHighestDrain = getPackageWithHighestDrain();
|
||||
if (!TextUtils.isEmpty(packageWithHighestDrain)) {
|
||||
serializer.attribute(null, BatteryUsageStats.XML_ATTR_HIGHEST_DRAIN_PACKAGE,
|
||||
mPackageWithHighestDrain);
|
||||
packageWithHighestDrain);
|
||||
}
|
||||
serializer.attributeLong(null, BatteryUsageStats.XML_ATTR_TIME_IN_FOREGROUND,
|
||||
mTimeInForegroundMs);
|
||||
getTimeInStateMs(STATE_FOREGROUND));
|
||||
serializer.attributeLong(null, BatteryUsageStats.XML_ATTR_TIME_IN_BACKGROUND,
|
||||
mTimeInBackgroundMs);
|
||||
getTimeInStateMs(STATE_BACKGROUND));
|
||||
mPowerComponents.writeToXml(serializer);
|
||||
serializer.endTag(null, BatteryUsageStats.XML_TAG_UID);
|
||||
}
|
||||
@@ -209,22 +180,20 @@ public final class UidBatteryConsumer extends BatteryConsumer implements Parcela
|
||||
private final BatteryStats.Uid mBatteryStatsUid;
|
||||
private final int mUid;
|
||||
private String mPackageWithHighestDrain = PACKAGE_NAME_UNINITIALIZED;
|
||||
public long mTimeInForegroundMs;
|
||||
public long mTimeInBackgroundMs;
|
||||
private boolean mExcludeFromBatteryUsageStats;
|
||||
|
||||
public Builder(@NonNull String[] customPowerComponentNames,
|
||||
boolean includePowerModels, @NonNull BatteryStats.Uid batteryStatsUid) {
|
||||
super(customPowerComponentNames, includePowerModels);
|
||||
public Builder(BatteryConsumerData data, @NonNull BatteryStats.Uid batteryStatsUid) {
|
||||
super(data, CONSUMER_TYPE_UID);
|
||||
mBatteryStatsUid = batteryStatsUid;
|
||||
mUid = batteryStatsUid.getUid();
|
||||
data.putLong(COLUMN_INDEX_UID, mUid);
|
||||
}
|
||||
|
||||
public Builder(@NonNull String[] customPowerComponentNames, boolean includePowerModels,
|
||||
int uid) {
|
||||
super(customPowerComponentNames, includePowerModels);
|
||||
public Builder(BatteryConsumerData data, int uid) {
|
||||
super(data, CONSUMER_TYPE_UID);
|
||||
mBatteryStatsUid = null;
|
||||
mUid = uid;
|
||||
data.putLong(COLUMN_INDEX_UID, mUid);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@@ -258,10 +227,10 @@ public final class UidBatteryConsumer extends BatteryConsumer implements Parcela
|
||||
public Builder setTimeInStateMs(@State int state, long timeInStateMs) {
|
||||
switch (state) {
|
||||
case STATE_FOREGROUND:
|
||||
mTimeInForegroundMs = timeInStateMs;
|
||||
mData.putLong(COLUMN_INDEX_TIME_IN_FOREGROUND, timeInStateMs);
|
||||
break;
|
||||
case STATE_BACKGROUND:
|
||||
mTimeInBackgroundMs = timeInStateMs;
|
||||
mData.putLong(COLUMN_INDEX_TIME_IN_BACKGROUND, timeInStateMs);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported state: " + state);
|
||||
@@ -282,13 +251,18 @@ public final class UidBatteryConsumer extends BatteryConsumer implements Parcela
|
||||
*/
|
||||
public Builder add(UidBatteryConsumer consumer) {
|
||||
mPowerComponentsBuilder.addPowerAndDuration(consumer.mPowerComponents);
|
||||
mTimeInBackgroundMs += consumer.mTimeInBackgroundMs;
|
||||
mTimeInForegroundMs += consumer.mTimeInForegroundMs;
|
||||
|
||||
setTimeInStateMs(STATE_FOREGROUND,
|
||||
mData.getLong(COLUMN_INDEX_TIME_IN_FOREGROUND)
|
||||
+ consumer.getTimeInStateMs(STATE_FOREGROUND));
|
||||
setTimeInStateMs(STATE_BACKGROUND,
|
||||
mData.getLong(COLUMN_INDEX_TIME_IN_BACKGROUND)
|
||||
+ consumer.getTimeInStateMs(STATE_BACKGROUND));
|
||||
|
||||
if (mPackageWithHighestDrain == PACKAGE_NAME_UNINITIALIZED) {
|
||||
mPackageWithHighestDrain = consumer.mPackageWithHighestDrain;
|
||||
mPackageWithHighestDrain = consumer.getPackageWithHighestDrain();
|
||||
} else if (!TextUtils.equals(mPackageWithHighestDrain,
|
||||
consumer.mPackageWithHighestDrain)) {
|
||||
consumer.getPackageWithHighestDrain())) {
|
||||
// Consider combining two UidBatteryConsumers with this distribution
|
||||
// of power drain between packages:
|
||||
// (package1=100, package2=10) and (package1=100, package2=101).
|
||||
@@ -317,6 +291,9 @@ public final class UidBatteryConsumer extends BatteryConsumer implements Parcela
|
||||
if (mPackageWithHighestDrain == PACKAGE_NAME_UNINITIALIZED) {
|
||||
mPackageWithHighestDrain = null;
|
||||
}
|
||||
if (mPackageWithHighestDrain != null) {
|
||||
mData.putString(COLUMN_INDEX_PACKAGE_WITH_HIGHEST_DRAIN, mPackageWithHighestDrain);
|
||||
}
|
||||
return new UidBatteryConsumer(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,37 +35,30 @@ import java.util.List;
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
public class UserBatteryConsumer extends BatteryConsumer implements Parcelable {
|
||||
private final int mUserId;
|
||||
public class UserBatteryConsumer extends BatteryConsumer {
|
||||
static final int CONSUMER_TYPE_USER = 2;
|
||||
|
||||
public int getUserId() {
|
||||
return mUserId;
|
||||
private static final int COLUMN_INDEX_USER_ID = BatteryConsumer.COLUMN_COUNT;
|
||||
|
||||
static final int COLUMN_COUNT = BatteryConsumer.COLUMN_COUNT + 1;
|
||||
|
||||
UserBatteryConsumer(BatteryConsumerData data) {
|
||||
super(data);
|
||||
}
|
||||
|
||||
private UserBatteryConsumer(@NonNull UserBatteryConsumer.Builder builder) {
|
||||
super(builder.mPowerComponentsBuilder.build());
|
||||
mUserId = builder.mUserId;
|
||||
super(builder.mData, builder.mPowerComponentsBuilder.build());
|
||||
}
|
||||
|
||||
private UserBatteryConsumer(Parcel in) {
|
||||
super(new PowerComponents(in));
|
||||
mUserId = in.readInt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the contents into a Parcel.
|
||||
*/
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
dest.writeInt(mUserId);
|
||||
public int getUserId() {
|
||||
return mData.getInt(COLUMN_INDEX_USER_ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(PrintWriter pw, boolean skipEmptyComponents) {
|
||||
final double consumedPower = getConsumedPower();
|
||||
pw.print("User ");
|
||||
pw.print(mUserId);
|
||||
pw.print(getUserId());
|
||||
pw.print(": ");
|
||||
PowerCalculator.printPowerMah(pw, consumedPower);
|
||||
pw.print(" ( ");
|
||||
@@ -73,24 +66,6 @@ public class UserBatteryConsumer extends BatteryConsumer implements Parcelable {
|
||||
pw.print(" ) ");
|
||||
}
|
||||
|
||||
public static final Creator<UserBatteryConsumer> CREATOR =
|
||||
new Creator<UserBatteryConsumer>() {
|
||||
@Override
|
||||
public UserBatteryConsumer createFromParcel(Parcel in) {
|
||||
return new UserBatteryConsumer(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserBatteryConsumer[] newArray(int size) {
|
||||
return new UserBatteryConsumer[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Serializes this object to XML */
|
||||
void writeToXml(TypedXmlSerializer serializer) throws IOException {
|
||||
if (getConsumedPower() == 0) {
|
||||
@@ -131,13 +106,11 @@ public class UserBatteryConsumer extends BatteryConsumer implements Parcelable {
|
||||
* Builder for UserBatteryConsumer.
|
||||
*/
|
||||
public static final class Builder extends BaseBuilder<Builder> {
|
||||
private final int mUserId;
|
||||
private List<UidBatteryConsumer.Builder> mUidBatteryConsumers;
|
||||
|
||||
Builder(@NonNull String[] customPowerComponentNames, boolean includePowerModels,
|
||||
int userId) {
|
||||
super(customPowerComponentNames, includePowerModels);
|
||||
mUserId = userId;
|
||||
Builder(BatteryConsumerData data, int userId) {
|
||||
super(data, CONSUMER_TYPE_USER);
|
||||
data.putLong(COLUMN_INDEX_USER_ID, userId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -234,8 +234,8 @@ public class BatteryUsageStatsPulledTest {
|
||||
final BatteryUsageStats.Builder builder =
|
||||
new BatteryUsageStats.Builder(new String[0]);
|
||||
// If not truncated, this BatteryUsageStats object would generate a proto buffer
|
||||
// larger than 70 Kb
|
||||
for (int i = 0; i < 20000; i++) {
|
||||
// significantly larger than 50 Kb
|
||||
for (int i = 0; i < 3000; i++) {
|
||||
BatteryStatsImpl.Uid mockUid = mock(BatteryStatsImpl.Uid.class);
|
||||
when(mockUid.getUid()).thenReturn(i);
|
||||
builder.getOrCreateUidBatteryConsumerBuilder(mockUid)
|
||||
@@ -246,7 +246,7 @@ public class BatteryUsageStatsPulledTest {
|
||||
}
|
||||
|
||||
// Add a UID with much larger battery footprint
|
||||
final int largeConsumerUid = 20001;
|
||||
final int largeConsumerUid = 3001;
|
||||
BatteryStatsImpl.Uid largeConsumerMockUid = mock(BatteryStatsImpl.Uid.class);
|
||||
when(largeConsumerMockUid.getUid()).thenReturn(largeConsumerUid);
|
||||
builder.getOrCreateUidBatteryConsumerBuilder(largeConsumerMockUid)
|
||||
@@ -256,7 +256,7 @@ public class BatteryUsageStatsPulledTest {
|
||||
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU, 400);
|
||||
|
||||
// Add a UID with much larger usage duration
|
||||
final int highUsageUid = 20002;
|
||||
final int highUsageUid = 3002;
|
||||
BatteryStatsImpl.Uid highUsageMockUid = mock(BatteryStatsImpl.Uid.class);
|
||||
when(highUsageMockUid.getUid()).thenReturn(highUsageUid);
|
||||
builder.getOrCreateUidBatteryConsumerBuilder(highUsageMockUid)
|
||||
|
||||
@@ -70,18 +70,15 @@ public class BatteryUsageStatsTest {
|
||||
@Test
|
||||
public void testParcelability_smallNumberOfUids() {
|
||||
final BatteryUsageStats outBatteryUsageStats = buildBatteryUsageStats1(true).build();
|
||||
final Parcel outParcel = Parcel.obtain();
|
||||
outParcel.writeParcelable(outBatteryUsageStats, 0);
|
||||
final byte[] bytes = outParcel.marshall();
|
||||
outParcel.recycle();
|
||||
final Parcel parcel = Parcel.obtain();
|
||||
parcel.writeParcelable(outBatteryUsageStats, 0);
|
||||
|
||||
assertThat(bytes.length).isLessThan(2000);
|
||||
assertThat(parcel.dataSize()).isLessThan(5000);
|
||||
|
||||
parcel.setDataPosition(0);
|
||||
|
||||
final Parcel inParcel = Parcel.obtain();
|
||||
inParcel.unmarshall(bytes, 0, bytes.length);
|
||||
inParcel.setDataPosition(0);
|
||||
final BatteryUsageStats inBatteryUsageStats =
|
||||
inParcel.readParcelable(getClass().getClassLoader());
|
||||
parcel.readParcelable(getClass().getClassLoader());
|
||||
assertThat(inBatteryUsageStats).isNotNull();
|
||||
assertBatteryUsageStats1(inBatteryUsageStats, true);
|
||||
}
|
||||
@@ -91,7 +88,7 @@ public class BatteryUsageStatsTest {
|
||||
final BatteryUsageStats.Builder builder =
|
||||
new BatteryUsageStats.Builder(new String[0]);
|
||||
|
||||
// Without the use of a blob, this BatteryUsageStats object would generate a Parcel
|
||||
// Without the use of a CursorWindow, this BatteryUsageStats object would generate a Parcel
|
||||
// larger than 64 Kb
|
||||
final int uidCount = 200;
|
||||
for (int i = 0; i < uidCount; i++) {
|
||||
@@ -108,8 +105,6 @@ public class BatteryUsageStatsTest {
|
||||
|
||||
assertThat(parcel.dataSize()).isLessThan(2000);
|
||||
|
||||
// This parcel cannot be marshaled because it contains a file descriptor.
|
||||
// Assuming that parcel marshaling works fine, let's just rewind the parcel.
|
||||
parcel.setDataPosition(0);
|
||||
|
||||
final BatteryUsageStats inBatteryUsageStats =
|
||||
|
||||
Reference in New Issue
Block a user