Loading services/core/java/com/android/server/am/BatteryStatsService.java +18 −0 Original line number Diff line number Diff line Loading @@ -124,6 +124,7 @@ import com.android.server.power.stats.BatteryExternalStatsWorker; import com.android.server.power.stats.BatteryStatsDumpHelperImpl; import com.android.server.power.stats.BatteryStatsImpl; import com.android.server.power.stats.BatteryUsageStatsProvider; import com.android.server.power.stats.BluetoothPowerStatsProcessor; import com.android.server.power.stats.CpuPowerStatsProcessor; import com.android.server.power.stats.MobileRadioPowerStatsProcessor; import com.android.server.power.stats.PhoneCallPowerStatsProcessor; Loading Loading @@ -502,6 +503,17 @@ public final class BatteryStatsService extends IBatteryStats.Stub AggregatedPowerStatsConfig.STATE_PROCESS_STATE) .setProcessor( new WifiPowerStatsProcessor(mPowerProfile)); config.trackPowerComponent(BatteryConsumer.POWER_COMPONENT_BLUETOOTH) .trackDeviceStates( AggregatedPowerStatsConfig.STATE_POWER, AggregatedPowerStatsConfig.STATE_SCREEN) .trackUidStates( AggregatedPowerStatsConfig.STATE_POWER, AggregatedPowerStatsConfig.STATE_SCREEN, AggregatedPowerStatsConfig.STATE_PROCESS_STATE) .setProcessor( new BluetoothPowerStatsProcessor(mPowerProfile)); return config; } Loading Loading @@ -563,6 +575,12 @@ public final class BatteryStatsService extends IBatteryStats.Stub BatteryConsumer.POWER_COMPONENT_WIFI, Flags.streamlinedConnectivityBatteryStats()); mStats.setPowerStatsCollectorEnabled(BatteryConsumer.POWER_COMPONENT_BLUETOOTH, Flags.streamlinedConnectivityBatteryStats()); mBatteryUsageStatsProvider.setPowerStatsExporterEnabled( BatteryConsumer.POWER_COMPONENT_BLUETOOTH, Flags.streamlinedConnectivityBatteryStats()); mWorker.systemServicesReady(); mStats.systemServicesReady(mContext); mCpuWakeupStats.systemServicesReady(); Loading services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java +33 −26 Original line number Diff line number Diff line Loading @@ -572,6 +572,12 @@ public class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStat } if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_BT) != 0) { @SuppressWarnings("GuardedBy") PowerStatsCollector collector = mStats.getPowerStatsCollector( BatteryConsumer.POWER_COMPONENT_BLUETOOTH); if (collector.isEnabled()) { collector.schedule(); } else { // We were asked to fetch Bluetooth data. final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); if (adapter != null) { Loading Loading @@ -602,6 +608,7 @@ public class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStat bluetoothReceiver = resultReceiver; } } } if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_RADIO) != 0) { @SuppressWarnings("GuardedBy") Loading services/core/java/com/android/server/power/stats/BatteryStatsImpl.java +81 −2 Original line number Diff line number Diff line Loading @@ -32,6 +32,8 @@ import android.app.ActivityManager; import android.app.AlarmManager; import android.app.usage.NetworkStatsManager; import android.bluetooth.BluetoothActivityEnergyInfo; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothManager; import android.bluetooth.UidTraffic; import android.content.BroadcastReceiver; import android.content.ContentResolver; Loading Loading @@ -172,6 +174,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Queue; import java.util.concurrent.Executor; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; Loading Loading @@ -294,6 +297,7 @@ public class BatteryStatsImpl extends BatteryStats { private final CpuPowerStatsCollector mCpuPowerStatsCollector; private final MobileRadioPowerStatsCollector mMobileRadioPowerStatsCollector; private final WifiPowerStatsCollector mWifiPowerStatsCollector; private final BluetoothPowerStatsCollector mBluetoothPowerStatsCollector; private final SparseBooleanArray mPowerStatsCollectorEnabled = new SparseBooleanArray(); private final WifiPowerStatsCollector.WifiStatsRetriever mWifiStatsRetriever = new WifiPowerStatsCollector.WifiStatsRetriever() { Loading @@ -313,6 +317,38 @@ public class BatteryStatsImpl extends BatteryStats { } }; private class BluetoothStatsRetrieverImpl implements BluetoothPowerStatsCollector.BluetoothStatsRetriever { private final BluetoothManager mBluetoothManager; BluetoothStatsRetrieverImpl(BluetoothManager bluetoothManager) { mBluetoothManager = bluetoothManager; } @Override public void retrieveBluetoothScanTimes(Callback callback) { synchronized (BatteryStatsImpl.this) { retrieveBluetoothScanTimesLocked(callback); } } @Override public boolean requestControllerActivityEnergyInfo(Executor executor, BluetoothAdapter.OnBluetoothActivityEnergyInfoCallback callback) { if (mBluetoothManager == null) { return false; } BluetoothAdapter adapter = mBluetoothManager.getAdapter(); if (adapter == null) { return false; } adapter.requestControllerActivityEnergyInfo(executor, callback); return true; } } public LongSparseArray<SamplingTimer> getKernelMemoryStats() { return mKernelMemoryStats; } Loading Loading @@ -1926,12 +1962,14 @@ public class BatteryStatsImpl extends BatteryStats { } private class PowerStatsCollectorInjector implements CpuPowerStatsCollector.Injector, MobileRadioPowerStatsCollector.Injector, WifiPowerStatsCollector.Injector { MobileRadioPowerStatsCollector.Injector, WifiPowerStatsCollector.Injector, BluetoothPowerStatsCollector.Injector { private PackageManager mPackageManager; private PowerStatsCollector.ConsumedEnergyRetriever mConsumedEnergyRetriever; private NetworkStatsManager mNetworkStatsManager; private TelephonyManager mTelephonyManager; private WifiManager mWifiManager; private BluetoothPowerStatsCollector.BluetoothStatsRetriever mBluetoothStatsRetriever; void setContext(Context context) { mPackageManager = context.getPackageManager(); Loading @@ -1940,6 +1978,8 @@ public class BatteryStatsImpl extends BatteryStats { mNetworkStatsManager = context.getSystemService(NetworkStatsManager.class); mTelephonyManager = context.getSystemService(TelephonyManager.class); mWifiManager = context.getSystemService(WifiManager.class); mBluetoothStatsRetriever = new BluetoothStatsRetrieverImpl( context.getSystemService(BluetoothManager.class)); } @Override Loading Loading @@ -2017,6 +2057,11 @@ public class BatteryStatsImpl extends BatteryStats { return mWifiManager; } @Override public BluetoothPowerStatsCollector.BluetoothStatsRetriever getBluetoothStatsRetriever() { return mBluetoothStatsRetriever; } @Override public LongSupplier getCallDurationSupplier() { return () -> mPhoneOnTimer.getTotalTimeLocked(mClock.elapsedRealtime() * 1000, Loading Loading @@ -6774,6 +6819,24 @@ public class BatteryStatsImpl extends BatteryStats { } } private void retrieveBluetoothScanTimesLocked( BluetoothPowerStatsCollector.BluetoothStatsRetriever.Callback callback) { long elapsedTimeUs = mClock.elapsedRealtime() * 1000; for (int i = mUidStats.size() - 1; i >= 0; i--) { Uid uidStats = mUidStats.valueAt(i); if (uidStats.mBluetoothScanTimer == null) { continue; } long scanTimeUs = mBluetoothScanTimer.getTotalTimeLocked(elapsedTimeUs, STATS_SINCE_CHARGED); if (scanTimeUs != 0) { int uid = mUidStats.keyAt(i); callback.onBluetoothScanTime(uid, (scanTimeUs + 500) / 1000); } } } @GuardedBy("this") private void noteWifiRadioApWakeupLocked(final long elapsedRealtimeMillis, final long uptimeMillis, int uid) { Loading Loading @@ -11202,6 +11265,10 @@ public class BatteryStatsImpl extends BatteryStats { mWifiPowerStatsCollector = new WifiPowerStatsCollector(mPowerStatsCollectorInjector); mWifiPowerStatsCollector.addConsumer(this::recordPowerStats); mBluetoothPowerStatsCollector = new BluetoothPowerStatsCollector( mPowerStatsCollectorInjector); mBluetoothPowerStatsCollector.addConsumer(this::recordPowerStats); mStartCount++; initTimersAndCounters(); mOnBattery = mOnBatteryInternal = false; Loading Loading @@ -13146,6 +13213,10 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void updateBluetoothStateLocked(@Nullable final BluetoothActivityEnergyInfo info, final long consumedChargeUC, long elapsedRealtimeMs, long uptimeMs) { if (mBluetoothPowerStatsCollector.isEnabled()) { return; } if (DEBUG_ENERGY) { Slog.d(TAG, "Updating bluetooth stats: " + info); } Loading @@ -13153,6 +13224,7 @@ public class BatteryStatsImpl extends BatteryStats { if (info == null) { return; } if (!mOnBatteryInternal || mIgnoreNextExternalStats) { mLastBluetoothActivityInfo.set(info); return; Loading Loading @@ -13187,7 +13259,6 @@ public class BatteryStatsImpl extends BatteryStats { (mGlobalEnergyConsumerStats != null && mBluetoothPowerCalculator != null && consumedChargeUC > 0) ? new SparseDoubleArray() : null; long totalScanTimeMs = 0; final int uidCount = mUidStats.size(); Loading Loading @@ -14616,6 +14687,10 @@ public class BatteryStatsImpl extends BatteryStats { mPowerStatsCollectorEnabled.get(BatteryConsumer.POWER_COMPONENT_WIFI)); mWifiPowerStatsCollector.schedule(); mBluetoothPowerStatsCollector.setEnabled( mPowerStatsCollectorEnabled.get(BatteryConsumer.POWER_COMPONENT_BLUETOOTH)); mBluetoothPowerStatsCollector.schedule(); mSystemReady = true; } Loading @@ -14632,6 +14707,8 @@ public class BatteryStatsImpl extends BatteryStats { return mMobileRadioPowerStatsCollector; case BatteryConsumer.POWER_COMPONENT_WIFI: return mWifiPowerStatsCollector; case BatteryConsumer.POWER_COMPONENT_BLUETOOTH: return mBluetoothPowerStatsCollector; } return null; } Loading Loading @@ -16168,6 +16245,7 @@ public class BatteryStatsImpl extends BatteryStats { mCpuPowerStatsCollector.forceSchedule(); mMobileRadioPowerStatsCollector.forceSchedule(); mWifiPowerStatsCollector.forceSchedule(); mBluetoothPowerStatsCollector.forceSchedule(); } /** Loading @@ -16187,6 +16265,7 @@ public class BatteryStatsImpl extends BatteryStats { mCpuPowerStatsCollector.collectAndDump(pw); mMobileRadioPowerStatsCollector.collectAndDump(pw); mWifiPowerStatsCollector.collectAndDump(pw); mBluetoothPowerStatsCollector.collectAndDump(pw); } private final Runnable mWriteAsyncRunnable = () -> { services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java +3 −1 Original line number Diff line number Diff line Loading @@ -90,7 +90,9 @@ public class BatteryUsageStatsProvider { if (!mPowerStatsExporterEnabled.get(BatteryConsumer.POWER_COMPONENT_WIFI)) { mPowerCalculators.add(new WifiPowerCalculator(mPowerProfile)); } if (!mPowerStatsExporterEnabled.get(BatteryConsumer.POWER_COMPONENT_BLUETOOTH)) { mPowerCalculators.add(new BluetoothPowerCalculator(mPowerProfile)); } mPowerCalculators.add(new SensorPowerCalculator( mContext.getSystemService(SensorManager.class))); mPowerCalculators.add(new GnssPowerCalculator(mPowerProfile)); Loading services/core/java/com/android/server/power/stats/BluetoothPowerStatsCollector.java 0 → 100644 +332 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.power.stats; import android.bluetooth.BluetoothActivityEnergyInfo; import android.bluetooth.BluetoothAdapter; import android.bluetooth.UidTraffic; import android.content.pm.PackageManager; import android.hardware.power.stats.EnergyConsumerType; import android.os.BatteryConsumer; import android.os.Handler; import android.os.PersistableBundle; import android.util.Slog; import android.util.SparseArray; import com.android.internal.os.Clock; import com.android.internal.os.PowerStats; import java.util.Arrays; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import java.util.function.IntSupplier; public class BluetoothPowerStatsCollector extends PowerStatsCollector { private static final String TAG = "BluetoothPowerStatsCollector"; private static final long BLUETOOTH_ACTIVITY_REQUEST_TIMEOUT = 20000; private static final long ENERGY_UNSPECIFIED = -1; interface BluetoothStatsRetriever { interface Callback { void onBluetoothScanTime(int uid, long scanTimeMs); } void retrieveBluetoothScanTimes(Callback callback); boolean requestControllerActivityEnergyInfo(Executor executor, BluetoothAdapter.OnBluetoothActivityEnergyInfoCallback callback); } interface Injector { Handler getHandler(); Clock getClock(); PowerStatsUidResolver getUidResolver(); long getPowerStatsCollectionThrottlePeriod(String powerComponentName); PackageManager getPackageManager(); ConsumedEnergyRetriever getConsumedEnergyRetriever(); IntSupplier getVoltageSupplier(); BluetoothStatsRetriever getBluetoothStatsRetriever(); } private final Injector mInjector; private BluetoothPowerStatsLayout mLayout; private boolean mIsInitialized; private PowerStats mPowerStats; private long[] mDeviceStats; private BluetoothStatsRetriever mBluetoothStatsRetriever; private ConsumedEnergyRetriever mConsumedEnergyRetriever; private IntSupplier mVoltageSupplier; private int[] mEnergyConsumerIds = new int[0]; private long[] mLastConsumedEnergyUws; private int mLastVoltageMv; private long mLastRxTime; private long mLastTxTime; private long mLastIdleTime; private static class UidStats { public long rxCount; public long lastRxCount; public long txCount; public long lastTxCount; public long scanTime; public long lastScanTime; } private final SparseArray<UidStats> mUidStats = new SparseArray<>(); BluetoothPowerStatsCollector(Injector injector) { super(injector.getHandler(), injector.getPowerStatsCollectionThrottlePeriod( BatteryConsumer.powerComponentIdToString( BatteryConsumer.POWER_COMPONENT_BLUETOOTH)), injector.getUidResolver(), injector.getClock()); mInjector = injector; } @Override public void setEnabled(boolean enabled) { if (enabled) { PackageManager packageManager = mInjector.getPackageManager(); super.setEnabled(packageManager != null && packageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)); } else { super.setEnabled(false); } } private boolean ensureInitialized() { if (mIsInitialized) { return true; } if (!isEnabled()) { return false; } mConsumedEnergyRetriever = mInjector.getConsumedEnergyRetriever(); mVoltageSupplier = mInjector.getVoltageSupplier(); mBluetoothStatsRetriever = mInjector.getBluetoothStatsRetriever(); mEnergyConsumerIds = mConsumedEnergyRetriever.getEnergyConsumerIds(EnergyConsumerType.BLUETOOTH); mLastConsumedEnergyUws = new long[mEnergyConsumerIds.length]; Arrays.fill(mLastConsumedEnergyUws, ENERGY_UNSPECIFIED); mLayout = new BluetoothPowerStatsLayout(); mLayout.addDeviceBluetoothControllerActivity(); mLayout.addDeviceSectionEnergyConsumers(mEnergyConsumerIds.length); mLayout.addDeviceSectionUsageDuration(); mLayout.addDeviceSectionPowerEstimate(); mLayout.addUidTrafficStats(); mLayout.addUidSectionPowerEstimate(); PersistableBundle extras = new PersistableBundle(); mLayout.toExtras(extras); PowerStats.Descriptor powerStatsDescriptor = new PowerStats.Descriptor( BatteryConsumer.POWER_COMPONENT_BLUETOOTH, mLayout.getDeviceStatsArrayLength(), null, 0, mLayout.getUidStatsArrayLength(), extras); mPowerStats = new PowerStats(powerStatsDescriptor); mDeviceStats = mPowerStats.stats; mIsInitialized = true; return true; } @Override protected PowerStats collectStats() { if (!ensureInitialized()) { return null; } mPowerStats.uidStats.clear(); collectBluetoothActivityInfo(); collectBluetoothScanStats(); if (mEnergyConsumerIds.length != 0) { collectEnergyConsumers(); } return mPowerStats; } private void collectBluetoothActivityInfo() { CompletableFuture<BluetoothActivityEnergyInfo> immediateFuture = new CompletableFuture<>(); boolean success = mBluetoothStatsRetriever.requestControllerActivityEnergyInfo( Runnable::run, new BluetoothAdapter.OnBluetoothActivityEnergyInfoCallback() { @Override public void onBluetoothActivityEnergyInfoAvailable( BluetoothActivityEnergyInfo info) { immediateFuture.complete(info); } @Override public void onBluetoothActivityEnergyInfoError(int error) { immediateFuture.completeExceptionally( new RuntimeException("error: " + error)); } }); if (!success) { return; } BluetoothActivityEnergyInfo activityInfo; try { activityInfo = immediateFuture.get(BLUETOOTH_ACTIVITY_REQUEST_TIMEOUT, TimeUnit.MILLISECONDS); } catch (Exception e) { Slog.e(TAG, "Cannot acquire BluetoothActivityEnergyInfo", e); activityInfo = null; } if (activityInfo == null) { return; } long rxTime = activityInfo.getControllerRxTimeMillis(); long rxTimeDelta = Math.max(0, rxTime - mLastRxTime); mLayout.setDeviceRxTime(mDeviceStats, rxTimeDelta); mLastRxTime = rxTime; long txTime = activityInfo.getControllerTxTimeMillis(); long txTimeDelta = Math.max(0, txTime - mLastTxTime); mLayout.setDeviceTxTime(mDeviceStats, txTimeDelta); mLastTxTime = txTime; long idleTime = activityInfo.getControllerIdleTimeMillis(); long idleTimeDelta = Math.max(0, idleTime - mLastIdleTime); mLayout.setDeviceIdleTime(mDeviceStats, idleTimeDelta); mLastIdleTime = idleTime; mPowerStats.durationMs = rxTimeDelta + txTimeDelta + idleTimeDelta; List<UidTraffic> uidTraffic = activityInfo.getUidTraffic(); for (int i = uidTraffic.size() - 1; i >= 0; i--) { UidTraffic ut = uidTraffic.get(i); int uid = mUidResolver.mapUid(ut.getUid()); UidStats counts = mUidStats.get(uid); if (counts == null) { counts = new UidStats(); mUidStats.put(uid, counts); } counts.rxCount += ut.getRxBytes(); counts.txCount += ut.getTxBytes(); } for (int i = mUidStats.size() - 1; i >= 0; i--) { UidStats counts = mUidStats.valueAt(i); long rxDelta = Math.max(0, counts.rxCount - counts.lastRxCount); counts.lastRxCount = counts.rxCount; counts.rxCount = 0; long txDelta = Math.max(0, counts.txCount - counts.lastTxCount); counts.lastTxCount = counts.txCount; counts.txCount = 0; if (rxDelta != 0 || txDelta != 0) { int uid = mUidStats.keyAt(i); long[] stats = mPowerStats.uidStats.get(uid); if (stats == null) { stats = new long[mLayout.getUidStatsArrayLength()]; mPowerStats.uidStats.put(uid, stats); } mLayout.setUidRxBytes(stats, rxDelta); mLayout.setUidTxBytes(stats, txDelta); } } } private void collectBluetoothScanStats() { mBluetoothStatsRetriever.retrieveBluetoothScanTimes((uid, scanTimeMs) -> { uid = mUidResolver.mapUid(uid); UidStats uidStats = mUidStats.get(uid); if (uidStats == null) { uidStats = new UidStats(); mUidStats.put(uid, uidStats); } uidStats.scanTime += scanTimeMs; }); long totalScanTime = 0; for (int i = mUidStats.size() - 1; i >= 0; i--) { UidStats counts = mUidStats.valueAt(i); if (counts.scanTime == 0) { continue; } long delta = Math.max(0, counts.scanTime - counts.lastScanTime); counts.lastScanTime = counts.scanTime; counts.scanTime = 0; if (delta != 0) { int uid = mUidStats.keyAt(i); long[] stats = mPowerStats.uidStats.get(uid); if (stats == null) { stats = new long[mLayout.getUidStatsArrayLength()]; mPowerStats.uidStats.put(uid, stats); } mLayout.setUidScanTime(stats, delta); totalScanTime += delta; } } mLayout.setDeviceScanTime(mDeviceStats, totalScanTime); } private void collectEnergyConsumers() { int voltageMv = mVoltageSupplier.getAsInt(); if (voltageMv <= 0) { Slog.wtf(TAG, "Unexpected battery voltage (" + voltageMv + " mV) when querying energy consumers"); return; } int averageVoltage = mLastVoltageMv != 0 ? (mLastVoltageMv + voltageMv) / 2 : voltageMv; mLastVoltageMv = voltageMv; long[] energyUws = mConsumedEnergyRetriever.getConsumedEnergyUws(mEnergyConsumerIds); if (energyUws == null) { return; } for (int i = energyUws.length - 1; i >= 0; i--) { long energyDelta = mLastConsumedEnergyUws[i] != ENERGY_UNSPECIFIED ? energyUws[i] - mLastConsumedEnergyUws[i] : 0; if (energyDelta < 0) { // Likely, restart of powerstats HAL energyDelta = 0; } mLayout.setConsumedEnergy(mPowerStats.stats, i, uJtoUc(energyDelta, averageVoltage)); mLastConsumedEnergyUws[i] = energyUws[i]; } } @Override protected void onUidRemoved(int uid) { super.onUidRemoved(uid); mUidStats.remove(uid); } } Loading
services/core/java/com/android/server/am/BatteryStatsService.java +18 −0 Original line number Diff line number Diff line Loading @@ -124,6 +124,7 @@ import com.android.server.power.stats.BatteryExternalStatsWorker; import com.android.server.power.stats.BatteryStatsDumpHelperImpl; import com.android.server.power.stats.BatteryStatsImpl; import com.android.server.power.stats.BatteryUsageStatsProvider; import com.android.server.power.stats.BluetoothPowerStatsProcessor; import com.android.server.power.stats.CpuPowerStatsProcessor; import com.android.server.power.stats.MobileRadioPowerStatsProcessor; import com.android.server.power.stats.PhoneCallPowerStatsProcessor; Loading Loading @@ -502,6 +503,17 @@ public final class BatteryStatsService extends IBatteryStats.Stub AggregatedPowerStatsConfig.STATE_PROCESS_STATE) .setProcessor( new WifiPowerStatsProcessor(mPowerProfile)); config.trackPowerComponent(BatteryConsumer.POWER_COMPONENT_BLUETOOTH) .trackDeviceStates( AggregatedPowerStatsConfig.STATE_POWER, AggregatedPowerStatsConfig.STATE_SCREEN) .trackUidStates( AggregatedPowerStatsConfig.STATE_POWER, AggregatedPowerStatsConfig.STATE_SCREEN, AggregatedPowerStatsConfig.STATE_PROCESS_STATE) .setProcessor( new BluetoothPowerStatsProcessor(mPowerProfile)); return config; } Loading Loading @@ -563,6 +575,12 @@ public final class BatteryStatsService extends IBatteryStats.Stub BatteryConsumer.POWER_COMPONENT_WIFI, Flags.streamlinedConnectivityBatteryStats()); mStats.setPowerStatsCollectorEnabled(BatteryConsumer.POWER_COMPONENT_BLUETOOTH, Flags.streamlinedConnectivityBatteryStats()); mBatteryUsageStatsProvider.setPowerStatsExporterEnabled( BatteryConsumer.POWER_COMPONENT_BLUETOOTH, Flags.streamlinedConnectivityBatteryStats()); mWorker.systemServicesReady(); mStats.systemServicesReady(mContext); mCpuWakeupStats.systemServicesReady(); Loading
services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java +33 −26 Original line number Diff line number Diff line Loading @@ -572,6 +572,12 @@ public class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStat } if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_BT) != 0) { @SuppressWarnings("GuardedBy") PowerStatsCollector collector = mStats.getPowerStatsCollector( BatteryConsumer.POWER_COMPONENT_BLUETOOTH); if (collector.isEnabled()) { collector.schedule(); } else { // We were asked to fetch Bluetooth data. final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); if (adapter != null) { Loading Loading @@ -602,6 +608,7 @@ public class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStat bluetoothReceiver = resultReceiver; } } } if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_RADIO) != 0) { @SuppressWarnings("GuardedBy") Loading
services/core/java/com/android/server/power/stats/BatteryStatsImpl.java +81 −2 Original line number Diff line number Diff line Loading @@ -32,6 +32,8 @@ import android.app.ActivityManager; import android.app.AlarmManager; import android.app.usage.NetworkStatsManager; import android.bluetooth.BluetoothActivityEnergyInfo; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothManager; import android.bluetooth.UidTraffic; import android.content.BroadcastReceiver; import android.content.ContentResolver; Loading Loading @@ -172,6 +174,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Queue; import java.util.concurrent.Executor; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; Loading Loading @@ -294,6 +297,7 @@ public class BatteryStatsImpl extends BatteryStats { private final CpuPowerStatsCollector mCpuPowerStatsCollector; private final MobileRadioPowerStatsCollector mMobileRadioPowerStatsCollector; private final WifiPowerStatsCollector mWifiPowerStatsCollector; private final BluetoothPowerStatsCollector mBluetoothPowerStatsCollector; private final SparseBooleanArray mPowerStatsCollectorEnabled = new SparseBooleanArray(); private final WifiPowerStatsCollector.WifiStatsRetriever mWifiStatsRetriever = new WifiPowerStatsCollector.WifiStatsRetriever() { Loading @@ -313,6 +317,38 @@ public class BatteryStatsImpl extends BatteryStats { } }; private class BluetoothStatsRetrieverImpl implements BluetoothPowerStatsCollector.BluetoothStatsRetriever { private final BluetoothManager mBluetoothManager; BluetoothStatsRetrieverImpl(BluetoothManager bluetoothManager) { mBluetoothManager = bluetoothManager; } @Override public void retrieveBluetoothScanTimes(Callback callback) { synchronized (BatteryStatsImpl.this) { retrieveBluetoothScanTimesLocked(callback); } } @Override public boolean requestControllerActivityEnergyInfo(Executor executor, BluetoothAdapter.OnBluetoothActivityEnergyInfoCallback callback) { if (mBluetoothManager == null) { return false; } BluetoothAdapter adapter = mBluetoothManager.getAdapter(); if (adapter == null) { return false; } adapter.requestControllerActivityEnergyInfo(executor, callback); return true; } } public LongSparseArray<SamplingTimer> getKernelMemoryStats() { return mKernelMemoryStats; } Loading Loading @@ -1926,12 +1962,14 @@ public class BatteryStatsImpl extends BatteryStats { } private class PowerStatsCollectorInjector implements CpuPowerStatsCollector.Injector, MobileRadioPowerStatsCollector.Injector, WifiPowerStatsCollector.Injector { MobileRadioPowerStatsCollector.Injector, WifiPowerStatsCollector.Injector, BluetoothPowerStatsCollector.Injector { private PackageManager mPackageManager; private PowerStatsCollector.ConsumedEnergyRetriever mConsumedEnergyRetriever; private NetworkStatsManager mNetworkStatsManager; private TelephonyManager mTelephonyManager; private WifiManager mWifiManager; private BluetoothPowerStatsCollector.BluetoothStatsRetriever mBluetoothStatsRetriever; void setContext(Context context) { mPackageManager = context.getPackageManager(); Loading @@ -1940,6 +1978,8 @@ public class BatteryStatsImpl extends BatteryStats { mNetworkStatsManager = context.getSystemService(NetworkStatsManager.class); mTelephonyManager = context.getSystemService(TelephonyManager.class); mWifiManager = context.getSystemService(WifiManager.class); mBluetoothStatsRetriever = new BluetoothStatsRetrieverImpl( context.getSystemService(BluetoothManager.class)); } @Override Loading Loading @@ -2017,6 +2057,11 @@ public class BatteryStatsImpl extends BatteryStats { return mWifiManager; } @Override public BluetoothPowerStatsCollector.BluetoothStatsRetriever getBluetoothStatsRetriever() { return mBluetoothStatsRetriever; } @Override public LongSupplier getCallDurationSupplier() { return () -> mPhoneOnTimer.getTotalTimeLocked(mClock.elapsedRealtime() * 1000, Loading Loading @@ -6774,6 +6819,24 @@ public class BatteryStatsImpl extends BatteryStats { } } private void retrieveBluetoothScanTimesLocked( BluetoothPowerStatsCollector.BluetoothStatsRetriever.Callback callback) { long elapsedTimeUs = mClock.elapsedRealtime() * 1000; for (int i = mUidStats.size() - 1; i >= 0; i--) { Uid uidStats = mUidStats.valueAt(i); if (uidStats.mBluetoothScanTimer == null) { continue; } long scanTimeUs = mBluetoothScanTimer.getTotalTimeLocked(elapsedTimeUs, STATS_SINCE_CHARGED); if (scanTimeUs != 0) { int uid = mUidStats.keyAt(i); callback.onBluetoothScanTime(uid, (scanTimeUs + 500) / 1000); } } } @GuardedBy("this") private void noteWifiRadioApWakeupLocked(final long elapsedRealtimeMillis, final long uptimeMillis, int uid) { Loading Loading @@ -11202,6 +11265,10 @@ public class BatteryStatsImpl extends BatteryStats { mWifiPowerStatsCollector = new WifiPowerStatsCollector(mPowerStatsCollectorInjector); mWifiPowerStatsCollector.addConsumer(this::recordPowerStats); mBluetoothPowerStatsCollector = new BluetoothPowerStatsCollector( mPowerStatsCollectorInjector); mBluetoothPowerStatsCollector.addConsumer(this::recordPowerStats); mStartCount++; initTimersAndCounters(); mOnBattery = mOnBatteryInternal = false; Loading Loading @@ -13146,6 +13213,10 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") public void updateBluetoothStateLocked(@Nullable final BluetoothActivityEnergyInfo info, final long consumedChargeUC, long elapsedRealtimeMs, long uptimeMs) { if (mBluetoothPowerStatsCollector.isEnabled()) { return; } if (DEBUG_ENERGY) { Slog.d(TAG, "Updating bluetooth stats: " + info); } Loading @@ -13153,6 +13224,7 @@ public class BatteryStatsImpl extends BatteryStats { if (info == null) { return; } if (!mOnBatteryInternal || mIgnoreNextExternalStats) { mLastBluetoothActivityInfo.set(info); return; Loading Loading @@ -13187,7 +13259,6 @@ public class BatteryStatsImpl extends BatteryStats { (mGlobalEnergyConsumerStats != null && mBluetoothPowerCalculator != null && consumedChargeUC > 0) ? new SparseDoubleArray() : null; long totalScanTimeMs = 0; final int uidCount = mUidStats.size(); Loading Loading @@ -14616,6 +14687,10 @@ public class BatteryStatsImpl extends BatteryStats { mPowerStatsCollectorEnabled.get(BatteryConsumer.POWER_COMPONENT_WIFI)); mWifiPowerStatsCollector.schedule(); mBluetoothPowerStatsCollector.setEnabled( mPowerStatsCollectorEnabled.get(BatteryConsumer.POWER_COMPONENT_BLUETOOTH)); mBluetoothPowerStatsCollector.schedule(); mSystemReady = true; } Loading @@ -14632,6 +14707,8 @@ public class BatteryStatsImpl extends BatteryStats { return mMobileRadioPowerStatsCollector; case BatteryConsumer.POWER_COMPONENT_WIFI: return mWifiPowerStatsCollector; case BatteryConsumer.POWER_COMPONENT_BLUETOOTH: return mBluetoothPowerStatsCollector; } return null; } Loading Loading @@ -16168,6 +16245,7 @@ public class BatteryStatsImpl extends BatteryStats { mCpuPowerStatsCollector.forceSchedule(); mMobileRadioPowerStatsCollector.forceSchedule(); mWifiPowerStatsCollector.forceSchedule(); mBluetoothPowerStatsCollector.forceSchedule(); } /** Loading @@ -16187,6 +16265,7 @@ public class BatteryStatsImpl extends BatteryStats { mCpuPowerStatsCollector.collectAndDump(pw); mMobileRadioPowerStatsCollector.collectAndDump(pw); mWifiPowerStatsCollector.collectAndDump(pw); mBluetoothPowerStatsCollector.collectAndDump(pw); } private final Runnable mWriteAsyncRunnable = () -> {
services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java +3 −1 Original line number Diff line number Diff line Loading @@ -90,7 +90,9 @@ public class BatteryUsageStatsProvider { if (!mPowerStatsExporterEnabled.get(BatteryConsumer.POWER_COMPONENT_WIFI)) { mPowerCalculators.add(new WifiPowerCalculator(mPowerProfile)); } if (!mPowerStatsExporterEnabled.get(BatteryConsumer.POWER_COMPONENT_BLUETOOTH)) { mPowerCalculators.add(new BluetoothPowerCalculator(mPowerProfile)); } mPowerCalculators.add(new SensorPowerCalculator( mContext.getSystemService(SensorManager.class))); mPowerCalculators.add(new GnssPowerCalculator(mPowerProfile)); Loading
services/core/java/com/android/server/power/stats/BluetoothPowerStatsCollector.java 0 → 100644 +332 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.power.stats; import android.bluetooth.BluetoothActivityEnergyInfo; import android.bluetooth.BluetoothAdapter; import android.bluetooth.UidTraffic; import android.content.pm.PackageManager; import android.hardware.power.stats.EnergyConsumerType; import android.os.BatteryConsumer; import android.os.Handler; import android.os.PersistableBundle; import android.util.Slog; import android.util.SparseArray; import com.android.internal.os.Clock; import com.android.internal.os.PowerStats; import java.util.Arrays; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import java.util.function.IntSupplier; public class BluetoothPowerStatsCollector extends PowerStatsCollector { private static final String TAG = "BluetoothPowerStatsCollector"; private static final long BLUETOOTH_ACTIVITY_REQUEST_TIMEOUT = 20000; private static final long ENERGY_UNSPECIFIED = -1; interface BluetoothStatsRetriever { interface Callback { void onBluetoothScanTime(int uid, long scanTimeMs); } void retrieveBluetoothScanTimes(Callback callback); boolean requestControllerActivityEnergyInfo(Executor executor, BluetoothAdapter.OnBluetoothActivityEnergyInfoCallback callback); } interface Injector { Handler getHandler(); Clock getClock(); PowerStatsUidResolver getUidResolver(); long getPowerStatsCollectionThrottlePeriod(String powerComponentName); PackageManager getPackageManager(); ConsumedEnergyRetriever getConsumedEnergyRetriever(); IntSupplier getVoltageSupplier(); BluetoothStatsRetriever getBluetoothStatsRetriever(); } private final Injector mInjector; private BluetoothPowerStatsLayout mLayout; private boolean mIsInitialized; private PowerStats mPowerStats; private long[] mDeviceStats; private BluetoothStatsRetriever mBluetoothStatsRetriever; private ConsumedEnergyRetriever mConsumedEnergyRetriever; private IntSupplier mVoltageSupplier; private int[] mEnergyConsumerIds = new int[0]; private long[] mLastConsumedEnergyUws; private int mLastVoltageMv; private long mLastRxTime; private long mLastTxTime; private long mLastIdleTime; private static class UidStats { public long rxCount; public long lastRxCount; public long txCount; public long lastTxCount; public long scanTime; public long lastScanTime; } private final SparseArray<UidStats> mUidStats = new SparseArray<>(); BluetoothPowerStatsCollector(Injector injector) { super(injector.getHandler(), injector.getPowerStatsCollectionThrottlePeriod( BatteryConsumer.powerComponentIdToString( BatteryConsumer.POWER_COMPONENT_BLUETOOTH)), injector.getUidResolver(), injector.getClock()); mInjector = injector; } @Override public void setEnabled(boolean enabled) { if (enabled) { PackageManager packageManager = mInjector.getPackageManager(); super.setEnabled(packageManager != null && packageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)); } else { super.setEnabled(false); } } private boolean ensureInitialized() { if (mIsInitialized) { return true; } if (!isEnabled()) { return false; } mConsumedEnergyRetriever = mInjector.getConsumedEnergyRetriever(); mVoltageSupplier = mInjector.getVoltageSupplier(); mBluetoothStatsRetriever = mInjector.getBluetoothStatsRetriever(); mEnergyConsumerIds = mConsumedEnergyRetriever.getEnergyConsumerIds(EnergyConsumerType.BLUETOOTH); mLastConsumedEnergyUws = new long[mEnergyConsumerIds.length]; Arrays.fill(mLastConsumedEnergyUws, ENERGY_UNSPECIFIED); mLayout = new BluetoothPowerStatsLayout(); mLayout.addDeviceBluetoothControllerActivity(); mLayout.addDeviceSectionEnergyConsumers(mEnergyConsumerIds.length); mLayout.addDeviceSectionUsageDuration(); mLayout.addDeviceSectionPowerEstimate(); mLayout.addUidTrafficStats(); mLayout.addUidSectionPowerEstimate(); PersistableBundle extras = new PersistableBundle(); mLayout.toExtras(extras); PowerStats.Descriptor powerStatsDescriptor = new PowerStats.Descriptor( BatteryConsumer.POWER_COMPONENT_BLUETOOTH, mLayout.getDeviceStatsArrayLength(), null, 0, mLayout.getUidStatsArrayLength(), extras); mPowerStats = new PowerStats(powerStatsDescriptor); mDeviceStats = mPowerStats.stats; mIsInitialized = true; return true; } @Override protected PowerStats collectStats() { if (!ensureInitialized()) { return null; } mPowerStats.uidStats.clear(); collectBluetoothActivityInfo(); collectBluetoothScanStats(); if (mEnergyConsumerIds.length != 0) { collectEnergyConsumers(); } return mPowerStats; } private void collectBluetoothActivityInfo() { CompletableFuture<BluetoothActivityEnergyInfo> immediateFuture = new CompletableFuture<>(); boolean success = mBluetoothStatsRetriever.requestControllerActivityEnergyInfo( Runnable::run, new BluetoothAdapter.OnBluetoothActivityEnergyInfoCallback() { @Override public void onBluetoothActivityEnergyInfoAvailable( BluetoothActivityEnergyInfo info) { immediateFuture.complete(info); } @Override public void onBluetoothActivityEnergyInfoError(int error) { immediateFuture.completeExceptionally( new RuntimeException("error: " + error)); } }); if (!success) { return; } BluetoothActivityEnergyInfo activityInfo; try { activityInfo = immediateFuture.get(BLUETOOTH_ACTIVITY_REQUEST_TIMEOUT, TimeUnit.MILLISECONDS); } catch (Exception e) { Slog.e(TAG, "Cannot acquire BluetoothActivityEnergyInfo", e); activityInfo = null; } if (activityInfo == null) { return; } long rxTime = activityInfo.getControllerRxTimeMillis(); long rxTimeDelta = Math.max(0, rxTime - mLastRxTime); mLayout.setDeviceRxTime(mDeviceStats, rxTimeDelta); mLastRxTime = rxTime; long txTime = activityInfo.getControllerTxTimeMillis(); long txTimeDelta = Math.max(0, txTime - mLastTxTime); mLayout.setDeviceTxTime(mDeviceStats, txTimeDelta); mLastTxTime = txTime; long idleTime = activityInfo.getControllerIdleTimeMillis(); long idleTimeDelta = Math.max(0, idleTime - mLastIdleTime); mLayout.setDeviceIdleTime(mDeviceStats, idleTimeDelta); mLastIdleTime = idleTime; mPowerStats.durationMs = rxTimeDelta + txTimeDelta + idleTimeDelta; List<UidTraffic> uidTraffic = activityInfo.getUidTraffic(); for (int i = uidTraffic.size() - 1; i >= 0; i--) { UidTraffic ut = uidTraffic.get(i); int uid = mUidResolver.mapUid(ut.getUid()); UidStats counts = mUidStats.get(uid); if (counts == null) { counts = new UidStats(); mUidStats.put(uid, counts); } counts.rxCount += ut.getRxBytes(); counts.txCount += ut.getTxBytes(); } for (int i = mUidStats.size() - 1; i >= 0; i--) { UidStats counts = mUidStats.valueAt(i); long rxDelta = Math.max(0, counts.rxCount - counts.lastRxCount); counts.lastRxCount = counts.rxCount; counts.rxCount = 0; long txDelta = Math.max(0, counts.txCount - counts.lastTxCount); counts.lastTxCount = counts.txCount; counts.txCount = 0; if (rxDelta != 0 || txDelta != 0) { int uid = mUidStats.keyAt(i); long[] stats = mPowerStats.uidStats.get(uid); if (stats == null) { stats = new long[mLayout.getUidStatsArrayLength()]; mPowerStats.uidStats.put(uid, stats); } mLayout.setUidRxBytes(stats, rxDelta); mLayout.setUidTxBytes(stats, txDelta); } } } private void collectBluetoothScanStats() { mBluetoothStatsRetriever.retrieveBluetoothScanTimes((uid, scanTimeMs) -> { uid = mUidResolver.mapUid(uid); UidStats uidStats = mUidStats.get(uid); if (uidStats == null) { uidStats = new UidStats(); mUidStats.put(uid, uidStats); } uidStats.scanTime += scanTimeMs; }); long totalScanTime = 0; for (int i = mUidStats.size() - 1; i >= 0; i--) { UidStats counts = mUidStats.valueAt(i); if (counts.scanTime == 0) { continue; } long delta = Math.max(0, counts.scanTime - counts.lastScanTime); counts.lastScanTime = counts.scanTime; counts.scanTime = 0; if (delta != 0) { int uid = mUidStats.keyAt(i); long[] stats = mPowerStats.uidStats.get(uid); if (stats == null) { stats = new long[mLayout.getUidStatsArrayLength()]; mPowerStats.uidStats.put(uid, stats); } mLayout.setUidScanTime(stats, delta); totalScanTime += delta; } } mLayout.setDeviceScanTime(mDeviceStats, totalScanTime); } private void collectEnergyConsumers() { int voltageMv = mVoltageSupplier.getAsInt(); if (voltageMv <= 0) { Slog.wtf(TAG, "Unexpected battery voltage (" + voltageMv + " mV) when querying energy consumers"); return; } int averageVoltage = mLastVoltageMv != 0 ? (mLastVoltageMv + voltageMv) / 2 : voltageMv; mLastVoltageMv = voltageMv; long[] energyUws = mConsumedEnergyRetriever.getConsumedEnergyUws(mEnergyConsumerIds); if (energyUws == null) { return; } for (int i = energyUws.length - 1; i >= 0; i--) { long energyDelta = mLastConsumedEnergyUws[i] != ENERGY_UNSPECIFIED ? energyUws[i] - mLastConsumedEnergyUws[i] : 0; if (energyDelta < 0) { // Likely, restart of powerstats HAL energyDelta = 0; } mLayout.setConsumedEnergy(mPowerStats.stats, i, uJtoUc(energyDelta, averageVoltage)); mLastConsumedEnergyUws[i] = energyUws[i]; } } @Override protected void onUidRemoved(int uid) { super.onUidRemoved(uid); mUidStats.remove(uid); } }