Android内核学习之三----------Power源码分析学习(1)

6 篇文章 0 订阅
6 篇文章 0 订阅

 

Android内核学习


-----Power源码分析学习(1)

1.    前言

最近学习了一下Android的Power源码,虽然还没学习通透,但是有点感觉了,怕后面忘了东西,就边学便把东西记录下来吧。如果有大神再致电一二那更是感激不尽了

Android4.4以后Power系统的使用了Linux power supply架构,这个架构的使用又是头疼的地方。不懂再Linux中怎么样使得服务将消息放到socket里面,然后客户端又怎么样通过socket获取到消息。不过还好,这几天看源码的过程有了一些进步,很多地方不再怵怕C和C++了。碰到系统函数就查一下意义,然后看看别人的思路,自己再继续走下去,还是有点收获。后面再把电池系统看一下,因为还有不少地方没明白。这次看的时候把这些个搞明白,顺便记录下学习路程。

2.    Power框架概况

    “ Android4.4的电池管理功能用于管理电池的充、放电功能。整个电池管理的部分包括Linux电池驱动、Android电池服务、电池属性和参数、电池曲线优化四个部分”。这段话是一篇博客中提到的android电池管理的功能部分,是我们后续学习的一个主要根据。

       下图是电池模块的系统结构。这个模块为我们提供了很多有用的信息,在看源码的时候不知道下一步该怎么走的时候这幅图提供了一个很大的帮助。(图是盗来的,URL下回补上去)



3.    power_supply驱动层学习

在学习android的电池驱动以前,需要学习一下power_supply驱动。该驱动的目的就是让用户空间来读取系统内核空间的电池信息。电池信息可以分为AC,battery和usb等。该驱动是通过sys文件系统与用户进行交互。目录为/sys/class/power_supply/。而/sys/class/power_supply/XXX的每个子目录表示一种供电设备的名称。


上图右边方框是该驱动的主要文件,方框里面的文件是我们将要学习的驱动文件。

(1)power_supply_core.c

==============》》init

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;

         power_supply_init_attrs(&power_supply_dev_type);

         return 0;

}

 

 












这是子模块的初始化函数入口,class_creat在sys下创建了一个名为power_supply的class。然后赋值给power_supply_class其中power_supply_class是一个名为class的struct,定义在XXX/kernel/common/include/linux/device.h中。将power_supply_uevent作为回调函挂载在power_supply_class的dev_uevent上。这个回调函数就是当底层发生变化的时候将信息反馈到用户空间。这个函数极为重要,定义在power_supply_sysfs.c中,下面将会分析。后面的power_supply_init_attrs操作是填充device_tepe结构体的,该函数的定义也在power_supply_sysfs.c中。

(2)power_supply_sysfs.c

================》》power_supply_uevent



int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env)

{

         struct power_supply *psy = dev_get_drvdata(dev);

         int ret = 0, j;

         char *prop_buf;

         char *attrname;

         dev_dbg(dev, "uevent\n");

         if (!psy || !psy->dev) {

                   dev_dbg(dev, "No power supply yet\n");

                   return ret;

         }

         dev_dbg(dev, "POWER_SUPPLY_NAME=%s\n", psy->name);

         ret = add_uevent_var(env, "POWER_SUPPLY_NAME=%s", psy->name);

         if (ret)

                   return ret;

         prop_buf = (char *)get_zeroed_page(GFP_KERNEL);

         if (!prop_buf)

                   return -ENOMEM;

         for (j = 0; j < psy->num_properties; j++) {

                   struct device_attribute *attr;

                   char *line;

                   attr = &power_supply_attrs[psy->properties[j]];

                   ret = power_supply_show_property(dev, attr, prop_buf);

                   if (ret == -ENODEV || ret == -ENODATA) {

                            /* 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;

                   line = strchr(prop_buf, '\n');

                   if (line)

                            *line = 0;

                   attrname = kstruprdup(attr->attr.name, GFP_KERNEL);

if (!attrname) {

                            ret= -ENOMEM;

                            gotoout;

                   }

                   dev_dbg(dev,"prop %s=%s\n", attrname, prop_buf);

                   ret= add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf);

                   kfree(attrname);

                   if(ret)

                            gotoout;

         }

 

out:

         free_page((unsignedlong)prop_buf);

         return ret;

}

                        

 


上述的函数就是挂载到dev_uevent上的回调函数。首先是dev_get_drvdata,这个函数是返回驱动的指针,但是我没搞明白为什么可以吧struct device的指针返回给power_supply。然后add_uevent_var(env, "POWER_SUPPLY_NAME=%s",psy->name),这个地方就是将该函数添加发送信息到uevent,也就是往用户控件发送信息。如果psy->name为battery,则发送数据中有一个字符串为:POWER_SUPPLY_NAME=battery。后面的for循环中是将power_supply_attrs中的对应的属性和值,以POWER_SUPPLY_XXXX=xxxx的方式添加到发送的数据中。这个回调函数就是做了这个操作,即将系统中的变化数据组织成特定的格式,通过uevent发送出去(有人讲到使用socket发送的,可能我没走到那么深,后面慢慢完善吧)。具体的发送可以查看振片博客:

http://blog.csdn.net/pillarbuaa/article/details/9062115

(3)power_supply_core.c

===============》》power_supply_init_attrs


void power_supply_init_attrs(struct device_type*dev_type)

{

         int i;

         dev_type->groups= power_supply_attr_groups;

         for (i = 0;i < ARRAY_SIZE(power_supply_attrs); i++)

                   __power_supply_attrs[i]= &power_supply_attrs[i].attr;

}



上述函数应该主要用来填充device_type了。在core.c中还有其他一些辅助函数,这些函数在后面的学习中还会用到,这里将他们一一列举出来:

static int __power_supply_changed_work(struct device*dev, void *data)

static void power_supply_changed_work(structwork_struct *work)

void power_supply_changed(struct power_supply *psy)

static int __power_supply_am_i_supplied(struct device*dev, void *data)

int power_supply_am_i_supplied(struct power_supply*psy)

static int __power_supply_is_system_supplied(structdevice *dev, void *data)

int power_supply_is_system_supplied(void)

int power_supply_set_battery_charged(structpower_supply *psy)

static int power_supply_match_device_by_name(structdevice *dev, void *data)

struct power_supply *power_supply_get_by_name(char*name)

int power_supply_powers(struct power_supply *psy,struct device *dev)

int power_supply_register(struct device *parent,struct power_supply *psy)

static void __exit power_supply_class_exit(void)


未完待续……


继续努力,Keep moving!!!





评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值