summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBookatz <bookatz@google.com>2018-11-09 12:27:37 -0800
committerBookatz <bookatz@google.com>2018-11-14 18:13:58 -0800
commit75ee6042443bfe22dc779609697881fc83ed23db (patch)
tree3610691da91a8955408cfe4bc18c8fb2aa4e78e2
parente9f5e860547e7314c4c0e03fa4838c5b06164f5d (diff)
Statsd atom: Power Use
BatteryStats calculates power usage of the device and various components (such as apps). This information is used, e.g., in the battery panel of Settings. We now log it to statsd. It can be used for validating how good the information displayed in Settings is. In the long-term, it is likely not ideal for off-device calculations, since that can be hopefully estimated using statsd's raw data. Three atoms: one for the total power use, one for the power use of each uid, and one for each non-uid component. Since they will all likely be pulled together, StatsCompanionService will provide stale data for BatteryStats pulls called within a second of a previous BatteryStats pull. Also in this cl: Remove StatsLogEventWrapper.writeDouble. Statsd doesn't support actually writing doubles into its proto reports, so having this function is misleading (the data will get to statsd and then be completely ignored). It's less confusing if we don't pretend it does something. Change-Id: If80bab8ea938afa4632535bb88ff59879fbe8099 Fixes: 119111972 Test: cts-tradefed run cts-dev -m CtsStatsdHostTestCases -t android.cts.statsd.atom.UidAtomTests#testDeviceCalculatedPowerUse Test: cts-tradefed run cts-dev -m CtsStatsdHostTestCases -t android.cts.statsd.atom.UidAtomTests#testDeviceCalculatedPowerBlameUid Test: BatteryStatsHelperTest#testDrainTypesSyncedWithProto
-rw-r--r--cmds/statsd/src/atoms.proto63
-rw-r--r--cmds/statsd/src/external/StatsPullerManager.cpp14
-rw-r--r--core/java/android/os/StatsLogEventWrapper.java8
-rw-r--r--core/java/com/android/internal/os/BatterySipper.java4
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java31
-rw-r--r--data/etc/platform.xml1
-rw-r--r--libs/services/src/os/StatsLogEventWrapper.cpp3
-rw-r--r--services/core/java/com/android/server/stats/StatsCompanionService.java86
8 files changed, 199 insertions, 11 deletions
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 53d967363765..244974d137ef 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -192,6 +192,9 @@ message Atom {
NativeProcessMemoryState native_process_memory_state = 10036;
CpuTimePerThreadFreq cpu_time_per_thread_freq = 10037;
OnDevicePowerMeasurement on_device_power_measurement = 10038;
+ DeviceCalculatedPowerUse device_calculated_power_use = 10039;
+ DeviceCalculatedPowerBlameUid device_calculated_power_blame_uid = 10040;
+ DeviceCalculatedPowerBlameOther device_calculated_power_blame_other = 10041;
}
// DO NOT USE field numbers above 100,000 in AOSP.
@@ -3198,3 +3201,63 @@ message CpuTimePerThreadFreq {
// Time spent in frequency in milliseconds, since thread start.
optional uint32 time_millis = 7;
}
+
+/**
+ * Pulls on-device BatteryStats power use calculations for the overall device.
+ */
+message DeviceCalculatedPowerUse {
+ // Power used by the device in mAh, as computed by BatteryStats, since BatteryStats last reset
+ // (i.e. roughly since device was last significantly charged).
+ // Currently, this is BatteryStatsHelper.getComputedPower() (not getTotalPower()).
+ optional float computed_power_milli_amp_hours = 1;
+}
+
+/**
+ * Pulls on-device BatteryStats power use calculations broken down by uid.
+ * This atom should be complemented by DeviceCalculatedPowerBlameOther, which contains the power use
+ * that is attributed to non-uid items. They must all be included to get the total power use.
+ */
+message DeviceCalculatedPowerBlameUid {
+ // Uid being blamed. Note: isolated uids have already been mapped to host uid.
+ optional int32 uid = 1 [(is_uid) = true];
+
+ // Power used by this uid in mAh, as computed by BatteryStats, since BatteryStats last reset
+ // (i.e. roughly since device was last significantly charged).
+ optional float power_milli_amp_hours = 2;
+}
+
+/**
+ * Pulls on-device BatteryStats power use calculations that are not due to a uid, broken down by
+ * drain type.
+ * This atom should be complemented by DeviceCalculatedPowerBlameUid, which contains the blame that
+ * is attributed uids. They must all be included to get the total power use.
+ */
+message DeviceCalculatedPowerBlameOther {
+ // The type of item whose power use is being reported.
+ enum DrainType {
+ AMBIENT_DISPLAY = 0;
+ // reserved 1; reserved "APP"; // Logged instead in DeviceCalculatedPowerBlameUid.
+ BLUETOOTH = 2;
+ CAMERA = 3;
+ // Cell-standby
+ CELL = 4;
+ FLASHLIGHT = 5;
+ IDLE = 6;
+ MEMORY = 7;
+ // Amount that total computed drain exceeded the drain estimated using the
+ // battery level changes and capacity.
+ OVERCOUNTED = 8;
+ PHONE = 9;
+ SCREEN = 10;
+ // Amount that total computed drain was below the drain estimated using the
+ // battery level changes and capacity.
+ UNACCOUNTED = 11;
+ // reserved 12; reserved "USER"; // Entire drain for a user. This is NOT supported.
+ WIFI = 13;
+ }
+ optional DrainType drain_type = 1;
+
+ // Power used by this item in mAh, as computed by BatteryStats, since BatteryStats last reset
+ // (i.e. roughly since device was last significantly charged).
+ optional float power_milli_amp_hours = 2;
+} \ No newline at end of file
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index 8378ae15c1ef..0e131cb6c8c9 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -243,6 +243,20 @@ const std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = {
{2, 3, 4, 5, 6},
1 * NS_PER_SEC,
new StatsCompanionServicePuller(android::util::CPU_TIME_PER_THREAD_FREQ)}},
+ // DeviceCalculatedPowerUse.
+ {android::util::DEVICE_CALCULATED_POWER_USE,
+ {{}, {}, 1 * NS_PER_SEC,
+ new StatsCompanionServicePuller(android::util::DEVICE_CALCULATED_POWER_USE)}},
+ // DeviceCalculatedPowerBlameUid.
+ {android::util::DEVICE_CALCULATED_POWER_BLAME_UID,
+ {{}, {}, // BatteryStats already merged isolated with host ids so it's unnecessary here.
+ 1 * NS_PER_SEC,
+ new StatsCompanionServicePuller(android::util::DEVICE_CALCULATED_POWER_BLAME_UID)}},
+ // DeviceCalculatedPowerBlameOther.
+ {android::util::DEVICE_CALCULATED_POWER_BLAME_OTHER,
+ {{}, {},
+ 1 * NS_PER_SEC,
+ new StatsCompanionServicePuller(android::util::DEVICE_CALCULATED_POWER_BLAME_OTHER)}},
};
StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) {
diff --git a/core/java/android/os/StatsLogEventWrapper.java b/core/java/android/os/StatsLogEventWrapper.java
index 72e1ab972846..866bd9a17f41 100644
--- a/core/java/android/os/StatsLogEventWrapper.java
+++ b/core/java/android/os/StatsLogEventWrapper.java
@@ -104,14 +104,6 @@ public final class StatsLogEventWrapper implements Parcelable {
}
/**
- * Write a double value.
- */
- public void writeDouble(double val) {
- mTypes.add(EVENT_TYPE_DOUBLE);
- mValues.add(val);
- }
-
- /**
* Write a storage value.
*/
public void writeStorage(byte[] val) {
diff --git a/core/java/com/android/internal/os/BatterySipper.java b/core/java/com/android/internal/os/BatterySipper.java
index 0baf73cc024a..02c9542fa40d 100644
--- a/core/java/com/android/internal/os/BatterySipper.java
+++ b/core/java/com/android/internal/os/BatterySipper.java
@@ -130,6 +130,10 @@ public class BatterySipper implements Comparable<BatterySipper> {
public double wakeLockPowerMah;
public double wifiPowerMah;
+ // ****************
+ // This list must be kept current with atoms.proto (frameworks/base/cmds/statsd/src/atoms.proto)
+ // so the ordinal values (and therefore the order) must never change.
+ // ****************
public enum DrainType {
AMBIENT_DISPLAY,
@UnsupportedAppUsage
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java
index e81f6789185e..7467114a7596 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java
@@ -41,6 +41,7 @@ import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.text.format.DateUtils;
+import android.util.StatsLog;
import junit.framework.TestCase;
@@ -258,6 +259,36 @@ public class BatteryStatsHelperTest extends TestCase {
assertThat(time).isEqualTo(TIME_STATE_FOREGROUND_MS);
}
+ @Test
+ public void testDrainTypesSyncedWithProto() {
+ assertEquals(BatterySipper.DrainType.AMBIENT_DISPLAY.ordinal(),
+ StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__AMBIENT_DISPLAY);
+ // AtomsProto has no "APP"
+ assertEquals(BatterySipper.DrainType.BLUETOOTH.ordinal(),
+ StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__BLUETOOTH);
+ assertEquals(BatterySipper.DrainType.CAMERA.ordinal(),
+ StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__CAMERA);
+ assertEquals(BatterySipper.DrainType.CELL.ordinal(),
+ StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__CELL);
+ assertEquals(BatterySipper.DrainType.FLASHLIGHT.ordinal(),
+ StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__FLASHLIGHT);
+ assertEquals(BatterySipper.DrainType.IDLE.ordinal(),
+ StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__IDLE);
+ assertEquals(BatterySipper.DrainType.MEMORY.ordinal(),
+ StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__MEMORY);
+ assertEquals(BatterySipper.DrainType.OVERCOUNTED.ordinal(),
+ StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__OVERCOUNTED);
+ assertEquals(BatterySipper.DrainType.PHONE.ordinal(),
+ StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__PHONE);
+ assertEquals(BatterySipper.DrainType.SCREEN.ordinal(),
+ StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__SCREEN);
+ assertEquals(BatterySipper.DrainType.UNACCOUNTED.ordinal(),
+ StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__UNACCOUNTED);
+ // AtomsProto has no "USER"
+ assertEquals(BatterySipper.DrainType.WIFI.ordinal(),
+ StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__WIFI);
+ }
+
private BatterySipper createTestSmearBatterySipper(long activityTime, double totalPowerMah,
int uidCode, boolean isUidNull) {
final BatterySipper sipper = mock(BatterySipper.class);
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 68f24fb7b661..a4c5ed2ee30f 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -173,6 +173,7 @@
<assign-permission name="android.permission.ACCESS_LOWPAN_STATE" uid="lowpan" />
<assign-permission name="android.permission.MANAGE_LOWPAN_INTERFACES" uid="lowpan" />
+ <assign-permission name="android.permission.BATTERY_STATS" uid="statsd" />
<assign-permission name="android.permission.DUMP" uid="statsd" />
<assign-permission name="android.permission.PACKAGE_USAGE_STATS" uid="statsd" />
<assign-permission name="android.permission.STATSCOMPANION" uid="statsd" />
diff --git a/libs/services/src/os/StatsLogEventWrapper.cpp b/libs/services/src/os/StatsLogEventWrapper.cpp
index a1a6d9fe0e22..04c4629b5432 100644
--- a/libs/services/src/os/StatsLogEventWrapper.cpp
+++ b/libs/services/src/os/StatsLogEventWrapper.cpp
@@ -85,9 +85,6 @@ status_t StatsLogEventWrapper::readFromParcel(const Parcel* in) {
case StatsLogValue::FLOAT:
mElements.push_back(StatsLogValue(in->readFloat()));
break;
- case StatsLogValue::DOUBLE:
- mElements.push_back(StatsLogValue(in->readDouble()));
- break;
case StatsLogValue::STORAGE:
mElements.push_back(StatsLogValue());
mElements.back().setType(StatsLogValue::STORAGE);
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 01d02d61cc83..d111702e5bbb 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -47,6 +47,7 @@ import android.net.NetworkRequest;
import android.net.NetworkStats;
import android.net.wifi.IWifiManager;
import android.net.wifi.WifiActivityEnergyInfo;
+import android.os.BatteryStats;
import android.os.BatteryStatsInternal;
import android.os.Binder;
import android.os.Bundle;
@@ -87,6 +88,8 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.procstats.IProcessStats;
import com.android.internal.app.procstats.ProcessStats;
import com.android.internal.net.NetworkStatsFactory;
+import com.android.internal.os.BatterySipper;
+import com.android.internal.os.BatteryStatsHelper;
import com.android.internal.os.BinderCallsStats.ExportedCallStat;
import com.android.internal.os.KernelCpuSpeedReader;
import com.android.internal.os.KernelCpuThreadReader;
@@ -205,6 +208,10 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
@Nullable
private final KernelCpuThreadReader mKernelCpuThreadReader;
+ private BatteryStatsHelper mBatteryStatsHelper = null;
+ private static final int MAX_BATTERY_STATS_HELPER_FREQUENCY_MS = 1000;
+ private long mBatteryStatsHelperTimestampMs = -MAX_BATTERY_STATS_HELPER_FREQUENCY_MS;
+
private static IThermalService sThermalService;
private File mBaseDir =
new File(SystemServiceManager.ensureSystemDir(), "stats_companion");
@@ -1430,6 +1437,73 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
pulledData.add(e);
}
+ private BatteryStatsHelper getBatteryStatsHelper() {
+ if (mBatteryStatsHelper == null) {
+ final long callingToken = Binder.clearCallingIdentity();
+ try {
+ // clearCallingIdentity required for BatteryStatsHelper.checkWifiOnly().
+ mBatteryStatsHelper = new BatteryStatsHelper(mContext, false);
+ } finally {
+ Binder.restoreCallingIdentity(callingToken);
+ }
+ mBatteryStatsHelper.create((Bundle) null);
+ }
+ long currentTime = SystemClock.elapsedRealtime();
+ if (currentTime - mBatteryStatsHelperTimestampMs >= MAX_BATTERY_STATS_HELPER_FREQUENCY_MS) {
+ // Load BatteryStats and do all the calculations.
+ mBatteryStatsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, UserHandle.USER_ALL);
+ // Calculations are done so we don't need to save the raw BatteryStats data in RAM.
+ mBatteryStatsHelper.clearStats();
+ mBatteryStatsHelperTimestampMs = currentTime;
+ }
+ return mBatteryStatsHelper;
+ }
+
+ private void pullDeviceCalculatedPowerUse(int tagId,
+ long elapsedNanos, final long wallClockNanos, List<StatsLogEventWrapper> pulledData) {
+ BatteryStatsHelper bsHelper = getBatteryStatsHelper();
+ StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
+ e.writeFloat((float) bsHelper.getComputedPower());
+ pulledData.add(e);
+ }
+
+ private void pullDeviceCalculatedPowerBlameUid(int tagId,
+ long elapsedNanos, final long wallClockNanos, List<StatsLogEventWrapper> pulledData) {
+ final List<BatterySipper> sippers = getBatteryStatsHelper().getUsageList();
+ if (sippers == null) {
+ return;
+ }
+ for (BatterySipper bs : sippers) {
+ if (bs.drainType != bs.drainType.APP) {
+ continue;
+ }
+ StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
+ e.writeInt(bs.uidObj.getUid());
+ e.writeFloat((float) bs.totalPowerMah);
+ pulledData.add(e);
+ }
+ }
+
+ private void pullDeviceCalculatedPowerBlameOther(int tagId,
+ long elapsedNanos, final long wallClockNanos, List<StatsLogEventWrapper> pulledData) {
+ final List<BatterySipper> sippers = getBatteryStatsHelper().getUsageList();
+ if (sippers == null) {
+ return;
+ }
+ for (BatterySipper bs : sippers) {
+ if (bs.drainType == bs.drainType.APP) {
+ continue; // This is a separate atom; see pullDeviceCalculatedPowerBlameUid().
+ }
+ if (bs.drainType == bs.drainType.USER) {
+ continue; // This is not supported. We purposefully calculate over USER_ALL.
+ }
+ StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
+ e.writeInt(bs.drainType.ordinal());
+ e.writeFloat((float) bs.totalPowerMah);
+ pulledData.add(e);
+ }
+ }
+
private void pullDiskIo(int tagId, long elapsedNanos, final long wallClockNanos,
List<StatsLogEventWrapper> pulledData) {
mStoragedUidIoStatsReader.readAbsolute((uid, fgCharsRead, fgCharsWrite, fgBytesRead,
@@ -1655,6 +1729,18 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
pullCpuTimePerThreadFreq(tagId, elapsedNanos, wallClockNanos, ret);
break;
}
+ case StatsLog.DEVICE_CALCULATED_POWER_USE: {
+ pullDeviceCalculatedPowerUse(tagId, elapsedNanos, wallClockNanos, ret);
+ break;
+ }
+ case StatsLog.DEVICE_CALCULATED_POWER_BLAME_UID: {
+ pullDeviceCalculatedPowerBlameUid(tagId, elapsedNanos, wallClockNanos, ret);
+ break;
+ }
+ case StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER: {
+ pullDeviceCalculatedPowerBlameOther(tagId, elapsedNanos, wallClockNanos, ret);
+ break;
+ }
default:
Slog.w(TAG, "No such tagId data as " + tagId);
return null;