天天看點

android電池電量更新,android 電池(三):android電池系統

一、電池系統結構

Android中的電池使用方式主要有三種:AC、USB、Battery

等不同的模式。在應用程式層次,通常包括了電池狀态顯示的功能。是以從 Android

系統的軟體方面(包括驅動程式和使用者空間内容)需要在一定程度上獲得電池的狀态,電池系統主要負責電池資訊統計、顯示。電池系統的架構如下所示:

android電池電量更新,android 電池(三):android電池系統

自下而上, Android 的電池系統分成以下幾個部分:

1、驅動程式:

特定硬體平台電池的驅動程式,用 Linux的Power Supply 驅動程式,實作向使用者空間提供資訊。Battery

驅動程式需要通過sys檔案系 統向使用者空間提供接口, sys檔案系統的路徑是由上層的程式指定的。Linux标準的 Power

Supply驅動程式 所使用的檔案系統路徑為:/sys/class/power_supply

,其中的每個子目錄表示一種能源供應裝置的名稱。

android電池電量更新,android 電池(三):android電池系統

Power Supply 驅動程式的頭檔案在

include/linux/power_supply.h中定義,注冊和登出驅動程式的函數如下所示:

intpower_supply_register(structdevice *parent,structpower_supply *psy);

voidpower_supply_unregister(structpower_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)(structpower_supply *psy,

enumpower_supply_property psp,

unionpower_supply_propval *val);

void(*external_power_changed)(structpower_supply *psy);

};

Linux中驅動程式:power_supply

android電池電量更新,android 電池(三):android電池系統

2、本地代碼 - JNI

代碼路徑:

frameworks/base/services/jni/com_android_server_BatteryService.cpp

這個類調用sys檔案系統通路驅動程式,也同時提供了JNI的接口。

這個檔案提供的方法清單如下所示:

staticJNINativeMethod sMethods[] = {

{"native_update","()V", (void*)android_server_BatteryService_update},

};

上面的JNINativeMethod[cpp]view plaincopy

typedefstruct{

constchar* name;

constchar* signature;

void* fnPtr;

} JNINativeMethod;

name對應java中的method

name; signature是參數清單,由一串字元串表示,fnPtr是function pointer,

指向jni中的method。

最難了解的就是signature了,裡面包含JAVAC/C++之間的參數的map,即每個java類型,都有一個c/c++類型與之對應。

JNI是JAVA

Native Interface的縮寫,意思是“JAVA 本地接口”。JNI幫助JAVA能和其它程式設計語言(C++ , C,

彙編)和庫進行互動。

“()V”JNI函數的參數和傳回值,()"填的是參數(這裡為空),傳回值也為void空

處理的流程為根據裝置類型判定裝置後, 得到各個裝置的相關屬性,則需要得到更多得 資訊。例如:果是交流或者 USB 裝置,隻需

要得到它們是否線上( onLine );如果是電 池裝置,則需要得到更多的資訊,例如狀态 ( status ),健康程度(

health ),容 量( capacity ),電壓 ( voltage_now )等。

Linux 驅動 driver 維護着儲存電池資訊的一組檔案

sysfs,供應用程式擷取電源相關狀态:

#define AC_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 會更新這些檔案。傳送資訊到java

先看一下/frameworks/base/services/jni/com_android_server_BatteryService.cpp的register_android_server_BatteryService方法。可以看到,每個資訊都是從相應的檔案中讀取到的。

/frameworks/base/services/java/com/android/server/BatteryService.java中注冊一個UEventObserver,每次電池資訊有更新時,會調用update(),update()方法分兩步,先調用native_update()方法通過JNI讀取上面幾個檔案中的資訊,然後通過Broadcast廣播出去。

TAG =

BatteryServices.class.getSimpleName(); //得到類的簡寫名稱BatteryServices

再看一下應用程式層面如何擷取這些資訊的。

/packages/apps/Settings/src/com/android/settings/BatteryInfo.java檔案中,在onResume()方法中通過registerReceiver(mIntentReceiver,

mIntentFilter);注冊一個Receiver,最終在onReceive()方法中擷取資訊。

3 、JAVA 代碼

代碼路徑:

frameworks/base/services/java/com/android/server/BatteryService.java

frameworks/base/core/java/android/os/ : android.os :包中和Battery

相關的部分

frameworks/base/core/java/com/android/internal/os/:和Battery

相關的内部部分 BatteryService.java 通過調用, BatteryService

JNI來實作com.android.server包中的

BatteryService類。BatteryManager.java中定義了一些 JAVA

應用程式層可以使用的常量。

android電池電量更新,android 電池(三):android電池系統

電池系統在驅動程式層以上的部分都是Android

系統中預設的内容。在移植的過程中基本不需要改動。電池系統需要移植的部分僅有Battery驅動程式。Battery 驅動程式用Linux

标準的Power

Supply驅動程式與上層的接口是sys檔案系統,主要用于讀取sys檔案系統中的檔案來擷取電池相關的資訊。整個系統中各部件的聯系:

BatteryService 作為電池及充電相關的服務: 監聽 Uevent、讀取sysfs 裡中的狀态

、廣播Intent.ACTION_BATTERY_CHANGED。

(1)、mUEventObserver

BatteryService實作了一個UevenObserver mUEventObserver。uevent是Linux

核心用來向使用者空間主動上報事件的機制,對于JAVA程式來說,隻實作 UEventObserver的虛函數

onUEvent,然後注冊即可。

BatteryService隻關注 power_supply 的事件,是以在構造函數注冊:

(2)、update()

update讀取sysfs檔案做到同步取得電池資訊, 然後根據讀到的狀态更新 BatteryService

的成員變量,并廣播一個Intent來通知其它關注電源狀态的 元件。

當kernel有power_supply事件上報時, mUEventObserver調用update()函數,然後update

調用native_update從sysfs中讀取相關狀态(com_android_server_BatteryService.cpp):

(3)、sysfs

Linux 驅動 driver 維護着儲存電池資訊的一組檔案 sysfs,供應用程式獲

取電源相關狀态:

二、Uevent部分

Uevent是核心通知android有狀态變化的一種方法,比如USB線插入、拔出,電池電量變化等等。其本質是核心發送(可以通過socket)一個字元串,應用層(android)接收并解釋該字元串,擷取相應資訊。如下圖所示,如果其中有資訊變化,uevent觸發,做出相應的數更新。

android電池電量更新,android 電池(三):android電池系統

Android中的BatteryService及相關元件

1、Androiduevent架構

Android很多事件都是通過uevent跟kernel來異步通信的。其中類UEventObserver是核心。UEventObserver接收kernel的uevent資訊的抽象類。

(1)、server層代碼

battery server:

frameworks/frameworks/base/services/java/com/android/server/SystemServer.java

frameworks/frameworks/base/services/java/com/android/server/BatteryService.java

(2)、java層代碼

frameworks/base/core/java/android/os/UEventObserver.java

(3)、JNI層代碼

frameworks/base/core/jni/android_os_UEventObserver.cpp

(4)、底層代碼

hardware/libhardware_legacy/uevent/uevent.c

讀寫kernel的接口socket(PF_NETLINK,SOCK_DGRAM,

NETLINK_KOBJECT_UEVENT);

2、UEventObserver的使用

類UEventObserver提供了三個接口給子類來調用:

(1)、onUEvent(UEvent event): 子類必須重寫這個onUEvent來處理uevent。

(2)、startObserving(Stringmatch): 啟動程序,要提供一個字元串參數。

(3)、stopObserving(): 停止程序。

例子://在BatteryService.java中

mUEventObserver.startObserving("SUBSYSTEM=power_supply");

privateUEventObserver mUEventObserver =newUEventObserver() {

@Override

publicvoidonUEvent(UEventObserver.UEvent event) {

update();

}

};

在UEvent thread中會不停調用 update()方法,來更新電池的資訊資料。

3、vold

server分析

(1)、在system/vold/NetlinkManager.cpp中:

if((mSock = socket(PF_NETLINK,SOCK_DGRAM,NETLINK_KOBJECT_UEVENT)) 

SLOGE("Unable to create uevent socket: %s", strerror(errno));

return-1;

}

if(setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz,sizeof(sz)) 

SLOGE("Unable to set uevent socket options: %s", strerror(errno));

return-1;

}

if(bind(mSock, (structsockaddr *) &nladdr,sizeof(nladdr)) 

SLOGE("Unable to bind uevent socket: %s", strerror(errno));

return-1;

}

(2)、然後在system/vold/NetlinkHandler.cpp的NetlinkHandler::onEvent中處理

voidNetlinkHandler::onEvent(NetlinkEvent *evt) {

VolumeManager *vm = VolumeManager::Instance();

constchar*subsys = evt->getSubsystem();

if(!subsys) {

SLOGW("No subsystem found in netlink event");

return;

}

if(!strcmp(subsys,"block")) {

vm->handleBlockEvent(evt);

} elseif(!strcmp(subsys,"switch")) {

vm->handleSwitchEvent(evt);

} elseif(!strcmp(subsys,"battery")) {

} elseif(!strcmp(subsys,"power_supply")) {

}

}

(3)、在system/core/libsysutils/src/NetlinkListener.cpp中監聽。

4、batteryserver分析

java代碼:frameworks/frameworks/base/services/java/com/android/server/BatteryService.java

JNI代碼: frameworks/base/services/jni/com_android_server_BatteryService.cpp

(1)、BatteryService是跑在system_process當中,在系統初始化的時候啟動,

如下在BatteryService.java中:

Log.i(TAG, “Starting Battery Service.”);

BatteryService battery = newBatteryService(context);

ServiceManager.addService(“battery”, battery);

(2)、資料來源BatteryService通過JNI(com_android_server_BatteryService.cpp)讀取資料。

BatteryService通過JNI注冊的不僅有函數,還有變量。

如下:BatteryService是跑在system_process當中,在系統初始化的時候啟動,如下在BatteryService.java中:

//##############在BatteryService.java中聲明的變量################

privatebooleanmAcOnline;

privatebooleanmUsbOnline;

privateintmBatteryStatus;

privateintmBatteryHealth;

privatebooleanmBatteryPresent;

privateintmBatteryLevel;

privateintmBatteryVoltage;

privateintmBatteryTemperature;

privateString mBatteryTechnology;

//在BatteryService.java中聲明的變量,在com_android_server_BatteryService.cpp中共用,即在com_android_server_BatteryService.cpp中其實操作的也是BatteryService.java中聲明的變量。

gFieldIds.mAcOnline = env->GetFieldID(clazz, “mAcOnline”, “Z”);

gFieldIds.mUsbOnline = env->GetFieldID(clazz, “mUsbOnline”, “Z”);

gFieldIds.mBatteryStatus = env->GetFieldID(clazz, “mBatteryStatus”, “I”);

gFieldIds.mBatteryHealth = env->GetFieldID(clazz, “mBatteryHealth”, “I”);

gFieldIds.mBatteryPresent = env->GetFieldID(clazz, “mBatteryPresent”, “Z”);

gFieldIds.mBatteryLevel = env->GetFieldID(clazz, “mBatteryLevel”, “I”);

gFieldIds.mBatteryTechnology = env->GetFieldID(clazz, “mBatteryTechnology”, Ljava/lang/String;”);

gFieldIds.mBatteryVoltage = env->GetFieldID(clazz, “mBatteryVoltage”, “I”);

gFieldIds.mBatteryTemperature = env->GetFieldID(clazz, “mBatteryTemperature”, “I”);

//上面這些變量的值,對應是從下面的檔案中讀取的,一隻檔案存儲一個數值。

#define AC_ONLINE_PATH “/sys/class/power_supply/ac/online”

#define USB_ONLINE_PATH “/sys/class/power_supply/usb/online”

#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”

#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”

(3)、資料傳送

BatteryService主動把資料傳送給所關心的應用程式,所有的電池的資訊資料是通過Intent傳送出去的。在BatteryService.java中,Code如下:

Intent intent =newIntent(Intent.ACTION_BATTERY_CHANGED);

intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);

intent.putExtra(“status”, mBatteryStatus);

intent.putExtra(“health”, mBatteryHealth);

intent.putExtra(“present”, mBatteryPresent);

intent.putExtra(“level”, mBatteryLevel);

intent.putExtra(“scale”, BATTERY_SCALE);

intent.putExtra(“icon-small”, icon);

intent.putExtra(“plugged”, mPlugType);

intent.putExtra(“voltage”, mBatteryVoltage);

intent.putExtra(“temperature”, mBatteryTemperature);

intent.putExtra(“technology”, mBatteryTechnology);

ActivityManagerNative.broadcastStickyIntent(intent, null);

(4)、資料接收

應用如果想要接收到BatteryService發送出來的電池資訊,則需要注冊一個Intent為Intent.ACTION_BATTERY_CHANGED的BroadcastReceiver。

注冊方法如下:

IntentFilter mIntentFilter =newIntentFilter();

mIntentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);

registerReceiver(mIntentReceiver, mIntentFilter);

privateBroadcastReceiver mIntentReceiver =newBroadcastReceiver() {

@Override

publicvoidonReceive(Context context, Intent intent) {

// TODO Auto-generated method stub

String action = intent.getAction();

if(action.equals(Intent.ACTION_BATTERY_CHANGED)) {

intnVoltage = intent.getIntExtra(“voltage”,0);

if(nVoltage!=0){

mVoltage.setText(“V: ” + nVoltage + “mV – Success…”);

}

else{

mVoltage.setText(“V: ” + nVoltage + “mV – fail…”);

}

}

}

};

(5)、資料更新

電池的資訊會随着時間不停變化,自然地,就需要考慮如何實時的更新電池的資料資訊。在BatteryService啟動的時候,會同時通過UEventObserver啟動一個onUEvent

Thread。每一個Process最多隻能有一個onUEvent

Thread,即使這個Process中有多個UEventObserver的執行個體。當在一個Process中,第一次Call

startObserving()方法後,這個UEvent thread就啟動了。而一旦這個UEvent

thread啟動之後,就不會停止。

//在BatteryService.java中

mUEventObserver.startObserving(“SUBSYSTEM=power_supply”);

privateUEventObserver mUEventObserver =newUEventObserver() {

@Override

publicvoidonUEvent(UEventObserver.UEvent event) {

update();

}

};

在UEvent

thread中會不停調用 update()方法,來更新電池的資訊資料。