diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 53d967363765c..244974d137efd 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 8378ae15c1ef3..0e131cb6c8c98 100644 --- a/cmds/statsd/src/external/StatsPullerManager.cpp +++ b/cmds/statsd/src/external/StatsPullerManager.cpp @@ -243,6 +243,20 @@ const std::map 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 72e1ab9728469..866bd9a17f41c 100644 --- a/core/java/android/os/StatsLogEventWrapper.java +++ b/core/java/android/os/StatsLogEventWrapper.java @@ -103,14 +103,6 @@ public final class StatsLogEventWrapper implements Parcelable { mValues.add(val); } - /** - * Write a double value. - */ - public void writeDouble(double val) { - mTypes.add(EVENT_TYPE_DOUBLE); - mValues.add(val); - } - /** * Write a storage value. */ diff --git a/core/java/com/android/internal/os/BatterySipper.java b/core/java/com/android/internal/os/BatterySipper.java index 0baf73cc024aa..02c9542fa40d8 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 { 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 e81f6789185e3..7467114a75966 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 68f24fb7b6610..a4c5ed2ee30f1 100644 --- a/data/etc/platform.xml +++ b/data/etc/platform.xml @@ -173,6 +173,7 @@ + diff --git a/libs/services/src/os/StatsLogEventWrapper.cpp b/libs/services/src/os/StatsLogEventWrapper.cpp index a1a6d9fe0e22b..04c4629b54327 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 70220d8102afc..3050409e67f92 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"); @@ -1449,6 +1456,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 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 pulledData) { + final List 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 pulledData) { + final List 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 pulledData) { mStoragedUidIoStatsReader.readAbsolute((uid, fgCharsRead, fgCharsWrite, fgBytesRead, @@ -1674,6 +1748,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;