1. 程式人生 > >Android核心學習之三----------Power原始碼分析學習(1)

Android核心學習之三----------Power原始碼分析學習(1)

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!!!