編輯:關於Android編程
隨著移動智能設備的快速發屏,電池的續航能力在很大情況下誘導了大眾消費者的購買選擇,android系統對電源管理的合理與否直接影響到電池的續航能力,而電池系統作為其中的一部分,主要用於對電池狀態的監控(電池電量、電池狀態及電池溫度等)。下面將詳細分析android的電池系統架構。
Android系統中對電池的管理驅動層繼承了linux下的power supply class,而在用戶層則是在BatteryService.java中通過廣播的方式將如下一些電池相關的屬性上報給上層app使用。這些屬性都是在java中聲明,在jni中調用更新的。
而這些屬性都是在com_android_server_BatteryService.cpp這個本地代碼-jni中通過調用sys文件系統訪問驅動層中電池相應的狀態進行更新的。
代碼路徑:
frameworks/base/services/java/com/android/server/BatteryService.java
BatteryService 作為電池及充電相關的服務,主要作了如下幾件事情: 監聽 UEvent、讀取sysfs 中的狀態 、廣播Intent.ACTION_BATTERY_CHANGED。
BatteryService實現了兩個UEvenObserver mUEventObserver(如上代碼所示)。uevent是Linux 內核用來向用戶空間主動上報事件的機制,對於JAVA程序來說,只實現 UEventObserver的虛函數 onUEvent,然後注冊即可。
update讀取sysfs文件做到同步取得電池信息,然後根據讀到的狀態更新BatteryService 的成員變量,並廣播一個Intent來通知其它關注電源狀態的組件。當kernel有power_supply事件上報時,mUEventObserver調用update()函數,然後update 調用native_update從sysfs中讀取相關狀態(com_android_server_BatteryService.cpp)。
通過廣播Intent.ACTION_BATTERY_CHANGED,將電池狀態、電池電量、電池工藝等屬性打包,發送給其它的使用者,也就是說,只要在app程序裡監聽了Intent.ACTION_BATTERY_CHANGED這個廣播,就能獲取到電池的各種狀態屬性!
代碼路徑:
frameworks/base/services/jni/com_android_server_BatteryService.cpp
這是battery用戶空間的本地代碼,調用sys文件系統訪問驅動程序,並向上層BatteryService封裝本地方法以隔離平台化的差異。
在這個文件的頭部有如下定義:
這個就是底層battery驅動所生成的sys文件系統路徑。
在這個文件裡封裝了一個本地方法:
供上層BatteryService使用。另外,在這個文件中通過GetFieldID,得到BatteryService.java類中聲明的電池屬性ID,如下:
關於java與c/c++互調的問題,這裡就不再贅訴了,網上有很多的資料。
在這個文件裡通過操作相應的sys文件系統來獲取電池的各種屬性值,看看如下這段代碼:
POWER_SUPPLY_PATH已經在文件頭部定義過了,對應路徑:/sys/class/power_supply,然後遍歷整個文件夾,查找各個能源供應設備的各種屬性,如上選中部分是用來查找交流設備的屬性的。
各能源設備屬性概況如下:
/sys/class/power_supply/ac/online AC 電源連接狀態
/sys/class/power_supply/usb/online USB電源連接狀態
/sys/class/power_supply/battery/status 充電狀態
/sys/class/power_supply/battery/health 電池狀態
/sys/class/power_supply/battery/present 使用狀態
/sys/class/power_supply/battery/capacity 電池 level
/sys/class/power_supply/battery/batt_vol 電池電壓
/sys/class/power_supply/battery/batt_temp 電池溫度
/sys/class/power_supply/battery/technology 電池技術
當供電設備的狀態發生變化時,driver會更新這些文件,然後通過jni中的本地方法android_server_BatteryService_update向java層發送信息。
android系統電池部分的驅動程序,繼承了傳統linux系統下的Power Supply驅動程序架構,Battery驅動程序通過Power Supply驅動程序生成相應的sys文件系統,從而向用戶空間提供電池各種屬性的接口。Linux標准的 Power Supply驅動程序所使用的文件系統路徑為:/sys/class/power_supply ,其中的每個子目錄表示一種能源供應設備。
Power Supply驅動程序頭文件kernel/include/linux/power_supply.h,注冊和注銷驅動程序的函數如下:
intpower_supply_register(struct device *parent,struct power_supply *psy);
voidpower_supply_unregister(struct power_supply *psy);
structpower_supply {
constchar *name; /*設備名稱*/
enumpower_supply_type type; /* 類型 */
enumpower_supply_property *properties; /* 屬性指針 */
size_tnum_properties; /*屬性的數目*/
char**supplied_to;
size_tnum_supplicants;
int(*get_property)(struct power_supply *psy, /*獲得屬性*/
enumpower_supply_property psp,
unionpower_supply_propval *val);
void(*external_power_changed)(struct power_supply *psy);
/* ...... 省略部分內容 */
};
對應的驅動程序:power_supply
來看看power_supply_sysfs.c這個文件。這裡主要是對諸如如下這些電源設備屬性創建uevent!
這些uevent節點不一定都會創建,節點創建與否還和具體的電源設備驅動傳進來的num_properties和properties有關,在創建uevent函數power_supply_uevent中可以很容易的看出這一點:
目前項目(T808、T828)中所使用的電池檢測與管理方式是POC ADC方式,對應的驅動文件是:
mediatek/kernel/drivers/power/battery_common.c
在此文件的probe函數裡有如下內容:
可以看出,在這裡將ac、usb及battery三種電源供應設備注冊到了power supply core中去了,而相應的全局結構體變量ac_main、usb_main及battery_main作了如下定義:
各個電源設備所需要創建的uevent節點由這裡傳入的xx_props決定,相應的定義如下:
可發現:ac和usb只創建了一個online屬性,上層app通過判斷ac和usb的online狀態便可知道當前系統是由什麼設備在充電了;而battery則創建了如:status、health、present、capacity、batt_vol等等和電池相關的諸多屬性,上層app通過這些電池屬性uevent便可監控電池的當前工作狀態了。
舉例說明一下這些屬性的狀態改變後是如何向系統發送更新消息的,來看看ac online的狀態更新。
該函數在power supply sysfs中show property的時候得到調用,而AC_ONLINE作為ac電源唯一的屬性會在ac_update中得到更新:
ac_update則最終會在bat_thread_kthread中進行輪循,在這裡有一個全局的BMT_status,作為整個電源供應設備的各種屬性傳達!另外再來看看CHARGING_CONTROL battery_charging_control這個全局的函數指針,原型定義如下:
chr_control_interface函數原型如下:
對應文件路徑:
mediatek/platform/mt6572/kernel/drivers/power/charging_hw_pmic.c
charging_func函數指針數組定義如下:
可以看出通過如下的調用關系:
最終會調用到由:
在這裡通過pmic的硬件狀態來獲取相應的信息。
理想中的電池是沒有內阻的,電池電壓的消耗都在外部的負載上。
但實際情況卻不是這樣的,正由於電池內阻的存在,通過直接測量電池電壓(ADC)的方式獲得的電池電量都會存在一定的誤差,不管電池是處於供電還是放電的狀態,這種誤差都會存在,特別是在電池電量滿、電池電量空及關機充電的情況下這種誤差很容易被用戶察覺,從而帶來不好的用戶體驗。
那麼針對電池內阻導致的這個誤差,完全可以通過數學方式進行糾正。
通過上圖可知,只要知道了電池內阻,就可以很容易地糾正這種誤差。但電池的內阻不是不變的,而是隨著電池電量的變化而變化的,不同型號的電池,這種特性還不一樣,那麼要想得到比較准確的電池電量,就很有必要讓電池廠提供一組完整的電池電壓與電池內阻的關系表了!
充放電過程中誤差的糾正代碼:
mediatek/kernel/drivers/power/battery_meter.c
在oam_run中有如下代碼:
函數mtk_imp_tracking就是針對充放電過程中電池內阻所產生的壓降所作的一個△V的修正。
另外一個是,由於電池特性,在開關機的時候會出現電量跳變的問題,在系統中采用了將關機時的UI電量保存到RTC中,在下次開機的過程中用實際檢測到的電量值與保存到RTC中的UI電量值進行比較判斷,由於用戶可能會更換電池,這兩者之間的差值控制在了20%的范圍內,也就是說:實際檢測到的電量值在RTC中保存的UI電量值的20%范圍內則使用保存在RTC中的UI電量值作為當前電池的電量值;如果實際檢測到的電量值超過了RTC中UI電量值的20%,則認為用戶更換了電池,用實際檢測到的電量值作為當前電池的電量值。
相應的判斷代碼如下:
在頭文件:
mediate/custiom/mt6572/kernel/battery/battery/cust_battery_meter.h
中有如下定義
關於電池電量檢測的算法過程,這裡不再贅述,在MTK發布的Customer_Training_Battery_Charging.pdf這個文件中有比較詳細的講述。
通知使用權打開方式設置——提示音和通知——通知使用權。詳細界面如圖:存在需要擁有通知使用權應用時:不存在需要擁有通知使用權
概述:之前有個需求是寫一個公告,需要無限輪詢效果,第一時間想到的是用viewpager實現。網上一看,幾乎都是用viewpager實現的。於是我也手動實現了一下,發現其實
本文實例為大家分享了Android仿安卓微信6.0的具體代碼,供大家參考,具體內容如下wechat6Activity.java的代碼:package siso.geekw
SQLite是一款輕量級的關系型數據庫,它運算速度快,占用資源少,通常只需要幾百k的內存就夠了,支持標准的sql語法和數據庫的ACID事務。在android中為了能夠更加