android电池系统

內核:linux2.6/linux3.0
系統:android/android4.0 
平台:S5PV310(samsungexynos4210) samsung exynos4412

android 電池(一):鋰電池基本原理篇

android 電池(二):android關機充電流程、充電畫面顯示

android 電池(三):android電池系統


一、電池系統結構

       Android中的電池使用方式主要有三種:AC、USB、Battery 等不同的模式。在應用程序層次,通常包括了電池狀態顯示的功能。因此從 Android 系統的軟件方面(包括驅動程序和用戶空間內容)需要在一定程度上獲得電池的狀態,電池系統主要負責電池信息統計、顯示。電池系統的架構如下所示:


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

1、驅動程序

特定硬件平台電池的驅動程序,用 Linux的Power Supply 驅動程序,實現向用戶空間提供信息。Battery 驅動程序需要通過sys文件系 統向用戶空間提供接口, sys文件系統的路徑是由上層的程序指定的。Linux標准的 Power Supply驅動程序 所使用的文件系統路徑为:/sys/class/power_supply ,其中的每個子目錄表示一種能源供應設備的名稱。


Power Supply 驅動程序的頭文件在 include/linux/power_supply.h中定義,注冊和注銷驅動程序的函數如下所示: 

int power_supply_register(struct device *parent,struct power_supply *psy); void power_supply_unregister(struct power_supply *psy); struct power_supply { const char *name; /* 設備名稱 */ enum power_supply_type type; /* 類型 */ enum power_supply_property *properties; /* 屬性指針 */ size_t num_properties; /* 屬性的數目 */ char **supplied_to; size_t num_supplicants; int (*get_property)(struct power_supply *psy, /* 獲得屬性 */ enum power_supply_property psp, union power_supply_propval *val); void (*external_power_changed)(struct power_supply *psy); /* ...... 省略部分內容 */ }; 

Linux中驅動程序:power_supply


2、本地代碼 - JNI

代碼路徑: frameworks/base/services/jni/com_android_server_BatteryService.cpp 這個類調用sys文件系統訪問驅動程序,也同時提供了JNI的接口。

這個文件提供的方法列表如下所示: 

static JNINativeMethod sMethods[] = { {"native_update", "()V", (void*)android_server_BatteryService_update}, };  

處理的流程为根據設備類型判定設備後, 得到各個設備的相關屬性,則需要得到更多得 信息。例如:果是交流或者 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 

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 系統中默認的內容。在移植的過程中基本不需要改動。電池系統需要移植的部分僅有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中的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");         private UEventObserver mUEventObserver = new UEventObserver() {         @Override               public void onUEvent(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)) < 0) {               SLOGE("Unable to create uevent socket: %s", strerror(errno));               return -1;       }       if (setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) {               SLOGE("Unable to set uevent socket options: %s", strerror(errno));               return -1;       }       if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {               SLOGE("Unable to bind uevent socket: %s", strerror(errno));               return -1;       }
 (2)、然後在system/vold/NetlinkHandler.cpp的NetlinkHandler::onEvent中處理  
             void NetlinkHandler::onEvent(NetlinkEvent *evt) {                      VolumeManager *vm = VolumeManager::Instance();                     const char *subsys = evt->getSubsystem();                     if (!subsys) {                           SLOGW("No subsystem found in netlink event");                           return;                     }                     if (!strcmp(subsys, "block")) {                           vm->handleBlockEvent(evt);                     } else if (!strcmp(subsys, "switch")) {                           vm->handleSwitchEvent(evt);                     } else if (!strcmp(subsys, "battery")) {                     } else if (!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 = new BatteryService(context);        ServiceManager.addService(“battery”, battery);
    (2)、數據來源
       BatteryService通過JNI(com_android_server_BatteryService.cpp)讀取數據。
        BatteryService通過JNI注冊的不僅有函數,還有變量。 如下:ont-faVi:T�{ ~Roman";mso-hansi-font-family:"Times New Roman";mso-bidi-font-family:新宋體;mso-fareast-language:ZH-CN'>) 、BatteryService是跑在system_process當中,在系統初始化的時候启動 ,如下在BatteryService.java中:
        //##############在BatteryService.java中聲明的變量################        private boolean mAcOnline;        private boolean mUsbOnline;        private int mBatteryStatus;        private int mBatteryHealth;        private boolean mBatteryPresent;        private int mBatteryLevel;        private int mBatteryVoltage;        private int mBatteryTemperature;        private String 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如下:so-�-o�/z�{:新宋體;mso-ansi-language:EN-US;mso-fareast-language:#0400;mso-bidi-language:AR-SA'>注冊的不僅有函數,還有變量。 如下:
        Intent intent = new Intent(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 = new IntentFilter();        mIntentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);        registerReceiver(mIntentReceiver, mIntentFilter);        private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {            @Override            public void onReceive(Context context, Intent intent) {                // TODO Auto-generated method stub                String action = intent.getAction();                if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {                    int nVoltage = 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”);        private UEventObserver mUEventObserver = new UEventObserver() {            @Override            public void onUEvent(UEventObserver.UEvent event) {                update();            }        };

    在UEvent thread中會不停調用 update()方法,來更新電池的信息數據。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值