/* * Copyright (C) 2019 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 android.os; import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; import android.content.Context; import android.net.NetworkStack; import android.os.connectivity.CellularBatteryStats; import android.os.connectivity.WifiBatteryStats; import android.telephony.DataConnectionRealTimeInfo; import com.android.internal.app.IBatteryStats; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.List; /** * This class provides an API surface for internal system components to report events that are * needed for battery usage/estimation and battery blaming for apps. * * Note: This internally uses the same {@link IBatteryStats} binder service as the public * {@link BatteryManager}. * @hide */ @SystemApi @SystemService(Context.BATTERY_STATS_SERVICE) public final class BatteryStatsManager { /** * Wifi states. * * @see #noteWifiState(int, String) */ /** * Wifi fully off. */ public static final int WIFI_STATE_OFF = 0; /** * Wifi connectivity off, but scanning enabled. */ public static final int WIFI_STATE_OFF_SCANNING = 1; /** * Wifi on, but no saved infrastructure networks to connect to. */ public static final int WIFI_STATE_ON_NO_NETWORKS = 2; /** * Wifi on, but not connected to any infrastructure networks. */ public static final int WIFI_STATE_ON_DISCONNECTED = 3; /** * Wifi on and connected to a infrastructure network. */ public static final int WIFI_STATE_ON_CONNECTED_STA = 4; /** * Wifi on and connected to a P2P device, but no infrastructure connection to a network. */ public static final int WIFI_STATE_ON_CONNECTED_P2P = 5; /** * Wifi on and connected to both a P2P device and infrastructure connection to a network. */ public static final int WIFI_STATE_ON_CONNECTED_STA_P2P = 6; /** * SoftAp/Hotspot turned on. */ public static final int WIFI_STATE_SOFT_AP = 7; /** @hide */ public static final int NUM_WIFI_STATES = WIFI_STATE_SOFT_AP + 1; /** @hide */ @IntDef(prefix = { "WIFI_STATE_" }, value = { WIFI_STATE_OFF, WIFI_STATE_OFF_SCANNING, WIFI_STATE_ON_NO_NETWORKS, WIFI_STATE_ON_DISCONNECTED, WIFI_STATE_ON_CONNECTED_STA, WIFI_STATE_ON_CONNECTED_P2P, WIFI_STATE_ON_CONNECTED_STA_P2P, WIFI_STATE_SOFT_AP }) @Retention(RetentionPolicy.SOURCE) public @interface WifiState {} /** * Wifi supplicant daemon states. * * @see android.net.wifi.SupplicantState for detailed description of states. * @see #noteWifiSupplicantStateChanged(int) */ /** @see android.net.wifi.SupplicantState#INVALID */ public static final int WIFI_SUPPL_STATE_INVALID = 0; /** @see android.net.wifi.SupplicantState#DISCONNECTED*/ public static final int WIFI_SUPPL_STATE_DISCONNECTED = 1; /** @see android.net.wifi.SupplicantState#INTERFACE_DISABLED */ public static final int WIFI_SUPPL_STATE_INTERFACE_DISABLED = 2; /** @see android.net.wifi.SupplicantState#INACTIVE*/ public static final int WIFI_SUPPL_STATE_INACTIVE = 3; /** @see android.net.wifi.SupplicantState#SCANNING*/ public static final int WIFI_SUPPL_STATE_SCANNING = 4; /** @see android.net.wifi.SupplicantState#AUTHENTICATING */ public static final int WIFI_SUPPL_STATE_AUTHENTICATING = 5; /** @see android.net.wifi.SupplicantState#ASSOCIATING */ public static final int WIFI_SUPPL_STATE_ASSOCIATING = 6; /** @see android.net.wifi.SupplicantState#ASSOCIATED */ public static final int WIFI_SUPPL_STATE_ASSOCIATED = 7; /** @see android.net.wifi.SupplicantState#FOUR_WAY_HANDSHAKE */ public static final int WIFI_SUPPL_STATE_FOUR_WAY_HANDSHAKE = 8; /** @see android.net.wifi.SupplicantState#GROUP_HANDSHAKE */ public static final int WIFI_SUPPL_STATE_GROUP_HANDSHAKE = 9; /** @see android.net.wifi.SupplicantState#COMPLETED */ public static final int WIFI_SUPPL_STATE_COMPLETED = 10; /** @see android.net.wifi.SupplicantState#DORMANT */ public static final int WIFI_SUPPL_STATE_DORMANT = 11; /** @see android.net.wifi.SupplicantState#UNINITIALIZED */ public static final int WIFI_SUPPL_STATE_UNINITIALIZED = 12; /** @hide */ public static final int NUM_WIFI_SUPPL_STATES = WIFI_SUPPL_STATE_UNINITIALIZED + 1; /** @hide */ @IntDef(prefix = { "WIFI_SUPPL_STATE_" }, value = { WIFI_SUPPL_STATE_INVALID, WIFI_SUPPL_STATE_DISCONNECTED, WIFI_SUPPL_STATE_INTERFACE_DISABLED, WIFI_SUPPL_STATE_INACTIVE, WIFI_SUPPL_STATE_SCANNING, WIFI_SUPPL_STATE_AUTHENTICATING, WIFI_SUPPL_STATE_ASSOCIATING, WIFI_SUPPL_STATE_ASSOCIATED, WIFI_SUPPL_STATE_FOUR_WAY_HANDSHAKE, WIFI_SUPPL_STATE_GROUP_HANDSHAKE, WIFI_SUPPL_STATE_COMPLETED, WIFI_SUPPL_STATE_DORMANT, WIFI_SUPPL_STATE_UNINITIALIZED, }) @Retention(RetentionPolicy.SOURCE) public @interface WifiSupplState {} private final IBatteryStats mBatteryStats; /** @hide */ public BatteryStatsManager(IBatteryStats batteryStats) { mBatteryStats = batteryStats; } /** * Returns BatteryUsageStats, which contains power attribution data on a per-subsystem * and per-UID basis. * * @hide */ @RequiresPermission(android.Manifest.permission.BATTERY_STATS) @NonNull public BatteryUsageStats getBatteryUsageStats() { return getBatteryUsageStats(BatteryUsageStatsQuery.DEFAULT); } /** * Returns BatteryUsageStats, which contains power attribution data on a per-subsystem * and per-UID basis. * * @hide */ @RequiresPermission(android.Manifest.permission.BATTERY_STATS) @NonNull public BatteryUsageStats getBatteryUsageStats(BatteryUsageStatsQuery query) { return getBatteryUsageStats(List.of(query)).get(0); } /** * Returns BatteryUsageStats, which contains power attribution data on a per-subsystem * and per-UID basis. * * @hide */ @RequiresPermission(android.Manifest.permission.BATTERY_STATS) @NonNull public List getBatteryUsageStats(List queries) { try { return mBatteryStats.getBatteryUsageStats(queries); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Indicates that the wifi connection RSSI has changed. * * @param newRssi The new RSSI value. */ @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiRssiChanged(@IntRange(from = -127, to = 0) int newRssi) { try { mBatteryStats.noteWifiRssiChanged(newRssi); } catch (RemoteException e) { e.rethrowFromSystemServer(); } } /** * Indicates that wifi was toggled on. */ @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiOn() { try { mBatteryStats.noteWifiOn(); } catch (RemoteException e) { e.rethrowFromSystemServer(); } } /** * Indicates that wifi was toggled off. */ @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiOff() { try { mBatteryStats.noteWifiOff(); } catch (RemoteException e) { e.rethrowFromSystemServer(); } } /** * Indicates that wifi state has changed. * * @param newWifiState The new wifi State. * @param accessPoint SSID of the network if wifi is connected to STA, else null. */ @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiState(@WifiState int newWifiState, @Nullable String accessPoint) { try { mBatteryStats.noteWifiState(newWifiState, accessPoint); } catch (RemoteException e) { e.rethrowFromSystemServer(); } } /** * Indicates that a new wifi scan has started. * * @param ws Worksource (to be used for battery blaming). */ @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiScanStartedFromSource(@NonNull WorkSource ws) { try { mBatteryStats.noteWifiScanStartedFromSource(ws); } catch (RemoteException e) { e.rethrowFromSystemServer(); } } /** * Indicates that an ongoing wifi scan has stopped. * * @param ws Worksource (to be used for battery blaming). */ @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiScanStoppedFromSource(@NonNull WorkSource ws) { try { mBatteryStats.noteWifiScanStoppedFromSource(ws); } catch (RemoteException e) { e.rethrowFromSystemServer(); } } /** * Indicates that a new wifi batched scan has started. * * @param ws Worksource (to be used for battery blaming). * @param csph Channels scanned per hour. */ @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiBatchedScanStartedFromSource(@NonNull WorkSource ws, @IntRange(from = 0) int csph) { try { mBatteryStats.noteWifiBatchedScanStartedFromSource(ws, csph); } catch (RemoteException e) { e.rethrowFromSystemServer(); } } /** * Indicates that an ongoing wifi batched scan has stopped. * * @param ws Worksource (to be used for battery blaming). */ @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiBatchedScanStoppedFromSource(@NonNull WorkSource ws) { try { mBatteryStats.noteWifiBatchedScanStoppedFromSource(ws); } catch (RemoteException e) { e.rethrowFromSystemServer(); } } /** * Retrieves all the cellular related battery stats. * * @return Instance of {@link CellularBatteryStats}. */ @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public @NonNull CellularBatteryStats getCellularBatteryStats() { try { return mBatteryStats.getCellularBatteryStats(); } catch (RemoteException e) { e.rethrowFromSystemServer(); return null; } } /** * Retrieves all the wifi related battery stats. * * @return Instance of {@link WifiBatteryStats}. */ @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public @NonNull WifiBatteryStats getWifiBatteryStats() { try { return mBatteryStats.getWifiBatteryStats(); } catch (RemoteException e) { e.rethrowFromSystemServer(); return null; } } /** * Indicates an app acquiring full wifi lock. * * @param ws Worksource (to be used for battery blaming). */ @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportFullWifiLockAcquiredFromSource(@NonNull WorkSource ws) { try { mBatteryStats.noteFullWifiLockAcquiredFromSource(ws); } catch (RemoteException e) { e.rethrowFromSystemServer(); } } /** * Indicates an app releasing full wifi lock. * * @param ws Worksource (to be used for battery blaming). */ @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportFullWifiLockReleasedFromSource(@NonNull WorkSource ws) { try { mBatteryStats.noteFullWifiLockReleasedFromSource(ws); } catch (RemoteException e) { e.rethrowFromSystemServer(); } } /** * Indicates that supplicant state has changed. * * @param newSupplState The new Supplicant state. * @param failedAuth Boolean indicating whether there was a connection failure due to * authentication failure. */ @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiSupplicantStateChanged(@WifiSupplState int newSupplState, boolean failedAuth) { try { mBatteryStats.noteWifiSupplicantStateChanged(newSupplState, failedAuth); } catch (RemoteException e) { e.rethrowFromSystemServer(); } } /** * Indicates that an app has acquired the wifi multicast lock. * * @param ws Worksource with the uid of the app that acquired the wifi lock (to be used for * battery blaming). */ @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiMulticastEnabled(@NonNull WorkSource ws) { try { mBatteryStats.noteWifiMulticastEnabled(ws.getAttributionUid()); } catch (RemoteException e) { e.rethrowFromSystemServer(); } } /** * Indicates that an app has released the wifi multicast lock. * * @param ws Worksource with the uid of the app that released the wifi lock (to be used for * battery blaming). */ @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiMulticastDisabled(@NonNull WorkSource ws) { try { mBatteryStats.noteWifiMulticastDisabled(ws.getAttributionUid()); } catch (RemoteException e) { e.rethrowFromSystemServer(); } } /** * Indicates that the radio power state has changed. * * @param isActive indicates if the mobile radio is powered. * @param uid Uid of this event. For the active state it represents the uid that was responsible * for waking the radio, or -1 if the system was responsible for waking the radio. * For inactive state, the UID should always be -1. */ @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportMobileRadioPowerState(boolean isActive, int uid) { try { mBatteryStats.noteMobileRadioPowerState(getDataConnectionPowerState(isActive), SystemClock.elapsedRealtimeNanos(), uid); } catch (RemoteException e) { e.rethrowFromSystemServer(); } } /** * Indicates that the wifi power state has changed. * * @param isActive indicates if the wifi radio is powered. * @param uid Uid of this event. For the active state it represents the uid that was responsible * for waking the radio, or -1 if the system was responsible for waking the radio. * For inactive state, the UID should always be -1. */ @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiRadioPowerState(boolean isActive, int uid) { try { mBatteryStats.noteWifiRadioPowerState(getDataConnectionPowerState(isActive), SystemClock.elapsedRealtimeNanos(), uid); } catch (RemoteException e) { e.rethrowFromSystemServer(); } } /** * Notifies the battery stats of a new interface, and the transport types of the network that * includes that interface. * * @param iface The interface of the network. * @param transportTypes The transport type of the network {@link Transport}. * @hide */ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @RequiresPermission(anyOf = { NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void reportNetworkInterfaceForTransports(@NonNull String iface, @NonNull int[] transportTypes) throws RuntimeException { try { mBatteryStats.noteNetworkInterfaceForTransports(iface, transportTypes); } catch (RemoteException e) { e.rethrowFromSystemServer(); } } private static int getDataConnectionPowerState(boolean isActive) { // TODO: DataConnectionRealTimeInfo is under telephony package but the constants are used // for both Wifi and mobile. It would make more sense to separate the constants to a // generic class or move it to generic package. return isActive ? DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH : DataConnectionRealTimeInfo.DC_POWER_STATE_LOW; } /** * Sets battery AC charger to enabled/disabled, and freezes the battery state. * @hide */ @TestApi @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void setChargerAcOnline(boolean online, boolean forceUpdate) { try { mBatteryStats.setChargerAcOnline(online, forceUpdate); } catch (RemoteException e) { e.rethrowFromSystemServer(); } } /** * Sets battery level, and freezes the battery state. * @hide */ @TestApi @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void setBatteryLevel(int level, boolean forceUpdate) { try { mBatteryStats.setBatteryLevel(level, forceUpdate); } catch (RemoteException e) { e.rethrowFromSystemServer(); } } /** * Unplugs battery, and freezes the battery state. * @hide */ @TestApi @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void unplugBattery(boolean forceUpdate) { try { mBatteryStats.unplugBattery(forceUpdate); } catch (RemoteException e) { e.rethrowFromSystemServer(); } } /** * Unfreezes battery state, returning to current hardware values. * @hide */ @TestApi @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void resetBattery(boolean forceUpdate) { try { mBatteryStats.resetBattery(forceUpdate); } catch (RemoteException e) { e.rethrowFromSystemServer(); } } /** * Suspend charging even if plugged in. * @hide */ @TestApi @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void suspendBatteryInput() { try { mBatteryStats.suspendBatteryInput(); } catch (RemoteException e) { e.rethrowFromSystemServer(); } } }