Android电池管理
1:Android电池管理结构
相关代码路径:
java代码:
frameworks/frameworks/base/services/java/com/android/server/BatteryService.java
frameworks/frameworks/base/core/java/android/os//BatteryManager.javaframeworks/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
JNI代码:
frameworks/base/services/jni/com_android_server_BatteryService.cpp
kerneldriver 代码:
drivers/power/xx_battery.c
2:在SystemServer.java中可以看到启动BatteryService的代码:
SystemServer.java
@Override
public void run() {
……………………………….
Slog.i(TAG,"Battery Service");
battery = newBatteryService(context, lights);
ServiceManager.addService("battery", battery);
……………………………….
}
BatteryManager.java电池的各个状态:
信息 |
类型 |
状态 |
值 |
|
Status 电池状态 |
int |
BATTERY_STATUS_UNKNOWN |
未知 |
1 |
BATTERY_STATUS_CHARGING |
充电状态 |
2 |
||
BATTERY_STATUS_DISCHARGING |
放电中 |
3 |
||
BATTERY_STATUS_NOT_CHARGING |
未充电 |
4 |
||
BATTERY_STATUS_FULL |
电池满 |
5 |
||
Health 电池健康情况 |
int
|
BATTERY_HEALTH_UNKNOWN |
未知 |
1 |
BATTERY_HEALTH_GOOD |
良好 |
2 |
||
BATTERY_HEALTH_OVERHEAT |
过热 |
3 |
||
BATTERY_HEALTH_DEAD |
没电 |
4 |
||
BATTERY_HEALTH_OVER_VOLTAGE |
过电压 |
5 |
||
BATTERY_HEALTH_UNSPECIFIED_FAILURE |
未知错误 |
6 |
||
BATTERY_HEALTH_COLD |
|
7 |
||
Plugged 充电类型 |
int
|
BATTERY_PLUGGED_AC |
充电器 |
1 |
BATTERY_PLUGGED_USB |
USB |
2 |
||
BATTERY_PLUGGED_UNKNOWN |
未知 |
3 |
||
level |
int |
电池电量,数字 |
|
|
scale |
int |
电池最大容量 |
|
|
present |
boolean |
使用状态 |
|
|
icon-small |
int |
图标ID |
|
|
voltage |
int |
电池伏数 |
|
|
temperature |
int |
电池温度,0.1度单位。 |
|
|
Technology |
String |
电池技术 |
|
|
invalid_charger |
String |
无效的充电器 |
|
|
3、BatteryService
BatteryService 作为电池及充电相关的服务: 监听Uevent、读取 sysfs
里中的状态 、广播 Intent.ACTION_BATTERY_CHANGED。
(1)、mPowerSupplyObserver
BatteryService 实现了一个 UevenObserver mPowerSupplyObserver。
uevent 是 Linux 内核用来向用户空间主动上报事件的机制,对于 JAVA 程
序来说,只实现 UEventObserver 的虚函数 onUEvent,然后注册即可。
private UEventObserver mPowerSupplyObserver= new UEventObserver()
{
@Override
public voidonUEvent(UEventObserver.UEvent event)
{
update();
}
};
BatteryService只关注 power_supply 的事件,所以在构造函数注册:
public BatteryService(Context context,LightsService lights)
{
mContext = context;
mLed = new Led(context, lights);
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);
mFullBatteryLevel =mContext.getResources().getInteger(
com.android.internal.R.integer.config_fullBatteryLevel);
mPowerSupplyObserver.startObserving("SUBSYSTEM=power_supply");
// watch for invalid charger messagesif the invalid_charger switch
// exists
if (newFile("/sys/devices/virtual/switch/invalid_charger/state").exists())
{
mInvalidChargerObserver.startObserving("DEVPATH=/devices/virtual/switch/invalid_charger");
}
// set initial status
update();
}
(2)、update()
update 读取 jni做到同步取得电池信息, 然后根据读到的状态更新
BatteryService的成员变量,并广播一个 Intent 来通知其它关注电源状态的
组件。
当 kernel 有 power_supply 事 件 上 报 时 ,mPowerSupplyObserver调 用
update()函数,然后 update 调用 native_update 从 jni处读取相关状态
(com_android_server_BatteryService.cpp):
private synchronized final void update()
{
native_update();
processValues();
}
然后:
privatenative void native_update();
(3)、sysfs
Linux 驱动 driver 维护着保存电池信息的一组文件 sysfs,供应用程序获
取电源相关状态.
当电池状态发生变化时,driver 会更新这些文件。
4:数据传送: processValues()里有调用sendIntent():
private final void sendIntent()
{ // Pack up the values and broadcast them to everyone
Intent intent = newIntent(Intent.ACTION_BATTERY_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY |Intent.FLAG_RECEIVER_REPLACE_PENDING);
int icon = getIcon(mBatteryLevel);
intent.putExtra(BatteryManager.EXTRA_STATUS, mBatteryStatus);
intent.putExtra(BatteryManager.EXTRA_HEALTH, mBatteryHealth);
intent.putExtra(BatteryManager.EXTRA_PRESENT, mBatteryPresent);
intent.putExtra(BatteryManager.EXTRA_LEVEL, mBatteryLevel);
intent.putExtra(BatteryManager.EXTRA_SCALE, BATTERY_SCALE);
intent.putExtra(BatteryManager.EXTRA_ICON_SMALL, icon);
intent.putExtra(BatteryManager.EXTRA_PLUGGED,mPlugType);
intent.putExtra(BatteryManager.EXTRA_VOLTAGE, mBatteryVoltage);
intent.putExtra(BatteryManager.EXTRA_TEMPERATURE, mBatteryTemperature);
intent.putExtra(BatteryManager.EXTRA_TECHNOLOGY, mBatteryTechnology);
intent.putExtra(BatteryManager.EXTRA_INVALID_CHARGER, mInvalidCharger);
if (false)
{
Slog.d(TAG, "level:" +mBatteryLevel + " scale:" + BATTERY_SCALE + " status:"
+ mBatteryStatus + "health:" + mBatteryHealth + " present:" + mBatteryPresent
+ " voltage: " +mBatteryVoltage + " temperature: " + mBatteryTemperature
+ " technology: "+ mBatteryTechnology + " AC powered:" + mAcOnline
+ " USB powered:"+ mUsbOnline + " Unknown powered: " + mUnknownOnline
+ " icon:" + icon+ " invalid charger:" + mInvalidCharger);
}
ActivityManagerNative.broadcastStickyIntent(intent, null);
}
5:数据接收:
BatteryController.Java里:
public BatteryController(Context context) {
mContext = context;
IntentFilter filter = newIntentFilter();
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
context.registerReceiver(this, filter);
}
接着:
public void onReceive(Context context,Intent intent) {
final String action =intent.getAction();
if(action.equals(Intent.ACTION_BATTERY_CHANGED)) {
final int level =intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
final boolean plugged =intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0;
final int status =intent.getIntExtra(BatteryManager.EXTRA_STATUS,BatteryManager.BATTERY_STATUS_UNKNOWN);
// @ { QIA-1189,update status baricon when battery state changed.
final int icon;
final boolean isBartteryPresent =intent.getBooleanExtra(BatteryManager.EXTRA_PRESENT,
false);
if (isBartteryPresent) {
icon =(BatteryManager.BATTERY_STATUS_CHARGING == status) ?R.drawable.stat_sys_battery_charge
:R.drawable.stat_sys_battery;
} else {
icon =R.drawable.stat_sys_battery_absent;
}
// @ }
int N = mIconViews.size();
for (int i=0; i ImageView v =mIconViews.get(i); v.setImageResource(icon); v.setImageLevel(level); v.setContentDescription(mContext.getString(R.string.accessibility_battery_level, level)); } N = mLabelViews.size(); for (int i=0; i TextView v =mLabelViews.get(i); v.setText(mContext.getString(R.string.status_bar_settings_battery_meter_format, level)); } mIcon = icon; mLevel = level; } } 6:控制显示 PhoneStatusBar.java // ================================================================================ //Constructing the view //================================================================================ protected ViewmakeStatusBarView() { ……………….. mBatteryController =newBatteryController(mContext); mBatteryController.addIconView((ImageView)sb.findViewById(R.id.battery)); ……………… 问题一:电量过低自动关机流程 other:充电100%和充电完成的区别 充电100%是level=100,并不等同于充电完成,充电完成的判断是BATTERY_STATUS_FULL 若要statusbar电池状态图:插线充电满显示充电完成图(未充电图),插线充电充满100%但未充满显示充电100%图(充电图);未插线充电显示未充电图标,则对于4.3,4.4系统需要修改BatteryController。java中接收action时对电池icon的处理: 增加boolean batteryFull 值判断 boolean batteryFull = false; boolean plugged = false; switch (status) { case BatteryManager.BATTERY_STATUS_CHARGING: batteryFull = false; plugged = true; break; case BatteryManager.BATTERY_STATUS_FULL: plugged = true; batteryFull = true; break; } int icon = (plugged && !batteryFull) ? R.drawable.stat_sys_battery_charge:: R.drawable.stat_sys_battery; 同时去除level=100的判断 ......................... for (BatteryStateChangeCallback cb : mChangeCallbacks) { cb.onBatteryLevelChanged(level, (plugged && !batteryFull)); } ......................... 在实现onBatteryLevelChanged处只需调整对应充电字串显示。 对于通知栏电池快捷显示,需改变接口BatteryStateChangeCallback中onBatteryLevelChanged方法
1: BatteryService.java
update() /processValues() /shutdownIfNoPower():
条件:
(mBatteryLevel <= 0 && !isPowered() && ActivityManagerNative.isSystemReady())
执行:
Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); mContext.startActivity(intent);
2:启动ShutdownActivity.java
ShutdownThread.shutdown(ShutdownActivity.this, mConfirm);
3:调到ShutdownThread.java
shutdown(final Context context, boolean confirm).
根据confirm的boolean值决定是哪种关机方式;电量过低confirm=false,是自动关机。
注:1>:mBatteryLevel赋值:
else if ("level".equals(key)) {
mBatteryLevel = Integer.parseInt(value);
2>:isPowered()
3>:ActivityManagerNative.isSystemReady()
问题二A:低电量弹出警告对话框
1: BatteryService.java
update() /processValues() /shutdownIfNoPower():
……………………………………………………..
final boolean sendBatteryLow = !plugged
&& mBatteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
&& mBatteryLevel <= mLowBatteryWarningLevel
&& (oldPlugged || mLastBatteryLevel > mLowBatteryWarningLevel);
…………………………………………………….
if (sendBatteryLow) {
mSentLowBatteryBroadcast = true;
statusIntent.setAction(Intent.ACTION_BATTERY_LOW);
mContext.sendBroadcast(statusIntent);
}
2: PhoneApp.java
protected class PhoneAppBroadcastReceiver extends BroadcastReceiver{
……………………
else if (action.equals(Intent.ACTION_BATTERY_LOW)) {
Log.i("_battery", "PA-----XXX------Recvier:ACTION_BATTERY_LOW+will notifier.sendBatteryLow()--");
if (VDBG) Log.d(LOG_TAG, "mReceiver: ACTION_BATTERY_LOW");
notifier.sendBatteryLow(); // Play a warning tone if in-call
………………………..
问题二B:低电量弹出警告对话框
通过广播接收处理
PowerUI.java
在start()方法里注册:
……………………………..
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
……………………………
mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
在接收里处理:
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
………………………
if (!plugged
&& (bucket < oldBucket || oldPlugged)
&& mBatteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
&& bucket < 0) {
//弹出低电量请连接充电器对话框,此对话框不会自动消失,必须处理。若连上充电器则调用//dismissLowBatteryWarning()自动消失。
showLowBatteryWarning();
// only play SFX when the dialog comes up or the bucket changes
if (bucket != oldBucket || oldPlugged) {
//弹出低电量请连接充电器对话框的警告声音。
playLowBatterySound();
}
}
………………………
}
}
}