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

BatteryService实现了一个UevenObserver mUEventObserverueventLinux内核用来向用户空间主动上报事件的机制,对于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_propertypower_supply_show_propertytwl4030_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);

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


更多相关文章

  1. Android(安卓)中状态栏(屏幕顶部)消息的显示 Notification
  2. [Android]Activity生命周期之三大循环|五种状态|七种方法
  3. EditText设置可以编辑和不可编辑状态
  4. android 状态栏颜色
  5. drawable 下 selector 状态
  6. android之Notification通知
  7. Android下拉状态栏快捷开关的添加
  8. Android4.0中蓝牙适配器state machine(状态机)的分析
  9. android软键盘状态监听最稳的方法,属性动画手动调整布局,再也不怕

随机推荐

  1. 三子棋 游戏 c++ c
  2. 4-10(二叉搜索树)
  3. 【DB笔试面试234】在Oracle中,如何有效的
  4. 2021-04-10:给定两个可能有环也可能无环的
  5. Oracle Namespace 说明
  6. 【DB笔试面试389】在Oracle中,什么是绑定
  7. PyCharm最新激活教程,不用激活码即可永久
  8. Oracle数据库安全管理
  9. 【静默】在RHEL 6.5上静默安装Oracle 18c
  10. shell脚本实战之编译mysql