5.5 BatteryService及BatteryStatsService分析
从前面介绍PMS的代码中发现,PMS和系统中其他两个服务(BatterService及Battery-StatsService)均有交互,其中:
BatteryService提供接口用于获取电池信息,充电状态等。
BatteryStatsService主要用于用电统计,通过它可知谁是系统中的“耗电大户”。
下面先来介绍稍简单的BatteryService。
5.5.1 BatteryService分析
BatteryService由SystemServer创建,代码如下:
battery=new BatteryService(context, lights);
ServiceManager.addService("battery",battery);
下面来看BatteryService的构造函数:
[—>BatteryService.java:Battery Service]
public BatteryService(Context context, LightsService lights){
mContext=context;
mLed=new Led(context, lights);//提示灯控制,感兴趣的读者可自行阅读相关代码
//BatteryService也需要和BatteryStatsService交互
mBatteryStats=BatteryStatsService.getService();
//获取一些配置参数
mCriticalBatteryLevel=mContext.getResources().getInteger(
com.android.internal.R.integer.config_criticalBatteryWarningLevel);
mLowBatteryWarningLevel=mContext.getResources().getInteger(
com.android.internal.R.integer.config_lowBatteryWarningLevel);
mLowBatteryCloseWarningLevel=mContext.getResources().getInteger(
com.android.internal.R.integer.config_lowBatteryCloseWarningLevel);
//启动uevent监听对象,监视power_supply信息
mPowerSupplyObserver.startObserving("SUBSYSTEM=power_supply");
//如果下列文件存在,那么启动另一个uevent监听对象。该uevent事件来自invalid charger
//switch设备(即不匹配的充电设备)
if(new File("/sys/devices/virtual/switch/invalid_charger/state").exists()){
mInvalidChargerObserver.startObserving(
"DEVPATH=/devices/virtual/switch/invalid_charger");
}
update();//①查询HAL层,获取此时的电池信息
}
BatteryService定义了3个非常重要的阈值,分别是:
mCriticalBatteryLevel表示严重低电,其值为4。当电量低于该值时会强制关机。该值由config.xml中的config_criticalBatteryWarningLevel控制。
mLowBatteryWarningLevel表示低电,值为15,当电量低于该值时,系统会报警,例如闪烁LED灯。该值由config.xml中的config_lowBatteryWarningLevel控制。
mLowBatteryCloseWarningLevel表示一旦电量大于此值,就脱离低电状态,即可停止警示灯。该值为20,由config.xml中的config_lowBatteryCloseWarningLevel控制。在BatteryService构造函数的最后调用了update函数,该函数将查询系统电池信息,以
更新BatteryService内部的成员变量。此函数代码如下:
[—>BatteryService.java:update]
private synchronized final void update(){
native_update();//到Native层查询并更新内部变量的值
processValues();//处理更新后的状态
}
1.native_update函数分析
native_update的实现代码如下:
[—>com_android_server_BatteryService.cpp:android_server_BatteryService_update]
static void android_server_BatteryService_update(JNIEnv*env, jobject obj)
{
setBooleanField(env, obj, gPaths.acOnlinePath, gFieldIds.mAcOnline);
……//获取电池信息,并通过JNI设置到Java层对应的变量中
setIntField(env, obj, gPaths.batteryTemperaturePath,
gFieldIds.mBatteryTemperature);
const int SIZE=128;
char buf[SIZE];
//获取信息,以下参数并不是所有手机都支持的
if(readFromFile(gPaths.batteryStatusPath, buf, SIZE)>0)
env->SetIntField(obj, gFieldIds.mBatteryStatus, getBatteryStatus(buf));
else
env->SetIntField(obj, gFieldIds.mBatteryStatus,
gConstants.statusUnknown);
……
}
Android系统中的电池信息如表5-4所示。
mBatteryStatus和mBatteryHealth均有几种不同状态,详细信息可查看getBatteryStatus和getBatteryHealth函数的实现。
上述信息均通过从/sys/class/power_supply目录读取对应文件得到。和以往使用固定路径(可能是Android 2.2版本之前)不同的是,本处先读取power_supply目录中各个子目录中的type文件,然后根据type文件的内容,再做对应处理:
如果type文件的内容为Mains,则读取对应子目录中的online文件,可判断是否为AC充电。
如果type文件的内容为Battery,则从对应子目录中其他的文件中读取电池相关的信息,例如从temp文件获取电池温度,从technology文件读取电池制造技术等。
如果type文件的内容为USB,则读取该子目录中的online文件内容,可判断是否为USB充电。
提示 读者可通过dumpsys battery查看自己手机的电池信息。
2.processValues分析
获取了电池信息后,BatteryService就要做一些处理,此项工作通过processValues完成,其代码如下:
[—>BatteryService.java:processValues]
private void processValues(){
long dischargeDuration=0;
mBatteryLevelCritical=mBatteryLevel<=mCriticalBatteryLevel;
if(mAcOnline){
mPlugType=BatteryManager.BATTERY_PLUGGED_AC;
}else if(mUsbOnline){
mPlugType=BatteryManager.BATTERY_PLUGGED_USB;
}else{
mPlugType=BATTERY_PLUGGED_NONE;
}
//通知BatteryStatsService,该函数以后再分析
mBatteryStats.setBatteryState(mBatteryStatus, mBatteryHealth,
mPlugType, mBatteryLevel, mBatteryTemperature, mBatteryVoltage
);
shutdownIfNoPower();//如果电量不够,则弹出关机对话框
shutdownIfOverTemp();//如果电池过热,则弹出关机对话框
……//根据当前电池信息与上次电池信息比较,判断是否需要发送广播等
if(……/比较前后两次电池信息是否发生变化/){
……//记录信息到日志文件
Intent statusIntent=new Intent();
statusIntent.setFlags(
Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
if(mPlugType!=0&&mLastPlugType==0){
statusIntent.setAction(Intent.ACTION_POWER_CONNECTED);
mContext.sendBroadcast(statusIntent);
}……
if(sendBatteryLow){
mSentLowBatteryBroadcast=true;//发送低电提醒
statusIntent.setAction(Intent.ACTION_BATTERY_LOW);
mContext.sendBroadcast(statusIntent);
}……
mLed.updateLightsLocked();//更新LED灯状态
mLastBatteryStatus=mBatteryStatus;//保存新的电池信息
……
}
processValues函数非常简单,此处不再详述。另外,当电池信息发生改变时,系统会发送uevent事件给BatteryService,此时BatteryService只要重新调用update即可完成工作。