现在的位置: 首页 > 综合 > 正文

Android电池架构分析

2013年02月16日 ⁄ 综合 ⁄ 共 11986字 ⁄ 字号 评论关闭

此文基于博文 http://wangzhigang2.iteye.com/blog/1270925稍作补充,主要添加 kernel流程的分析

 BatteryService实现了一个UevenObserver mUEventObserver
uevent
Linux内核用来向用户空间主动上报事件的机制,对于JAVA序来说,只实现UEventObserver的虚函数onUEvent,然后注册即可。
Java
代码
1. private UEventObserver mUEventObserver = new UEventObserver(){
2. @Override
3. public void onUEvent(UEventObserver.UEvent event){
4. update();
5. }
6. }
BatteryService
只关注power_supply的事件,所以在构造函数注册:
Java
代码

public BatteryService(Context context) {
mContext = context;
mBatteryStats = BatteryStatsService.getService();
mLowBatteryWarningLevel = mContext.getResources().getInteger(
com.android.internal.R.integer.config_lowBatteryWarningLevel);
mLowBatteryCloseWarningLevel = mContext.getResources().getInteger(
com.android.internal.R.integer.config_lowBatteryCloseWarningLevel);
//mUEventObserver.startObserving("SUBSYSTEM=power_supply");
String hwNoBatteryStr = SystemProperties.get("hw.nobattery");
hwNoBattery = Boolean.parseBoolean(hwNoBatteryStr);
if (!hwNoBattery)
// Slog.d(TAG,"[baker] Battery service class hwNOBatter = false \n");
mUEventObserver.startObserving("SUBSYSTEM=power_supply");
// set initial status
update();
}
这里需要在 init.rc中设置
hw.nobattery
属性为 false ,以启动监听
Uevent
线程。 (2)update()
update
读取sysfs文件做到同步取得电池信息,然后根据读到的状态更新
BatteryService
的成员变量,并广播一个Intent来通知其它关注电源状态的组件。kernelpower_supply事件上报时,mUEventObserver调用
update()
函数,然后update调用native_updatesysfs中读取相关状态com_android_server_BatteryService.cpp):
Java
代码
1. private synchronized final void update(){
2. native_update(); //
android_server_BatteryService_update()
3. }
(3)
sysfs Linux驱动driver维护着保存电池信息的一组文件sysfs,供应用程序获取电源相关状态:
#defineAC_ONLINE_PATH "/sys/class/power_supply/ac/online" AC
电源连接状态
#define USB_ONLINE_PATH"/sys/class/power_supply/usb/online" USB
电源连接状态
#define BATTERY_STATUS_PATH"/sys/class/power_supply/battery/status"
充电状态 #define BATTERY_HEALTH_PATH"/sys/class/power_supply/battery/health"电池状态
#define BATTERY_PRESENT_PATH"/sys/class/power_supply/battery/present"
使用状态 #define BATTERY_CAPACITY_PATH"/sys/class/power_supply/battery/capacity"电池level
#define BATTERY_VOLTAGE_PATH"/sys/class/power_supply/battery/batt_vol"
电池电压 #define BATTERY_TEMPERATURE_PATH"/sys/class/power_supply/battery/batt_temp"电池温度
#define BATTERY_TECHNOLOGY_PATH"/sys/class/power_supply/battery/technology"
电池技术当电池状态发生变化时,driver会更新这些文件。
以上分析来自 http://wangzhigang2.iteye.com/blog/1270925,但没有具体分析
Kernel
的处理流程。下面接着补充分享下
(4)kernel
(以我调试的 twl4030_charger.c为例)
中断函数:
static irqreturn_t twl4030_charger_interrupt(int irq, void *arg)
{
struct twl4030_bci *bci = arg;
//int gpio_value = 0;
printk("[baker] Enter %s :%s ---- \n",__FILE__,__func__);
dev_dbg(bci->dev, "CHG_PRES irq\n");
ac_charger_state=gpio_get_value(CHARGER_STATE_GPIO);
ac_charger_state = (~ ac_charger_state) & 0x01;
power_supply_changed(&bci->ac);
power_supply_changed(&bci->usb);
printk("[baker] ac_charger_state = %d ---\n",ac_charger_state);
//ac_charger_state = 1 ;
return IRQ_HANDLED;
}
Kernel层,检测到中断后(充电器插入或拔出、电量的变化等),调用
kobject_uevent
上报 Uevent
twl4030_charger_interrupt
power_supply_changed (
power_supply_changed_work)
kobject_uevent() // kobject_uevent.c
power_supply_uevent() // power_supply_sysfs.c
power_supply_show_property()
add_uevent_var()
kobject_uevent中,如果获取不到某个属性,将有可能导致
Uevent
不能上报,致 Onuvent不能执行。
跟踪 kobject_uevent()代码,最终会在
kobject_uevent_env
调用 kset指定的
dev_uevent
(即 uevent_ops->uevent)设置环境变量。而
kset
指定的 uevent是在
power_supply_class_init
中配置。在设置环境变量后,将调用 netlink_broadcast上报
uevent

// power_supply_core.c
static int __init power_supply_class_init(void)
{
power_supply_class = class_create(THIS_MODULE, "power_supply");
if (IS_ERR(power_supply_class))
return PTR_ERR(power_supply_class);
power_supply_class->dev_uevent = power_supply_uevent;
return 0;
}
//power_supply_sysfs.c
power_supply_uevent中,注意
power_supply_show_property
power_supply_show_property
twl4030_charger.c
中填写,当获取属性失败时,返回 -61 ,Uevent将不能上报。
int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env)
{
.....
for (j = 0; j < ARRAY_SIZE(power_supply_static_attrs); j++) {
...
ret = power_supply_show_static_attrs(dev, attr, prop_buf);
if (ret < 0)
goto out;
....
ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf);
kfree(attrname);
if (ret)
goto out;
}
dev_dbg(dev, "%zd dynamic props\n", psy->num_properties);
for (j = 0; j < psy->num_properties; j++) {
....
ret = power_supply_show_property(dev, attr, prop_buf);
if (ret == -ENODEV) {
/* When a battery is absent, we expect -ENODEV. Don't abort;
send the uevent with at least the the PRESENT=0 property */
ret = 0;
continue;
}
if (ret < 0)
goto out;
....
ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf);
kfree(attrname);
if (ret)
goto out;
}
out:
free_page((unsigned long)prop_buf);
}

 

power_supply_sysfs.c中最终会创建uevent

static struct device_attributepower_supply_attrs[] = {
        
/*Properties of type `int' */
         POWER_SUPPLY_ATTR(status),
         POWER_SUPPLY_ATTR(charge_type),
         POWER_SUPPLY_ATTR(health),
         POWER_SUPPLY_ATTR(present),
         POWER_SUPPLY_ATTR(online),
         POWER_SUPPLY_ATTR(technology),
         POWER_SUPPLY_ATTR(cycle_count),
         POWER_SUPPLY_ATTR(voltage_max),
         POWER_SUPPLY_ATTR(voltage_min),
         POWER_SUPPLY_ATTR(voltage_max_design),
         POWER_SUPPLY_ATTR(voltage_min_design),
         POWER_SUPPLY_ATTR(voltage_now),
         POWER_SUPPLY_ATTR(voltage_avg),
         POWER_SUPPLY_ATTR(current_max),
         POWER_SUPPLY_ATTR(current_now),
         POWER_SUPPLY_ATTR(current_avg),
         POWER_SUPPLY_ATTR(power_now),
         POWER_SUPPLY_ATTR(power_avg),
         POWER_SUPPLY_ATTR(charge_full_design),
         POWER_SUPPLY_ATTR(charge_empty_design),
         POWER_SUPPLY_ATTR(charge_full),
         POWER_SUPPLY_ATTR(charge_empty),
         POWER_SUPPLY_ATTR(charge_now),
         POWER_SUPPLY_ATTR(charge_avg),
         POWER_SUPPLY_ATTR(charge_counter),
         POWER_SUPPLY_ATTR(energy_full_design),
         POWER_SUPPLY_ATTR(energy_empty_design),
         POWER_SUPPLY_ATTR(energy_full),
         POWER_SUPPLY_ATTR(energy_empty),
         POWER_SUPPLY_ATTR(energy_now),
         POWER_SUPPLY_ATTR(energy_avg),
         POWER_SUPPLY_ATTR(capacity),
         POWER_SUPPLY_ATTR(capacity_level),
         POWER_SUPPLY_ATTR(temp),
         POWER_SUPPLY_ATTR(temp_ambient),
         POWER_SUPPLY_ATTR(time_to_empty_now),
         POWER_SUPPLY_ATTR(time_to_empty_avg),
         POWER_SUPPLY_ATTR(time_to_full_now),
         POWER_SUPPLY_ATTR(time_to_full_avg),
         POWER_SUPPLY_ATTR(type),
         /*Properties of type `const char *' */
         POWER_SUPPLY_ATTR(model_name),
         POWER_SUPPLY_ATTR(manufacturer),
         POWER_SUPPLY_ATTR(serial_number),
};

 

static ssize_t power_supply_show_property(structdevice *dev,
                                              
  struct device_attribute *attr,
                                                 char *buf) {
         staticchar *type_text[] = {
                   "Battery","UPS", "Mains", "USB",
                   "USB_DCP","USB_CDP", "USB_ACA"
         };
         staticchar *status_text[] = {
                   "Unknown","Charging", "Discharging", "Not charging","Full"
         };
         staticchar *charge_type[] = {
                   "Unknown","N/A", "Trickle", "Fast"
         };
         staticchar *health_text[] = {
                   "Unknown","Good", "Overheat", "Dead", "Overvoltage",
                   "Unspecifiedfailure", "Cold",
         };
         staticchar *technology_text[] = {
                   "Unknown","NiMH", "Li-ion", "Li-poly", "LiFe","NiCd",
                   "LiMn"
         };
         staticchar *capacity_level_text[] = {
                   "Unknown","Critical", "Low", "Normal", "High","Full"
         };
         ssize_tret = 0;
         structpower_supply *psy = dev_get_drvdata(dev);
         constptrdiff_t off = attr - power_supply_attrs;
         unionpower_supply_propval value;

         if(off == POWER_SUPPLY_PROP_TYPE)
                   value.intval= psy->type;
         else
                   ret= psy->get_property(psy, off, &value);

         if(ret < 0) {
                   if(ret == -ENODATA)
                            dev_dbg(dev,"driver has no data for `%s' property\n",
                                     attr->attr.name);
                   elseif (ret != -ENODEV)
                            dev_err(dev,"driver failed to report `%s' property\n",
                                     attr->attr.name);
                   returnret;
         }

         if(off == POWER_SUPPLY_PROP_STATUS)
                   returnsprintf(buf, "%s\n", status_text[value.intval]);
         elseif (off == POWER_SUPPLY_PROP_CHARGE_TYPE)
                   returnsprintf(buf, "%s\n", charge_type[value.intval]);
         elseif (off == POWER_SUPPLY_PROP_HEALTH)
                   returnsprintf(buf, "%s\n", health_text[value.intval]);
         elseif (off == POWER_SUPPLY_PROP_TECHNOLOGY)
                   returnsprintf(buf, "%s\n", technology_text[value.intval]);
         elseif (off == POWER_SUPPLY_PROP_CAPACITY_LEVEL)
                   returnsprintf(buf, "%s\n", capacity_level_text[value.intval]);
         elseif (off == POWER_SUPPLY_PROP_TYPE)
                   returnsprintf(buf, "%s\n", type_text[value.intval]);
         elseif (off >= POWER_SUPPLY_PROP_MODEL_NAME)
                   returnsprintf(buf, "%s\n", value.strval);

         returnsprintf(buf, "%d\n", value.intval);

}

 

其中这里

      POWER_SUPPLY_ATTR(status),
        
POWER_SUPPLY_ATTR(charge_type),
         POWER_SUPPLY_ATTR(health),

          ……

是可能会创建的uevent节点
 
如:/sys/class/power_supply/battery/status

但是什么情况下驱动往里面送数据的呢?

power_supply_show_property()函数。

         ssize_t ret = 0;
        
structpower_supply *psy = dev_get_drvdata(dev);
         constptrdiff_t off = attr - power_supply_attrs;

       ……

通过offer来定位它最终把数据写好相对应的节点下。

battery驱动里会用到一些宏,这些宏的位置和 power_supply_attrs[] 对应的位置是一样的。

power_supply.h

enum power_supply_property {
        
/*Properties of type `int' */
         POWER_SUPPLY_PROP_STATUS= 0,
         POWER_SUPPLY_PROP_CHARGE_TYPE,
         POWER_SUPPLY_PROP_HEALTH,
         POWER_SUPPLY_PROP_PRESENT,
         POWER_SUPPLY_PROP_ONLINE,
         POWER_SUPPLY_PROP_TECHNOLOGY,
         POWER_SUPPLY_PROP_CYCLE_COUNT,
         POWER_SUPPLY_PROP_VOLTAGE_MAX,
         POWER_SUPPLY_PROP_VOLTAGE_MIN,
         POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
         POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
         POWER_SUPPLY_PROP_VOLTAGE_NOW,
         POWER_SUPPLY_PROP_VOLTAGE_AVG,
         POWER_SUPPLY_PROP_CURRENT_MAX,
         POWER_SUPPLY_PROP_CURRENT_NOW,
         POWER_SUPPLY_PROP_CURRENT_AVG,
         POWER_SUPPLY_PROP_POWER_NOW,
         POWER_SUPPLY_PROP_POWER_AVG,
         POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
         POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN,
         POWER_SUPPLY_PROP_CHARGE_FULL,
         POWER_SUPPLY_PROP_CHARGE_EMPTY,
         POWER_SUPPLY_PROP_CHARGE_NOW,
         POWER_SUPPLY_PROP_CHARGE_AVG,
         POWER_SUPPLY_PROP_CHARGE_COUNTER,
         POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
         POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN,
         POWER_SUPPLY_PROP_ENERGY_FULL,
         POWER_SUPPLY_PROP_ENERGY_EMPTY,
         POWER_SUPPLY_PROP_ENERGY_NOW,
         POWER_SUPPLY_PROP_ENERGY_AVG,
         POWER_SUPPLY_PROP_CAPACITY,/* in percents! */
         POWER_SUPPLY_PROP_CAPACITY_LEVEL,
         POWER_SUPPLY_PROP_TEMP,
         POWER_SUPPLY_PROP_TEMP_AMBIENT,
         POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
         POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
         POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
         POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
         POWER_SUPPLY_PROP_TYPE,/* use power_supply.type instead */
         /*Properties of type `const char *' */
         POWER_SUPPLY_PROP_MODEL_NAME,
         POWER_SUPPLY_PROP_MANUFACTURER,
         POWER_SUPPLY_PROP_SERIAL_NUMBER,
};

所以off = attr - power_supply_attrs;   

只要attr=POWER_SUPPLY_ATTR(status)    减去 power_supply_attrs.就可以算出off的值了。

然后->

         if (off == POWER_SUPPLY_PROP_STATUS)
                  
returnsprintf(buf, "%s\n", status_text[value.intval]);
         elseif (off == POWER_SUPPLY_PROP_CHARGE_TYPE)
                   returnsprintf(buf, "%s\n", charge_type[value.intval]);
         elseif (off == POWER_SUPPLY_PROP_HEALTH)
                   returnsprintf(buf, "%s\n", health_text[value.intval]);
         elseif (off == POWER_SUPPLY_PROP_TECHNOLOGY)
                   returnsprintf(buf, "%s\n", technology_text[value.intval]);
         elseif (off == POWER_SUPPLY_PROP_CAPACITY_LEVEL)
                   returnsprintf(buf, "%s\n", capacity_level_text[value.intval]);
         elseif (off == POWER_SUPPLY_PROP_TYPE)
                   returnsprintf(buf, "%s\n", type_text[value.intval]);
         elseif (off >= POWER_SUPPLY_PROP_MODEL_NAME)
                   returnsprintf(buf, "%s\n", value.strval);
         returnsprintf(buf, "%d\n", value.intval);

这个就不用解释了。设备节点和这些宏对应起来了。

 

 

抱歉!评论已关闭.