Android源码笔记--电量
Posted ljt2724960661
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android源码笔记--电量相关的知识,希望对你有一定的参考价值。
这一节主要了解BatteryService相关知识,在PowerManagerService中调用了BatteryService类的一些接口来获得电池的状态,下面看看BatteryService 是如何获得电池状态数据的。
BatteryService 类的作用
构造方法如下:
public BatteryService(Context context)
super(context);
mContext = context;
mHandler = new Handler(true /*async*/);
mLed = new Led(context, getLocalService(LightsManager.class));
mBatteryStats = BatteryStatsService.getService();
mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
// 读取系统设定的各种低电量报警值
mCriticalBatteryLevel = mContext.getResources().getInteger(
com.android.internal.R.integer.config_criticalBatteryWarningLevel);
mLowBatteryWarningLevel = mContext.getResources().getInteger(
com.android.internal.R.integer.config_lowBatteryWarningLevel);
mLowBatteryCloseWarningLevel = mLowBatteryWarningLevel + mContext.getResources().getInteger(
com.android.internal.R.integer.config_lowBatteryCloseWarningBump);
mShutdownBatteryTemperature = mContext.getResources().getInteger(
com.android.internal.R.integer.config_shutdownBatteryTemperature);
mBatteryLevelsEventQueue = new ArrayDeque<>();
mMetricsLogger = new MetricsLogger();
// 监听下面的设备文件 无效的充电设备
if (new File("/sys/devices/virtual/switch/invalid_charger/state").exists())
UEventObserver invalidChargerObserver = new UEventObserver()
@Override
public void onUEvent(UEvent event)
final int invalidCharger = "1".equals(event.get("SWITCH_STATE")) ? 1 : 0;
synchronized (mLock)
if (mInvalidCharger != invalidCharger)
mInvalidCharger = invalidCharger;
;
invalidChargerObserver.startObserving(
"DEVPATH=/devices/virtual/switch/invalid_charger");
分析: BatteryService的构造方法首先获得BatteryStatsService的对象,BatteryStatsService 主要的功能是收集系统中各个模块和进程的耗电情况。通过 BatteryStatsService 记录的数据,我们可以找到耗电量大的模块然后加以改进。
接下来是读取了系统设定的各种低电量报警值,包括如下:
mCriticalBatteryLevel:表示电量严重不足时的值,低于这个值系统将关闭。
mLowBatteryWarningLevel:表示电量不足时的值,低于这个值系统将发出警告。
mLowBatteryCloseWarningLevel:表示停止电量不足警告的值。电量高于这个值后系统将停止电量不足的警告。
mShutdownBatteryTemperature:表示电池温度太高的值。高于这个温度系统将关机。
再接下来是创建 mlnvalidChargerObserver 对象,这个对象是一个用于监听 UEvent 事件的对象,这里主要用于监听设备插入了无效充电器的事件,事件发生时将会调用该对象的 onUEvent设备文件方法,如下所示:
final int invalidCharger = "1".equals(event.get("SWITCH_STATE")) ? 1 : 0;
synchronized (mLock)
if (mInvalidCharger != invalidCharger)
mInvalidCharger = invalidCharger;
分析:onEvent()方法中将设置 BatterService的成员变量的值invalidCharger 。这样外界通过BatterService 就能查询充电器是否匹配。最后构造方法中创建了一个BatteryListener对象,并把它加入batterypropreg服务的回调接口中。
先看看BatteryListener类的定义,BatteryListener 是一个Binder 服务类,因此,batterypropreg 服务能通过它传递回数据。这里传递回来的数据类型是BatteryProperties,定义如下:
/frameworks/base/services/core/java/com/android/server/BatteryService.java
private final class BatteryListener extends IBatteryPropertiesListener.Stub
@Override public void batteryPropertiesChanged(BatteryProperties props)
final long identity = Binder.clearCallingIdentity();
try
BatteryService.this.update(props);
finally
Binder.restoreCallingIdentity(identity);
BatteryListener是一个Binder服务类,因此,batterpropreg服务能通过它传递回数据。这里传递回来的数据BatteryProperties,定义如下:
package android.os;
/**
* @hide
*/
public class BatteryProperties implements Parcelable
public boolean chargerAcOnline; //正在用AC充电器充电
public boolean chargerUsbOnline; //正在用USB充电器充电
public boolean chargerWirelessOnline; //正在用无线充电器充电
public int maxChargingCurrent;
public int maxChargingVoltage;
public int batteryStatus; // 电池状态值
public int batteryHealth; //电池的健康度
public boolean batteryPresent; //设备是否在使用电池供电
public int batteryLevel; //电量级别
public int batteryVoltage; //电压值
public int batteryTemperature; //电池温度
public int batteryFullCharge; //电量值
public int batteryChargeCounter; //充电的时间
public String batteryTechnology; //电池的制造商信息
public BatteryProperties()
public void set(BatteryProperties other)
chargerAcOnline = other.chargerAcOnline;
chargerUsbOnline = other.chargerUsbOnline;
chargerWirelessOnline = other.chargerWirelessOnline;
maxChargingCurrent = other.maxChargingCurrent;
maxChargingVoltage = other.maxChargingVoltage;
batteryStatus = other.batteryStatus;
batteryHealth = other.batteryHealth;
batteryPresent = other.batteryPresent;
batteryLevel = other.batteryLevel;
batteryVoltage = other.batteryVoltage;
batteryTemperature = other.batteryTemperature;
batteryFullCharge = other.batteryFullCharge;
batteryChargeCounter = other.batteryChargeCounter;
batteryTechnology = other.batteryTechnology;
/*
* Parcel read/write code must be kept in sync with
* frameworks/native/services/batteryservice/BatteryProperties.cpp
*/
private BatteryProperties(Parcel p)
chargerAcOnline = p.readInt() == 1 ? true : false;
chargerUsbOnline = p.readInt() == 1 ? true : false;
chargerWirelessOnline = p.readInt() == 1 ? true : false;
maxChargingCurrent = p.readInt();
maxChargingVoltage = p.readInt();
batteryStatus = p.readInt();
batteryHealth = p.readInt();
batteryPresent = p.readInt() == 1 ? true : false;
batteryLevel = p.readInt();
batteryVoltage = p.readInt();
batteryTemperature = p.readInt();
batteryFullCharge = p.readInt();
batteryChargeCounter = p.readInt();
batteryTechnology = p.readString();
public void writeToParcel(Parcel p, int flags)
p.writeInt(chargerAcOnline ? 1 : 0);
p.writeInt(chargerUsbOnline ? 1 : 0);
p.writeInt(chargerWirelessOnline ? 1 : 0);
p.writeInt(maxChargingCurrent);
p.writeInt(maxChargingVoltage);
p.writeInt(batteryStatus);
p.writeInt(batteryHealth);
p.writeInt(batteryPresent ? 1 : 0);
p.writeInt(batteryLevel);
p.writeInt(batteryVoltage);
p.writeInt(batteryTemperature);
p.writeInt(batteryFullCharge);
p.writeInt(batteryChargeCounter);
p.writeString(batteryTechnology);
public static final Parcelable.Creator<BatteryProperties> CREATOR
= new Parcelable.Creator<BatteryProperties>()
public BatteryProperties createFromParcel(Parcel p)
return new BatteryProperties(p);
public BatteryProperties[] newArray(int size)
return new BatteryProperties[size];
;
public int describeContents()
return 0;
Healthd守护进程
BatteryService中使用的batterypropreg 服务位于healthd守护进程中,healthd在init.rc中的定义如下:
/system/core/rootdir/init.rc
service healthd /system/bin/healthd
class core
critical
group root system wakelock
这里定义了一个服务 系统初始化时就会启动它。healthd的代码在system/core/healthd下,看一下healthd模块的main()函数,代码如下:
/system/core/healthd/healthd_common.cpp
int healthd_main()
int ret;
klog_set_level(KLOG_LEVEL);
if (!healthd_mode_ops)
KLOG_ERROR("healthd ops not set, exiting\\n");
exit(1);
ret = healthd_init();
if (ret)
KLOG_ERROR("Initialization failed, exiting\\n");
exit(2);
healthd_mainloop(); //进入主循环
KLOG_ERROR("Main loop terminated, exiting\\n");
return 3;
static int healthd_init()
epollfd = epoll_create(MAX_EPOLL_EVENTS);
if (epollfd == -1)
KLOG_ERROR(LOG_TAG,
"epoll_create failed; errno=%d\\n",
errno);
return -1;
healthd_board_init(&healthd_config);
healthd_mode_ops->init(&healthd_config);
wakealarm_init();
uevent_init();
gBatteryMonitor = new BatteryMonitor();
gBatteryMonitor->init(&healthd_config);
return 0;
分析:healthd_init()函数中调用 wakealarm_ini()的目的是创建一个定时器的文件句柄,代码如下:
static void wakealarm_init(void)
wakealarm_fd = timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK);
if (wakealarm_fd == -1)
KLOG_ERROR(LOG_TAG, "wakealarm_init: timerfd_create failed\\n");
return;
if (healthd_register_event(wakealarm_fd, wakealarm_event, EVENT_WAKEUP_FD))
KLOG_ERROR(LOG_TAG,
"Registration of wakealarm event failed\\n");
wakealarm_set_interval(healthd_config.periodic_chores_interval_fast);
分析: wakealarm initO函数调用timerfd_createO创建了一个定时器的文件句柄,并保存在全局变量
wakealarm_fd中,然后通过wakealarm_set_interval()来设置定时器的超时时间. 这个定时器的作用我们看看healthd_mainloopO的代码就能了解:
static void healthd_mainloop(void)
int nevents = 0;
while (1)
struct epoll_event events[eventct];
int timeout = awake_poll_interval;
int mode_timeout;
/* Don't wait for first timer timeout to run periodic chores */
if (!nevents)
periodic_chores();
healthd_mode_ops->heartbeat();
mode_timeout = healthd_mode_ops->preparetowait();
if (timeout < 0 || (mode_timeout > 0 && mode_timeout < timeout))
timeout = mode_timeout;
nevents = epoll_wait(epollfd, events, eventct, timeout);
if (nevents == -1)
if (errno == EINTR)
continue;
KLOG_ERROR(LOG_TAG, "healthd_mainloop: epoll_wait failed\\n");
break;
for (int n = 0; n < nevents; ++n)
if (events[n].data.ptr)
(*(void (*)(int))events[n].data.ptr)(events[n].events);
return;
分析: healthd_mainloop中通过epoll来监听uevent_fd,wakealarm_fd和binder_fd 3个句柄的状态,
一旦有数据到来就会epoll_wait()的调用中返回。当监听到定时器的时间后,定时器事件的处理函数wakealarm_event()将会被调用,代码如下:
static void wakealarm_event(uint32_t /*epevents*/)
unsigned long long wakeups;
if (read(wakealarm_fd, &wakeups, sizeof(wakeups)) == -1)
KLOG_ERROR(LOG_TAG, "wakealarm_event: read wakealarm fd failed\\n");
return;
periodic_chores();
wakealarm_event清空了wakealarm_fd中的数据后,调用了函数periodic_chores(),代码如下:
void healthd_battery_update(void)
// Fast wake interval when on charger (watch for overheat);
// slow wake interval when on battery (watch for drained battery).
int new_wake_interval = gBatteryMonitor->update() ?
healthd_config.periodic_chores_interval_fast :
healthd_config.periodic_chores_interval_slow;
if (new_wake_interval != wakealarm_wake_interval)
wakealarm_set_interval(new_wake_interval);
// During awake periods poll at fast rate. If wake alarm is set at fast
// rate then just use the alarm; if wake alarm is set at slow rate then
// poll at fast rate while awake and let alarm wake up at slow rate when
// asleep.
if (healthd_config.periodic_chores_interval_fast == -1)
awake_poll_interval = -1;
else
awake_poll_interval =
new_wake_interval == healthd_config.periodic_chores_interval_fast ?
-1 : healthd_config.periodic_chores_interval_fast * 1000;
void healthd_dump_battery_state(int fd)
gBatteryMonitor->dumpState(fd);
fsync(fd);
static void periodic_chores()
healthd_battery_update();
分析: battery_update()函数中调用gBatteryMonitor的update()函数来读取电池的状态,然后根据返回值来决定是否更新定时器的时间周期。这样在定时器的作用下,系统中电池的状态会持续更新。
BatteryMonitor类
BatteryMonitor的作用是从设备文件中读取电池的各种参数并返回给上层应用。在healthd的mainO函数中会创建BatteryMonitor对象,并调用它的initO函数,代码如下:
/system/core/healthd/healthd_common.cpp
static int healthd_init()
epollfd = epoll_create(MAX_EPOLL_EVENTS);
if (epollfd == -1)
KLOG_ERROR(LOG_TAG,
"epoll_create failed; errno=%d\\n",
errno);
return -1;
healthd_board_init(&healthd_config);
healthd_mode_ops->init(&healthd_config);
wakealarm_init();
uevent_init();
gBatteryMonitor = new BatteryMonitor();
gBatteryMonitor->init(&healthd_config);
return 0;
/system/core/healthd/BatteryMonitor.cpp
void BatteryMonitor::init(struct healthd_config *hc)
String8 path;
char pval[PROPERTY_VALUE_MAX];
mHealthdConfig = hc;
std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(POWER_SUPPLY_SYSFS_PATH), closedir);
if (dir == NULL)
KLOG_ERROR(LOG_TAG, "Could not open %s\\n", POWER_SUPPLY_SYSFS_PATH);
else
struct dirent* entry;
while ((entry = readdir(dir.get())))
const char* name = entry->d_name;
if (!strcmp(name, ".") || !strcmp(name, ".."))
continue;
// Look for "type" file in each subdirectory
path.clear();
path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH, name);
switch(readPowerSupplyType(path))
case ANDROID_POWER_SUPPLY_TYPE_AC:
case ANDROID_POWER_SUPPLY_TYPE_USB:
case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
path.clear();
path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name);
if (access(path.string(), R_OK) == 0)
mChargerNames.add(String8(name));
break;
case ANDROID_POWER_SUPPLY_TYPE_BATTERY:
mBatteryDevicePresent = true;
if (mHealthdConfig->batteryStatusPath.isEmpty())
path.clear();
path.appendFormat("%s/%s/status", POWER_SUPPLY_SYSFS_PATH,
name);
if (access(path, R_OK) == 0)
mHealthdConfig->batteryStatusPath = path;
if (mHealthdConfig->batteryHealthPath.isEmpty())
path.clear();
path.appendFormat("%s/%s/health", POWER_SUPPLY_SYSFS_PATH,
name);
if (access(path, R_OK) == 0)
mHealthdConfig->batteryHealthPath = path;
if (mHealthdConfig->batteryPresentPath.isEmpty())
path.clear();
path.appendFormat("%s/%s/present", POWER_SUPPLY_SYSFS_PATH,
name);
if (access(path, R_OK) == 0)
mHealthdConfig->batteryPresentPath = path;
if (mHealthdConfig->batteryCapacityPath.isEmpty())
path.clear();
path.appendFormat("%s/%s/capacity", POWER_SUPPLY_SYSFS_PATH,
name);
if (access(path, R_OK) == 0)
mHealthdConfig->batteryCapacityPath = path;
if (mHealthdConfig->batteryVoltagePath.isEmpty())
path.clear();
path.appendFormat("%s/%s/voltage_now",
POWER_SUPPLY_SYSFS_PATH, name);
if (access(path, R_OK) == 0)
mHealthdConfig->batteryVoltagePath = path;
else
path.clear();
path.appendFormat("%s/%s/batt_vol",
POWER_SUPPLY_SYSFS_PATH, name);
if (access(path, R_OK) == 0)
mHealthdConfig->batteryVoltagePath = path;
if (mHealthdConfig->batteryFullChargePath.isEmpty())
path.clear();
path.appendFormat("%s/%s/charge_full",
POWER_SUPPLY_SYSFS_PATH, name);
if (access(path, R_OK) == 0)
mHealthdConfig->batteryFullChargePath = path;
if (mHealthdConfig->batteryCurrentNowPath.isEmpty())
path.clear();
path.appendFormat("%s/%s/current_now",
POWER_SUPPLY_SYSFS_PATH, name);
if (access(path, R_OK) == 0)
mHealthdConfig->batteryCurrentNowPath = path;
if (mHealthdConfig->batteryCycleCountPath.isEmpty())
path.clear();
path.appendFormat("%s/%s/cycle_count",
POWER_SUPPLY_SYSFS_PATH, name);
if (access(path, R_OK) == 0)
mHealthdConfig->batteryCycleCountPath = path;
if (mHealthdConfig->batteryCurrentAvgPath.isEmpty())
path.clear();
path.appendFormat("%s/%s/current_avg",
POWER_SUPPLY_SYSFS_PATH, name);
if (access(path, R_OK) == 0)
mHealthdConfig->batteryCurrentAvgPath = path;
if (mHealthdConfig->batteryChargeCounterPath.isEmpty())
path.clear();
path.appendFormat("%s/%s/charge_counter",
POWER_SUPPLY_SYSFS_PATH, name);
if (access(path, R_OK) == 0)
mHealthdConfig->batteryChargeCounterPath = path;
if (mHealthdConfig->batteryTemperaturePath.isEmpty())
path.clear();
path.appendFormat("%s/%s/temp", POWER_SUPPLY_SYSFS_PATH,
name);
if (access(path, R_OK) == 0)
mHealthdConfig->batteryTemperaturePath = path;
else
path.clear();
path.appendFormat("%s/%s/batt_temp",
POWER_SUPPLY_SYSFS_PATH, name);
if (access(path, R_OK) == 0)
mHealthdConfig->batteryTemperaturePath = path;
if (mHealthdConfig->batteryTechnologyPath.isEmpty())
path.clear();
path.appendFormat("%s/%s/technology",
POWER_SUPPLY_SYSFS_PATH, name);
if (access(path, R_OK) == 0)
mHealthdConfig->batteryTechnologyPath = path;
break;
case ANDROID_POWER_SUPPLY_TYPE_UNKNOWN:
break;
...
;
分析:init()函数首先打开/sys/class/power_supply,该目录下包含了一些子目录,其中battery 目录下存放的是电池信息,这个目录下有很多文件,每个文件对应电池的一种属性,文件的内容就是各个属性的当前值。usb 目录表示USB充电器的信息,里面的online 文件内容为1表示正在用 usb充电。同样 wireless 目录保存的是无线充电器的信息。 ups、 usb_dcp、usb_cdp 和usb_aca 目录则分别表示不同类型的AC充电器的信息。init()函数主要功能是生成所有这些文件的文件名并保存到成员变量中,方便以后读取。完成这个工作后,initO函数创建了BatteryPropertiesRegistrar对象,这个对象是一个Binder服务对象,它就是在BatteryService中使用的batterypropreg服务。
以上是关于Android源码笔记--电量的主要内容,如果未能解决你的问题,请参考以下文章