Merge "Statsd atom: Power Use"
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 53d9673..244974d 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -192,6 +192,9 @@
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 @@
// 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 8378ae1..0e131cb 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -243,6 +243,20 @@
{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 72e1ab9..866bd9a 100644
--- a/core/java/android/os/StatsLogEventWrapper.java
+++ b/core/java/android/os/StatsLogEventWrapper.java
@@ -104,14 +104,6 @@
}
/**
- * 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 0baf73c..02c9542 100644
--- a/core/java/com/android/internal/os/BatterySipper.java
+++ b/core/java/com/android/internal/os/BatterySipper.java
@@ -130,6 +130,10 @@
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 e81f678..7467114 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.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 @@
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 68f24fb..a4c5ed2 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 a1a6d9f..04c4629 100644
--- a/libs/services/src/os/StatsLogEventWrapper.cpp
+++ b/libs/services/src/os/StatsLogEventWrapper.cpp
@@ -85,9 +85,6 @@
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 70220d8..3050409 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.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.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 @@
@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");
@@ -1449,6 +1456,73 @@
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,
@@ -1674,6 +1748,18 @@
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;