summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/os/BatteryUsageStats.java11
-rw-r--r--core/java/android/os/BatteryUsageStatsQuery.java25
-rw-r--r--core/java/com/android/internal/os/BatteryStatsHistory.java51
-rw-r--r--services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java8
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java67
5 files changed, 143 insertions, 19 deletions
diff --git a/core/java/android/os/BatteryUsageStats.java b/core/java/android/os/BatteryUsageStats.java
index f913fcfd56d4..86b8fad16275 100644
--- a/core/java/android/os/BatteryUsageStats.java
+++ b/core/java/android/os/BatteryUsageStats.java
@@ -161,6 +161,7 @@ public final class BatteryUsageStats implements Parcelable, Closeable {
private final List<UserBatteryConsumer> mUserBatteryConsumers;
private final AggregateBatteryConsumer[] mAggregateBatteryConsumers;
private final BatteryStatsHistory mBatteryStatsHistory;
+ private final long mPreferredHistoryDurationMs;
private final BatteryConsumer.BatteryConsumerDataLayout mBatteryConsumerDataLayout;
private CursorWindow mBatteryConsumersCursorWindow;
@@ -174,6 +175,7 @@ public final class BatteryUsageStats implements Parcelable, Closeable {
mDischargedPowerUpperBound = builder.mDischargedPowerUpperBoundMah;
mDischargeDurationMs = builder.mDischargeDurationMs;
mBatteryStatsHistory = builder.mBatteryStatsHistory;
+ mPreferredHistoryDurationMs = builder.mPreferredHistoryDurationMs;
mBatteryTimeRemainingMs = builder.mBatteryTimeRemainingMs;
mChargeTimeRemainingMs = builder.mChargeTimeRemainingMs;
mCustomPowerComponentNames = builder.mCustomPowerComponentNames;
@@ -402,8 +404,10 @@ public final class BatteryUsageStats implements Parcelable, Closeable {
if (source.readBoolean()) {
mBatteryStatsHistory = BatteryStatsHistory.createFromBatteryUsageStatsParcel(source);
+ mPreferredHistoryDurationMs = source.readLong();
} else {
mBatteryStatsHistory = null;
+ mPreferredHistoryDurationMs = 0;
}
}
@@ -428,7 +432,7 @@ public final class BatteryUsageStats implements Parcelable, Closeable {
if (mBatteryStatsHistory != null) {
dest.writeBoolean(true);
- mBatteryStatsHistory.writeToBatteryUsageStatsParcel(dest);
+ mBatteryStatsHistory.writeToBatteryUsageStatsParcel(dest, mPreferredHistoryDurationMs);
} else {
dest.writeBoolean(false);
}
@@ -919,6 +923,7 @@ public final class BatteryUsageStats implements Parcelable, Closeable {
private final SparseArray<UserBatteryConsumer.Builder> mUserBatteryConsumerBuilders =
new SparseArray<>();
private BatteryStatsHistory mBatteryStatsHistory;
+ private long mPreferredHistoryDurationMs;
public Builder(@NonNull String[] customPowerComponentNames) {
this(customPowerComponentNames, false, false, false, 0);
@@ -1092,8 +1097,10 @@ public final class BatteryUsageStats implements Parcelable, Closeable {
* Sets the parceled recent history.
*/
@NonNull
- public Builder setBatteryHistory(BatteryStatsHistory batteryStatsHistory) {
+ public Builder setBatteryHistory(BatteryStatsHistory batteryStatsHistory,
+ long preferredHistoryDurationMs) {
mBatteryStatsHistory = batteryStatsHistory;
+ mPreferredHistoryDurationMs = preferredHistoryDurationMs;
return this;
}
diff --git a/core/java/android/os/BatteryUsageStatsQuery.java b/core/java/android/os/BatteryUsageStatsQuery.java
index 6e67578fadc8..5aed39bd8fa6 100644
--- a/core/java/android/os/BatteryUsageStatsQuery.java
+++ b/core/java/android/os/BatteryUsageStatsQuery.java
@@ -25,6 +25,7 @@ import com.android.internal.os.MonotonicClock;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
+import java.util.concurrent.TimeUnit;
/**
* Query parameters for the {@link BatteryStatsManager#getBatteryUsageStats()} call.
@@ -77,6 +78,7 @@ public final class BatteryUsageStatsQuery implements Parcelable {
public static final int FLAG_BATTERY_USAGE_STATS_ACCUMULATED = 0x0080;
private static final long DEFAULT_MAX_STATS_AGE_MS = 5 * 60 * 1000;
+ private static final long DEFAULT_PREFERRED_HISTORY_DURATION_MS = TimeUnit.HOURS.toMillis(2);
private final int mFlags;
@NonNull
@@ -89,6 +91,7 @@ public final class BatteryUsageStatsQuery implements Parcelable {
private long mMonotonicEndTime;
private final double mMinConsumedPowerThreshold;
private final @BatteryConsumer.PowerComponentId int[] mPowerComponents;
+ private final long mPreferredHistoryDurationMs;
private BatteryUsageStatsQuery(@NonNull Builder builder) {
mFlags = builder.mFlags;
@@ -101,6 +104,7 @@ public final class BatteryUsageStatsQuery implements Parcelable {
mMonotonicStartTime = builder.mMonotonicStartTime;
mMonotonicEndTime = builder.mMonotonicEndTime;
mPowerComponents = builder.mPowerComponents;
+ mPreferredHistoryDurationMs = builder.mPreferredHistoryDurationMs;
}
@BatteryUsageStatsFlags
@@ -197,6 +201,13 @@ public final class BatteryUsageStatsQuery implements Parcelable {
return mAggregatedToTimestamp;
}
+ /**
+ * Returns the preferred duration of battery history (tail) to be included in the query result.
+ */
+ public long getPreferredHistoryDurationMs() {
+ return mPreferredHistoryDurationMs;
+ }
+
@Override
public String toString() {
return "BatteryUsageStatsQuery{"
@@ -209,6 +220,7 @@ public final class BatteryUsageStatsQuery implements Parcelable {
+ ", mMonotonicEndTime=" + mMonotonicEndTime
+ ", mMinConsumedPowerThreshold=" + mMinConsumedPowerThreshold
+ ", mPowerComponents=" + Arrays.toString(mPowerComponents)
+ + ", mMaxHistoryDurationMs=" + mPreferredHistoryDurationMs
+ '}';
}
@@ -223,6 +235,7 @@ public final class BatteryUsageStatsQuery implements Parcelable {
mAggregatedFromTimestamp = in.readLong();
mAggregatedToTimestamp = in.readLong();
mPowerComponents = in.createIntArray();
+ mPreferredHistoryDurationMs = in.readLong();
}
@Override
@@ -237,6 +250,7 @@ public final class BatteryUsageStatsQuery implements Parcelable {
dest.writeLong(mAggregatedFromTimestamp);
dest.writeLong(mAggregatedToTimestamp);
dest.writeIntArray(mPowerComponents);
+ dest.writeLong(mPreferredHistoryDurationMs);
}
@Override
@@ -271,6 +285,7 @@ public final class BatteryUsageStatsQuery implements Parcelable {
private long mAggregateToTimestamp;
private double mMinConsumedPowerThreshold = 0;
private @BatteryConsumer.PowerComponentId int[] mPowerComponents;
+ private long mPreferredHistoryDurationMs = DEFAULT_PREFERRED_HISTORY_DURATION_MS;
/**
* Builds a read-only BatteryUsageStatsQuery object.
@@ -311,6 +326,16 @@ public final class BatteryUsageStatsQuery implements Parcelable {
}
/**
+ * Set the preferred amount of battery history to be included in the result, provided
+ * that `includeBatteryHistory` is also called. The actual amount of history included in
+ * the result may vary for performance reasons and may exceed the specified preference.
+ */
+ public Builder setPreferredHistoryDurationMs(long preferredHistoryDurationMs) {
+ mPreferredHistoryDurationMs = preferredHistoryDurationMs;
+ return this;
+ }
+
+ /**
* Requests that per-process state data be included in the BatteryUsageStats, if
* available. Check {@link BatteryUsageStats#isProcessStateDataIncluded()} on the result
* to see if the data is available.
diff --git a/core/java/com/android/internal/os/BatteryStatsHistory.java b/core/java/com/android/internal/os/BatteryStatsHistory.java
index dc440e36ca0d..f49c5f1c2b0f 100644
--- a/core/java/com/android/internal/os/BatteryStatsHistory.java
+++ b/core/java/com/android/internal/os/BatteryStatsHistory.java
@@ -84,7 +84,7 @@ public class BatteryStatsHistory {
private static final String TAG = "BatteryStatsHistory";
// Current on-disk Parcel version. Must be updated when the format of the parcelable changes
- private static final int VERSION = 211;
+ private static final int VERSION = 212;
private static final String HISTORY_DIR = "battery-history";
private static final String FILE_SUFFIX = ".bh";
@@ -211,6 +211,8 @@ public class BatteryStatsHistory {
private final MonotonicClock mMonotonicClock;
// Monotonic time when we started writing to the history buffer
private long mHistoryBufferStartTime;
+ // Monotonic time when the last event was written to the history buffer
+ private long mHistoryMonotonicEndTime;
// Monotonically increasing size of written history
private long mMonotonicHistorySize;
private final ArraySet<PowerStats.Descriptor> mWrittenPowerStatsDescriptors = new ArraySet<>();
@@ -423,13 +425,22 @@ public class BatteryStatsHistory {
return file;
}
- void writeToParcel(Parcel out, boolean useBlobs) {
+ void writeToParcel(Parcel out, boolean useBlobs,
+ long preferredEarliestIncludedTimestampMs) {
Trace.traceBegin(TRACE_TAG_SYSTEM_SERVER, "BatteryStatsHistory.writeToParcel");
lock();
try {
final long start = SystemClock.uptimeMillis();
- out.writeInt(mHistoryFiles.size() - 1);
for (int i = 0; i < mHistoryFiles.size() - 1; i++) {
+ long monotonicEndTime = Long.MAX_VALUE;
+ if (i < mHistoryFiles.size() - 1) {
+ monotonicEndTime = mHistoryFiles.get(i + 1).monotonicTimeMs;
+ }
+
+ if (monotonicEndTime < preferredEarliestIncludedTimestampMs) {
+ continue;
+ }
+
AtomicFile file = mHistoryFiles.get(i).atomicFile;
byte[] raw = new byte[0];
try {
@@ -437,6 +448,8 @@ public class BatteryStatsHistory {
} catch (Exception e) {
Slog.e(TAG, "Error reading file " + file.getBaseFile().getPath(), e);
}
+
+ out.writeBoolean(true);
if (useBlobs) {
out.writeBlob(raw);
} else {
@@ -444,6 +457,7 @@ public class BatteryStatsHistory {
out.writeByteArray(raw);
}
}
+ out.writeBoolean(false);
if (DEBUG) {
Slog.d(TAG,
"writeToParcel duration ms:" + (SystemClock.uptimeMillis() - start));
@@ -634,6 +648,7 @@ public class BatteryStatsHistory {
mWritableHistory = writableHistory;
if (mWritableHistory != null) {
mMutable = false;
+ mHistoryMonotonicEndTime = mWritableHistory.mHistoryMonotonicEndTime;
}
if (historyBuffer != null) {
@@ -937,6 +952,8 @@ public class BatteryStatsHistory {
}
// skip monotonic time field.
p.readLong();
+ // skip monotonic end time field
+ p.readLong();
// skip monotonic size field
p.readLong();
@@ -996,6 +1013,8 @@ public class BatteryStatsHistory {
}
// skip monotonic time field.
out.readLong();
+ // skip monotonic end time field
+ out.readLong();
// skip monotonic size field
out.readLong();
return true;
@@ -1024,6 +1043,7 @@ public class BatteryStatsHistory {
p.setDataPosition(0);
p.readInt(); // Skip the version field
long monotonicTime = p.readLong();
+ p.readLong(); // Skip monotonic end time field
p.readLong(); // Skip monotonic size field
p.setDataPosition(pos);
return monotonicTime;
@@ -1086,7 +1106,10 @@ public class BatteryStatsHistory {
public void writeToParcel(Parcel out) {
synchronized (this) {
writeHistoryBuffer(out);
- writeToParcel(out, false /* useBlobs */);
+ /* useBlobs */
+ if (mHistoryDir != null) {
+ mHistoryDir.writeToParcel(out, false /* useBlobs */, 0);
+ }
}
}
@@ -1096,16 +1119,13 @@ public class BatteryStatsHistory {
*
* @param out the output parcel
*/
- public void writeToBatteryUsageStatsParcel(Parcel out) {
+ public void writeToBatteryUsageStatsParcel(Parcel out, long preferredHistoryDurationMs) {
synchronized (this) {
out.writeBlob(mHistoryBuffer.marshall());
- writeToParcel(out, true /* useBlobs */);
- }
- }
-
- private void writeToParcel(Parcel out, boolean useBlobs) {
- if (mHistoryDir != null) {
- mHistoryDir.writeToParcel(out, useBlobs);
+ if (mHistoryDir != null) {
+ mHistoryDir.writeToParcel(out, true /* useBlobs */,
+ mHistoryMonotonicEndTime - preferredHistoryDurationMs);
+ }
}
}
@@ -1166,8 +1186,7 @@ public class BatteryStatsHistory {
private void readFromParcel(Parcel in, boolean useBlobs) {
final long start = SystemClock.uptimeMillis();
mHistoryParcels = new ArrayList<>();
- final int count = in.readInt();
- for (int i = 0; i < count; i++) {
+ while (in.readBoolean()) {
byte[] temp = useBlobs ? in.readBlob() : in.createByteArray();
if (temp == null || temp.length == 0) {
continue;
@@ -2081,6 +2100,8 @@ public class BatteryStatsHistory {
*/
@GuardedBy("this")
private void writeHistoryDelta(Parcel dest, HistoryItem cur, HistoryItem last) {
+ mHistoryMonotonicEndTime = cur.time;
+
if (last == null || cur.cmd != HistoryItem.CMD_UPDATE) {
dest.writeInt(BatteryStatsHistory.DELTA_TIME_ABS);
cur.writeToParcel(dest, 0);
@@ -2396,6 +2417,7 @@ public class BatteryStatsHistory {
}
mHistoryBufferStartTime = in.readLong();
+ mHistoryMonotonicEndTime = in.readLong();
mMonotonicHistorySize = in.readLong();
mHistoryBuffer.setDataSize(0);
@@ -2424,6 +2446,7 @@ public class BatteryStatsHistory {
private void writeHistoryBuffer(Parcel out) {
out.writeInt(BatteryStatsHistory.VERSION);
out.writeLong(mHistoryBufferStartTime);
+ out.writeLong(mHistoryMonotonicEndTime);
out.writeLong(mMonotonicHistorySize);
out.writeInt(mHistoryBuffer.dataSize());
if (DEBUG) {
diff --git a/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java b/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java
index 977c6db66106..a5185a2139db 100644
--- a/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java
+++ b/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java
@@ -38,6 +38,7 @@ import com.android.internal.os.CpuScalingPolicies;
import com.android.internal.os.MonotonicClock;
import com.android.internal.os.PowerProfile;
import com.android.internal.util.ArrayUtils;
+import com.android.server.power.optimization.Flags;
import com.android.server.power.stats.BatteryStatsImpl.BatteryStatsSession;
import java.io.PrintWriter;
@@ -351,7 +352,7 @@ public class BatteryUsageStatsProvider {
accumulatedStats.endMonotonicTime = endMonotonicTime;
accumulatedStats.builder.setStatsEndTimestamp(endWallClockTime);
- accumulatedStats.builder.setStatsDuration(endWallClockTime - startMonotonicTime);
+ accumulatedStats.builder.setStatsDuration(endMonotonicTime - startMonotonicTime);
mPowerAttributor.estimatePowerConsumption(accumulatedStats.builder, session.getHistory(),
startMonotonicTime, endMonotonicTime);
@@ -403,7 +404,10 @@ public class BatteryUsageStatsProvider {
}
if ((query.getFlags()
& BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_HISTORY) != 0) {
- batteryUsageStatsBuilder.setBatteryHistory(session.getHistory().copy());
+ batteryUsageStatsBuilder.setBatteryHistory(session.getHistory().copy(),
+ Flags.extendedBatteryHistoryContinuousCollectionEnabled()
+ ? query.getPreferredHistoryDurationMs()
+ : Long.MAX_VALUE);
}
mPowerAttributor.estimatePowerConsumption(batteryUsageStatsBuilder, session.getHistory(),
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java
index d427c9d9ee37..e94ef5bb4871 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java
@@ -39,6 +39,8 @@ import android.os.Handler;
import android.os.Parcel;
import android.os.Process;
import android.os.UidBatteryConsumer;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.platform.test.ravenwood.RavenwoodRule;
import android.util.SparseLongArray;
@@ -49,6 +51,7 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.internal.os.BatteryStatsHistoryIterator;
import com.android.internal.os.MonotonicClock;
import com.android.internal.os.PowerProfile;
+import com.android.server.power.optimization.Flags;
import com.android.server.power.stats.processor.MultiStatePowerAttributor;
import org.junit.Before;
@@ -59,6 +62,7 @@ import org.junit.runner.RunWith;
import java.io.File;
import java.io.IOException;
import java.util.List;
+import java.util.concurrent.TimeUnit;
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -68,11 +72,14 @@ public class BatteryUsageStatsProviderTest {
.setProvideMainThread(true)
.build();
+ @Rule(order = 1)
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42;
private static final long MINUTE_IN_MS = 60 * 1000;
private static final double PRECISION = 0.00001;
- @Rule(order = 1)
+ @Rule(order = 2)
public final BatteryUsageStatsRule mStatsRule =
new BatteryUsageStatsRule(12345)
.createTempDirectory()
@@ -868,4 +875,62 @@ public class BatteryUsageStatsProviderTest {
stats.close();
}
+
+ @Test
+ @EnableFlags(Flags.FLAG_EXTENDED_BATTERY_HISTORY_CONTINUOUS_COLLECTION_ENABLED)
+ public void testIncludeSubsetOfHistory() throws IOException {
+ MockBatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
+ batteryStats.getHistory().setMaxHistoryBufferSize(100);
+ synchronized (batteryStats) {
+ batteryStats.setRecordAllHistoryLocked(true);
+ }
+ batteryStats.forceRecordAllHistory();
+ batteryStats.setNoAutoReset(true);
+
+ long lastIncludedEventTimestamp = 0;
+ String tag = "work work work work work work work work work work work work work work work";
+ for (int i = 1; i < 50; i++) {
+ mStatsRule.advanceTime(TimeUnit.MINUTES.toMillis(9));
+ synchronized (batteryStats) {
+ batteryStats.noteJobStartLocked(tag, 42);
+ }
+ mStatsRule.advanceTime(TimeUnit.MINUTES.toMillis(1));
+ synchronized (batteryStats) {
+ batteryStats.noteJobFinishLocked(tag, 42, 0);
+ }
+ lastIncludedEventTimestamp = mMonotonicClock.monotonicTime();
+ }
+
+ BatteryUsageStatsProvider provider = new BatteryUsageStatsProvider(mContext,
+ mock(PowerAttributor.class), mStatsRule.getPowerProfile(),
+ mStatsRule.getCpuScalingPolicies(), mock(PowerStatsStore.class), 0, mMockClock,
+ mMonotonicClock);
+
+ BatteryUsageStatsQuery query = new BatteryUsageStatsQuery.Builder()
+ .includeBatteryHistory()
+ .setPreferredHistoryDurationMs(TimeUnit.MINUTES.toMillis(20))
+ .build();
+ final BatteryUsageStats stats = provider.getBatteryUsageStats(batteryStats, query);
+ Parcel parcel = Parcel.obtain();
+ stats.writeToParcel(parcel, 0);
+ stats.close();
+
+ parcel.setDataPosition(0);
+ BatteryUsageStats actual = BatteryUsageStats.CREATOR.createFromParcel(parcel);
+
+ long firstIncludedEventTimestamp = 0;
+ try (BatteryStatsHistoryIterator it = actual.iterateBatteryStatsHistory()) {
+ BatteryStats.HistoryItem item;
+ while ((item = it.next()) != null) {
+ if (item.eventCode == BatteryStats.HistoryItem.EVENT_JOB_START) {
+ firstIncludedEventTimestamp = item.time;
+ break;
+ }
+ }
+ }
+ actual.close();
+
+ assertThat(firstIncludedEventTimestamp)
+ .isAtLeast(lastIncludedEventTimestamp - TimeUnit.MINUTES.toMillis(30));
+ }
}