Merge "Statsd atom: Power Use"

This commit is contained in:
Adam Bookatz
2018-11-15 20:20:08 +00:00
committed by Android (Google) Code Review
8 changed files with 199 additions and 11 deletions

View File

@@ -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;
}

View File

@@ -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) {

View File

@@ -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.
*/

View File

@@ -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

View File

@@ -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);

View File

@@ -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" />

View File

@@ -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);

View File

@@ -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<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 @@ 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;