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
This commit is contained in:
@@ -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;
|
||||
}
|
||||
14
cmds/statsd/src/external/StatsPullerManager.cpp
vendored
14
cmds/statsd/src/external/StatsPullerManager.cpp
vendored
@@ -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) {
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user