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所示。

5.5 BatteryService及BatteryStatsService分析 - 图1

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即可完成工作。