您的位置:首页 > 运维架构 > 网站架构

Android电池架构分析

2012-05-31 17:43 459 查看
此文基于博文 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来通知其它关注电源状态的组件。当kernel有power_supply事件上报时,mUEventObserver调用
update()函数,然后update调用native_update从sysfs中读取相关状态(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);

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

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息