1. 程式人生 > >android 4.4 電池電量管理底層分析(C\C++層)

android 4.4 電池電量管理底層分析(C\C++層)

參考文獻:http://blog.csdn.net/wlwl0071986/article/details/38778897

簡介:

Linux電池驅動用於和PMIC互動、負責監聽電池產生的相關事件,例如低電報警、電量發生變化、高溫報警、USB插拔等等。

Android電池服務,用來監聽核心上報的電池事件,並將最新的電池資料上報給系統,系統收到新資料後會去更新電池顯示狀態、剩餘電量等資訊。如果收到過溫報警和低電報警,系統會自動觸發關機流程,保護電池和機器不受到危害。

Android電池服務的啟動和執行流程:


Android電源管理底層用的是Linux powersupply框架,從Android 4.4開始,Google專門提供了一個healthd來監控電源狀態。它的路徑在:system/core/healthd資料夾下,編譯出來的檔案為/sbin/healthd。


電池系統從底層向Framework層上報資料的流程:


關於C/C++ 層與驅動互動的程式碼我不全部貼出,只給出路徑,大家可以自己查詢閱讀,這裡值講述關鍵函式。

一、關係圖:


二、Healthd

  包含兩個檔案:\system\core\healthd\healthd.h ,\system\core\healthd\healthd.cpp 

   簡要說明:

    health.h 是個標頭檔案,只要宣告函式與變數,不做過多介紹。我們說下healthd.cpp ,

int main(int argc, char **argv) {
    int ch;

    klog_set_level(KLOG_LEVEL);

    while ((ch = getopt(argc, argv, "n")) != -1) {
        switch (ch) {
        case 'n':
            nosvcmgr = true;
            break;
        case '?':
        default:
            KLOG_WARNING(LOG_TAG, "Unrecognized healthd option: %c\n", ch);
        }
    }

    healthd_board_init(&healthd_config);
    wakealarm_init();
    uevent_init();
    binder_init();
    gBatteryMonitor = new BatteryMonitor();
    gBatteryMonitor->init(&healthd_config, nosvcmgr);

    healthd_mainloop();
    return 0;
}

這是main函式,跟Java中的main是一樣的,作為程式的入口。這裡做一些初始化工作,獲得BatteryMonitor的指標物件。我們索要關注的是healthd_mainloop()的呼叫,僅憑函式名就能知道會進入一個無限迴圈,這樣也就能達到監控電源狀態的目的了。下面我們看一下這個函式:
static void healthd_mainloop(void) {
    struct epoll_event ev;
    int epollfd;
    int maxevents = 0;

    epollfd = epoll_create(MAX_EPOLL_EVENTS);
    if (epollfd == -1) {
        KLOG_ERROR(LOG_TAG,
                   "healthd_mainloop: epoll_create failed; errno=%d\n",
                   errno);
        return;
    }

    if (uevent_fd >= 0) {
        ev.events = EPOLLIN;
        ev.data.ptr = (void *)uevent_event;
        if (epoll_ctl(epollfd, EPOLL_CTL_ADD, uevent_fd, &ev) == -1)
            KLOG_ERROR(LOG_TAG,
                       "healthd_mainloop: epoll_ctl for uevent_fd failed; errno=%d\n",
                       errno);
        else
            maxevents++;
    }

    if (wakealarm_fd >= 0) {
        ev.events = EPOLLIN | EPOLLWAKEUP;
        ev.data.ptr = (void *)wakealarm_event;
        if (epoll_ctl(epollfd, EPOLL_CTL_ADD, wakealarm_fd, &ev) == -1)
            KLOG_ERROR(LOG_TAG,
                       "healthd_mainloop: epoll_ctl for wakealarm_fd failed; errno=%d\n",
                       errno);
        else
            maxevents++;
   }

    if (binder_fd >= 0) {
        ev.events = EPOLLIN | EPOLLWAKEUP;
        ev.data.ptr= (void *)binder_event;
        if (epoll_ctl(epollfd, EPOLL_CTL_ADD, binder_fd, &ev) == -1)
            KLOG_ERROR(LOG_TAG,
                       "healthd_mainloop: epoll_ctl for binder_fd failed; errno=%d\n",
                       errno);
        else
            maxevents++;
   }

    while (1) {
        struct epoll_event events[maxevents];
        int nevents;

        IPCThreadState::self()->flushCommands();
        nevents = epoll_wait(epollfd, events, maxevents, awake_poll_interval);

        if (nevents == -1) {
            if (errno == EINTR)
                continue;
            KLOG_ERROR(LOG_TAG, "healthd_mainloop: epoll_wait failed\n");
            break;
        }

        for (int n = 0; n < nevents; ++n) {
            if (events[n].data.ptr)
                (*(void (*)())events[n].data.ptr)();
        }

        if (!nevents)
            periodic_chores();
    }

    return;
}

我們來看一下這個函式都幹了哪些事情呢?首先,程式碼:epollfd = epoll_create(MAX_EPOLL_EVENTS);建立一個 epoll 例項,並要求核心分配一個可以儲存 size 個描述符的空間( 關於epoll,Linux中的字元裝置驅動中有一個函式是poll,Linux 2.5.44版本後被epoll取代,請參考:http://baike.baidu.com/view/1385104.htm?fr=aladdin ), 然後把函式賦值 ev.data.ptr = (void *)uevent_event; 在while(1) 的 呼叫 nevents = epoll_wait(epollfd, events, maxevents, awake_poll_interval); 等待EPOLL事件的發生,相當於監聽。當收到監聽後,就是在
        for (int n = 0; n < nevents; ++n) {
            if (events[n].data.ptr)
                (*(void (*)())events[n].data.ptr)();
        }

for迴圈中呼叫 事件賦值 ev.data.ptr = (void *)uevent_event; 所賦值的函式, 其實相當於Java中的回撥介面。我們這裡值關注uevent_event 函式。因為這個是跟電池屬性相關的。uevent_event 函式如下:

static void uevent_event(void) {
    char msg[UEVENT_MSG_LEN+2];
    char *cp;
    int n;

    n = uevent_kernel_multicast_recv(uevent_fd, msg, UEVENT_MSG_LEN);
    if (n <= 0)
        return;
    if (n >= UEVENT_MSG_LEN)   /* overflow -- discard */
        return;

    msg[n] = '\0';
    msg[n+1] = '\0';
    cp = msg;

    while (*cp) {
        if (!strcmp(cp, "SUBSYSTEM=" POWER_SUPPLY_SUBSYSTEM)) {
            battery_update();
            break;
        }

        /* advance to after the next \0 */
        while (*cp++)
            ;
    }
}

它會讀取socket中的字串,然後判斷事件來源是否是由kernel的power_supply發出的,程式碼if (!strcmp(cp, "SUBSYSTEM=" POWER_SUPPLY_SUBSYSTEM)) ,如果是,那就呼叫battery_update()更新電源狀態。下面來看看battery_update()是如何更新電源狀態的:
static void battery_update(void) {
    // Fast wake interval when on charger (watch for overheat);
    // slow wake interval when on battery (watch for drained battery).

   int new_wake_interval = gBatteryMonitor->update() ?
       healthd_config.periodic_chores_interval_fast :
           healthd_config.periodic_chores_interval_slow;

    if (new_wake_interval != wakealarm_wake_interval)
            wakealarm_set_interval(new_wake_interval);

    // During awake periods poll at fast rate.  If wake alarm is set at fast
    // rate then just use the alarm; if wake alarm is set at slow rate then
    // poll at fast rate while awake and let alarm wake up at slow rate when
    // asleep.

    if (healthd_config.periodic_chores_interval_fast == -1)
        awake_poll_interval = -1;
    else
        awake_poll_interval =
            new_wake_interval == healthd_config.periodic_chores_interval_fast ?
                -1 : healthd_config.periodic_chores_interval_fast * 1000;
}
主要就是這一句:gBatteryMonitor->update() ,gBatteryMonitor 是在mian 函式中初始化的BatteryMonitor的指標物件。 看關係圖,這裡就由Healthd 跳到BatteryMonitor了。

下面,我們看一下BatteryMonitor


三、BatteryMonitor

  包含兩個檔案:\system\core\healthd\BatteryMonitor.h ,\system\core\healthd\BatteryMonitor.cpp

   簡要說明:

    BatteryMonitor.h 是個標頭檔案,只要宣告函式與變數,不做過多介紹。我們說下BatteryMonitor.cpp

    上面說到,battery_update() 中會呼叫gBatteryMonitor->update() ,那BatteryMonitor.cpp 中的 update()都做了什麼了?程式碼如下:

bool BatteryMonitor::update(void) {
    struct BatteryProperties props;
    bool logthis;

    props.chargerAcOnline = false;
    props.chargerUsbOnline = false;
    props.chargerWirelessOnline = false;
    props.batteryStatus = BATTERY_STATUS_UNKNOWN;
    props.batteryHealth = BATTERY_HEALTH_UNKNOWN;
    props.batteryCurrentNow = INT_MIN;
    props.batteryChargeCounter = INT_MIN;

    if (!mHealthdConfig->batteryPresentPath.isEmpty())
        props.batteryPresent = getBooleanField(mHealthdConfig->batteryPresentPath);
    else
        props.batteryPresent = true;

    props.batteryLevel = getIntField(mHealthdConfig->batteryCapacityPath);
    props.batteryVoltage = getIntField(mHealthdConfig->batteryVoltagePath) / 1000;

    if (!mHealthdConfig->batteryCurrentNowPath.isEmpty())
        props.batteryCurrentNow = getIntField(mHealthdConfig->batteryCurrentNowPath);

    if (!mHealthdConfig->batteryChargeCounterPath.isEmpty())
        props.batteryChargeCounter = getIntField(mHealthdConfig->batteryChargeCounterPath);

    props.batteryTemperature = getIntField(mHealthdConfig->batteryTemperaturePath);

    const int SIZE = 128;
    char buf[SIZE];
    String8 btech;

    if (readFromFile(mHealthdConfig->batteryStatusPath, buf, SIZE) > 0)
        props.batteryStatus = getBatteryStatus(buf);

    if (readFromFile(mHealthdConfig->batteryHealthPath, buf, SIZE) > 0)
        props.batteryHealth = getBatteryHealth(buf);

    if (readFromFile(mHealthdConfig->batteryTechnologyPath, buf, SIZE) > 0)
        props.batteryTechnology = String8(buf);

    unsigned int i;

    for (i = 0; i < mChargerNames.size(); i++) {
        String8 path;
        path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH,
                          mChargerNames[i].string());

        if (readFromFile(path, buf, SIZE) > 0) {
            if (buf[0] != '0') {
                path.clear();
                path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH,
                                  mChargerNames[i].string());
                switch(readPowerSupplyType(path)) {
                case ANDROID_POWER_SUPPLY_TYPE_AC:
                    props.chargerAcOnline = true;
                    break;
                case ANDROID_POWER_SUPPLY_TYPE_USB:
                    props.chargerUsbOnline = true;
                    break;
                case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
                    props.chargerWirelessOnline = true;
                    break;
                default:
                    KLOG_WARNING(LOG_TAG, "%s: Unknown power supply type\n",
                                 mChargerNames[i].string());
                }
            }
        }
    }

    logthis = !healthd_board_battery_update(&props);

    if (logthis) {
        char dmesgline[256];
        snprintf(dmesgline, sizeof(dmesgline),
                 "battery l=%d v=%d t=%s%d.%d h=%d st=%d",
                 props.batteryLevel, props.batteryVoltage,
                 props.batteryTemperature < 0 ? "-" : "",
                 abs(props.batteryTemperature / 10),
                 abs(props.batteryTemperature % 10), props.batteryHealth,
                 props.batteryStatus);

        if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
            char b[20];

            snprintf(b, sizeof(b), " c=%d", props.batteryCurrentNow / 1000);
            strlcat(dmesgline, b, sizeof(dmesgline));
        }

        KLOG_INFO(LOG_TAG, "%s chg=%s%s%s\n", dmesgline,
                  props.chargerAcOnline ? "a" : "",
                  props.chargerUsbOnline ? "u" : "",
                  props.chargerWirelessOnline ? "w" : "");
    }

    if (mBatteryPropertiesRegistrar != NULL)
        mBatteryPropertiesRegistrar->notifyListeners(props);

    return props.chargerAcOnline | props.chargerUsbOnline |
            props.chargerWirelessOnline;
}
這個函式首先定義了BatteryProperties props; 這個屬性集(為了減少介紹的複雜度,大家可以簡單的認為只是一個包含各種屬性的類),然後給這個屬性集 props 裡面的屬性賦值。然後在最後會在最後判斷有無註冊監聽 ,如果有的話,呼叫註冊的監聽,把屬性傳入監聽:
   if (mBatteryPropertiesRegistrar != NULL)
        mBatteryPropertiesRegistrar->notifyListeners(props);
呼叫的就是上面的東西。 到目前為止,我們知道了health 裡面有個無線迴圈,監控驅動事件,然後呼叫BatteryProperties中的update方法。 然後update會讀取各種屬性值,然後呼叫註冊的監聽。如下圖


  那麼問題來了------->挖掘機技術哪家強?哈哈,開個玩笑。下面我們就要分兩個分支來講述:

(1)這些屬性是從哪裡來的。

(2)屬性變化後呼叫的監聽是誰註冊的。

首先,(1)這些屬性是從哪裡來的。

     我們先看一下 上面的 healthd.cpp 的main 函式初始化 BatteryMonitor 時,呼叫了

   gBatteryMonitor = new BatteryMonitor();
    gBatteryMonitor->init(&healthd_config, nosvcmgr);
  這個init 初始化的時候都幹了些什麼呢
void BatteryMonitor::init(struct healthd_config *hc, bool nosvcmgr) {
    String8 path;

    mHealthdConfig = hc;
    DIR* dir = opendir(POWER_SUPPLY_SYSFS_PATH);
    if (dir == NULL) {
        KLOG_ERROR(LOG_TAG, "Could not open %s\n", POWER_SUPPLY_SYSFS_PATH);
    } else {
        struct dirent* entry;

        while ((entry = readdir(dir))) {
            const char* name = entry->d_name;

            if (!strcmp(name, ".") || !strcmp(name, ".."))
                continue;

            char buf[20];
            // Look for "type" file in each subdirectory
            path.clear();
            path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH, name);
            switch(readPowerSupplyType(path)) {
            case ANDROID_POWER_SUPPLY_TYPE_AC:
            case ANDROID_POWER_SUPPLY_TYPE_USB:
            case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
                path.clear();
                path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name);
                if (access(path.string(), R_OK) == 0)
                    mChargerNames.add(String8(name));
                break;

            case ANDROID_POWER_SUPPLY_TYPE_BATTERY:
                if (mHealthdConfig->batteryStatusPath.isEmpty()) {
                    path.clear();
                    path.appendFormat("%s/%s/status", POWER_SUPPLY_SYSFS_PATH,
                                      name);
                    if (access(path, R_OK) == 0)
                        mHealthdConfig->batteryStatusPath = path;
                }

                if (mHealthdConfig->batteryHealthPath.isEmpty()) {
                    path.clear();
                    path.appendFormat("%s/%s/health", POWER_SUPPLY_SYSFS_PATH,
                                      name);
                    if (access(path, R_OK) == 0)
                        mHealthdConfig->batteryHealthPath = path;
                }

                if (mHealthdConfig->batteryPresentPath.isEmpty()) {
                    path.clear();
                    path.appendFormat("%s/%s/present", POWER_SUPPLY_SYSFS_PATH,
                                      name);
                    if (access(path, R_OK) == 0)
                        mHealthdConfig->batteryPresentPath = path;
                }

                if (mHealthdConfig->batteryCapacityPath.isEmpty()) {
                    path.clear();
                    path.appendFormat("%s/%s/capacity", POWER_SUPPLY_SYSFS_PATH,
                                      name);
                    if (access(path, R_OK) == 0)
                        mHealthdConfig->batteryCapacityPath = path;
                }

                if (mHealthdConfig->batteryVoltagePath.isEmpty()) {
                    path.clear();
                    path.appendFormat("%s/%s/voltage_now",
                                      POWER_SUPPLY_SYSFS_PATH, name);
                    if (access(path, R_OK) == 0) {
                        mHealthdConfig->batteryVoltagePath = path;
                    } else {
                        path.clear();
                        path.appendFormat("%s/%s/batt_vol",
                                          POWER_SUPPLY_SYSFS_PATH, name);
                        if (access(path, R_OK) == 0)
                            mHealthdConfig->batteryVoltagePath = path;
                    }
                }

                if (mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
                    path.clear();
                    path.appendFormat("%s/%s/current_now",
                                      POWER_SUPPLY_SYSFS_PATH, name);
                    if (access(path, R_OK) == 0)
                        mHealthdConfig->batteryCurrentNowPath = path;
                }

                if (mHealthdConfig->batteryChargeCounterPath.isEmpty()) {
                    path.clear();
                    path.appendFormat("%s/%s/charge_counter",
                                      POWER_SUPPLY_SYSFS_PATH, name);
                    if (access(path, R_OK) == 0)
                        mHealthdConfig->batteryChargeCounterPath = path;
                }

                if (mHealthdConfig->batteryTemperaturePath.isEmpty()) {
                    path.clear();
                    path.appendFormat("%s/%s/temp", POWER_SUPPLY_SYSFS_PATH,
                                      name);
                    if (access(path, R_OK) == 0) {
                        mHealthdConfig->batteryTemperaturePath = path;
                    } else {
                        path.clear();
                        path.appendFormat("%s/%s/batt_temp",
                                          POWER_SUPPLY_SYSFS_PATH, name);
                        if (access(path, R_OK) == 0)
                            mHealthdConfig->batteryTemperaturePath = path;
                    }
                }

                if (mHealthdConfig->batteryTechnologyPath.isEmpty()) {
                    path.clear();
                    path.appendFormat("%s/%s/technology",
                                      POWER_SUPPLY_SYSFS_PATH, name);
                    if (access(path, R_OK) == 0)
                        mHealthdConfig->batteryTechnologyPath = path;
                }

                break;

            case ANDROID_POWER_SUPPLY_TYPE_UNKNOWN:
                break;
            }
        }
        closedir(dir);
    }

    if (!mChargerNames.size())
        KLOG_ERROR(LOG_TAG, "No charger supplies found\n");
    if (mHealthdConfig->batteryStatusPath.isEmpty())
        KLOG_WARNING(LOG_TAG, "BatteryStatusPath not found\n");
    if (mHealthdConfig->batteryHealthPath.isEmpty())
        KLOG_WARNING(LOG_TAG, "BatteryHealthPath not found\n");
    if (mHealthdConfig->batteryPresentPath.isEmpty())
        KLOG_WARNING(LOG_TAG, "BatteryPresentPath not found\n");
    if (mHealthdConfig->batteryCapacityPath.isEmpty())
        KLOG_WARNING(LOG_TAG, "BatteryCapacityPath not found\n");
    if (mHealthdConfig->batteryVoltagePath.isEmpty())
        KLOG_WARNING(LOG_TAG, "BatteryVoltagePath not found\n");
    if (mHealthdConfig->batteryTemperaturePath.isEmpty())
        KLOG_WARNING(LOG_TAG, "BatteryTemperaturePath not found\n");
    if (mHealthdConfig->batteryTechnologyPath.isEmpty())
        KLOG_WARNING(LOG_TAG, "BatteryTechnologyPath not found\n");

    if (nosvcmgr == false) {
            mBatteryPropertiesRegistrar = new BatteryPropertiesRegistrar(this);
            mBatteryPropertiesRegistrar->publish();
    }
}


在init()裡會呼叫opendir(POWER_SUPPLY_SYSFS_PATH); 

opendir()函式的作用是:開啟目錄控制代碼,將返回一組目錄流(一組目錄字串),說白了就是目錄下的檔名。 

#define POWER_SUPPLY_SUBSYSTEM "power_supply"
#define POWER_SUPPLY_SYSFS_PATH "/sys/class/" POWER_SUPPLY_SUBSYSTEM
其實 opendir 開啟的就是 sys/class/power_supply ,並返回這個路徑下的所有檔案。檔案如下:

比如ac (充電器就叫AC)目錄下面都有什麼呢:


然後我們看init()程式碼裡面,其實就是把各種路徑讀取出來,然後把路徑賦值。 我們知道了init()幹了什麼,然後迴歸到主題:update() 中的屬性從哪裡來的。

我們只舉一個例子。在update()中如何讀取的當前電量級別(其他屬性獲取都是類似的)。在 update()函式中,獲取當前電量等級程式碼如下:

    if (!mHealthdConfig->batteryCurrentNowPath.isEmpty())
        props.batteryCurrentNow = getIntField(mHealthdConfig->batteryCurrentNowPath);
會用getIntField() 去讀取當前電量值。而且傳入的引數是我們init()時獲取的檔案路徑。 從路徑下讀取的值是什麼呢,大家看下截圖就明白了。如下:


看到沒,其實就是讀取檔案裡面的值。 100 是我當前手機的電量,我的手機是滿電狀態。

到此,我們第一個問題:

BatteryMonitor 中 update 方面裡面如何獲取的屬性已經解決。就是根據路徑,讀取檔案獲得的。

下面來看第二個問題:

(2)屬性變化後呼叫誰註冊的監聽。

在BatteryMonitor.cpp中的init()函式末尾 有這麼一句:

    if (nosvcmgr == false) {
            mBatteryPropertiesRegistrar = new BatteryPropertiesRegistrar(this);
            mBatteryPropertiesRegistrar->publish();
    }

而在在BatteryMonitor.cpp中的update()函式末尾 有這麼一句:
    if (mBatteryPropertiesRegistrar != NULL)
        mBatteryPropertiesRegistrar->notifyListeners(props);

由上面兩個函式中的呼叫,我們很容易推測出 註冊監聽跟 BatteryPropertiesRegistrar有關。

我們來分析下 BatteryPropertiesRegistrar 有什麼。

BatteryPropertiesRegistrar:

此類的相關檔案有4個,具體路徑:

\frameworks\native\include\batteryservice\IBatteryPropertiesRegistrar.h

\frameworks\native\services\batteryservice\IBatteryPropertiesRegistrar.cpp

\system\core\healthd\BatteryPropertiesRegistrar.cpp 

\system\core\healthd\BatteryPropertiesRegistrar.h



\frameworks\native\include\batteryservice\IBatteryPropertiesRegistrar.h檔案內容:

#ifndef ANDROID_IBATTERYPROPERTIESREGISTRAR_H
#define ANDROID_IBATTERYPROPERTIESREGISTRAR_H

#include <binder/IInterface.h>
#include <batteryservice/IBatteryPropertiesListener.h>

namespace android {

// must be kept in sync with interface defined in IBatteryPropertiesRegistrar.aidl
enum {
    REGISTER_LISTENER = IBinder::FIRST_CALL_TRANSACTION,
    UNREGISTER_LISTENER,
};

class IBatteryPropertiesRegistrar : public IInterface {
public:
    DECLARE_META_INTERFACE(BatteryPropertiesRegistrar);

    virtual void registerListener(const sp<IBatteryPropertiesListener>& listener) = 0;
    virtual void unregisterListener(const sp<IBatteryPropertiesListener>& listener) = 0;
};

class BnBatteryPropertiesRegistrar : public BnInterface<IBatteryPropertiesRegistrar> {
public:
    virtual status_t onTransact(uint32_t code, const Parcel& data,
                                Parcel* reply, uint32_t flags = 0);
};

}; // namespace android

#endif // ANDROID_IBATTERYPROPERTIESREGISTRAR_H

咦,我們可以看到IBatteryPropertiesRegistrar 繼承於  IInterface  ,還有一個類BnBatteryPropertiesRegistrar 繼承於BnInterface。 而且還呼叫了
 DECLARE_META_INTERFACE(BatteryPropertiesRegistrar);
這個巨集定義介面。如果你有看過我上篇 Binder 初解(http://blog.csdn.net/daweibalang717/article/details/41382603 )的話,你可以很輕易的看出這裡是Binder的寫法。而且明顯是個 native service。 對於這四個檔案的關係。你讀完 Binder 初解後,就一目瞭然了。


\frameworks\native\services\batteryservice\IBatteryPropertiesRegistrar.cpp的內容

#define LOG_TAG "IBatteryPropertiesRegistrar"
//#define LOG_NDEBUG 0
#include <utils/Log.h>

#include <batteryservice/IBatteryPropertiesListener.h>
#include <batteryservice/IBatteryPropertiesRegistrar.h>
#include <stdint.h>
#include <sys/types.h>
#include <binder/Parcel.h>

namespace android {

class BpBatteryPropertiesRegistrar : public BpInterface<IBatteryPropertiesRegistrar> {
public:
    BpBatteryPropertiesRegistrar(const sp<IBinder>& impl)
        : BpInterface<IBatteryPropertiesRegistrar>(impl) {}

        void registerListener(const sp<IBatteryPropertiesListener>& listener) {
            Parcel data;
            data.writeInterfaceToken(IBatteryPropertiesRegistrar::getInterfaceDescriptor());
            data.writeStrongBinder(listener->asBinder());
            remote()->transact(REGISTER_LISTENER, data, NULL);
        }

        void unregisterListener(const sp<IBatteryPropertiesListener>& listener) {
            Parcel data;
            data.writeInterfaceToken(IBatteryPropertiesRegistrar::getInterfaceDescriptor());
            data.writeStrongBinder(listener->asBinder());
            remote()->transact(UNREGISTER_LISTENER, data, NULL);
        }
};

IMPLEMENT_META_INTERFACE(BatteryPropertiesRegistrar, "android.os.IBatteryPropertiesRegistrar");

status_t BnBatteryPropertiesRegistrar::onTransact(uint32_t code,
                                                  const Parcel& data,
                                                  Parcel* reply,
                                                  uint32_t flags)
{
    switch(code) {
        case REGISTER_LISTENER: {
            CHECK_INTERFACE(IBatteryPropertiesRegistrar, data, reply);
            sp<IBatteryPropertiesListener> listener =
                interface_cast<IBatteryPropertiesListener>(data.readStrongBinder());
            //這個方法並不是上面 BpBatteryPropertiesRegistrar中的registerListener(),他們就不是一個類。這個方法還未實現      
            registerListener(listener);
            return OK;
        }

        case UNREGISTER_LISTENER: {
            CHECK_INTERFACE(IBatteryPropertiesRegistrar, data, reply);
            sp<IBatteryPropertiesListener> listener =
                interface_cast<IBatteryPropertiesListener>(data.readStrongBinder());
 //這個方法並不是上面 BpBatteryPropertiesRegistrar中的unregisterListener(),他們就不是一個類。這個方法還未實現 
            unregisterListener(listener);
            return OK;
        }
    }
    return BBinder::onTransact(code, data, reply, flags);
};

// ----------------------------------------------------------------------------

}; // namespace android


我們看到 這裡是服務端與代理端的實現。 但是服務端 onTransact( )中呼叫的 registerListener(listener); 與unregisterListener(listener); 是沒有實現的。這兩個方法是在

\system\core\healthd\BatteryPropertiesRegistrar.cpp  中實現的。

 \system\core\healthd\BatteryPropertiesRegistrar.h 中的內容:

#ifndef HEALTHD_BATTERYPROPERTIES_REGISTRAR_H
#define HEALTHD_BATTERYPROPERTIES_REGISTRAR_H

#include "BatteryMonitor.h"

#include <binder/IBinder.h>
#include <utils/Mutex.h>
#include <utils/Vector.h>
#include <batteryservice/BatteryService.h>
#include <batteryservice/IBatteryPropertiesListener.h>
#include <batteryservice/IBatteryPropertiesRegistrar.h>

namespace android {

class BatteryMonitor;

class BatteryPropertiesRegistrar : public BnBatteryPropertiesRegistrar,
                                   public IBinder::DeathRecipient {
public:
    BatteryPropertiesRegistrar(BatteryMonitor* monitor);
    void publish();
    void notifyListeners(struct BatteryProperties props);

private:
    BatteryMonitor* mBatteryMonitor;
    Mutex mRegistrationLock;
    Vector<sp<IBatteryPropertiesListener> > mListeners;

    void registerListener(const sp<IBatteryPropertiesListener>& listener);
    void unregisterListener(const sp<IBatteryPropertiesListener>& listener);
    void binderDied(const wp<IBinder>& who);
};

};  // namespace android

#endif // HEALTHD_BATTERYPROPERTIES_REGISTRAR_H
這個類是對\frameworks\native\include\batteryservice\IBatteryPropertiesRegistrar.h 中的  BnBatteryPropertiesRegistrar的擴充套件,並繼承於public IBinder::DeathRecipient

然後是\system\core\healthd\BatteryPropertiesRegistrar.cpp  的內容:

#include "BatteryPropertiesRegistrar.h"
#include <batteryservice/BatteryService.h>
#include <batteryservice/IBatteryPropertiesListener.h>
#include <batteryservice/IBatteryPropertiesRegistrar.h>
#include <binder/IServiceManager.h>
#include <utils/Errors.h>
#include <utils/Mutex.h>
#include <utils/String16.h>

namespace android {

BatteryPropertiesRegistrar::BatteryPropertiesRegistrar(BatteryMonitor* monitor) {
    mBatteryMonitor = monitor;
}

void BatteryPropertiesRegistrar::publish() {
    defaultServiceManager()->addService(String16("batterypropreg"), this);
}

void BatteryPropertiesRegistrar::notifyListeners(struct BatteryProperties props) {
    Mutex::Autolock _l(mRegistrationLock);
    for (size_t i = 0; i < mListeners.size(); i++) {
        mListeners[i]->batteryPropertiesChanged(props);
    }
}

void BatteryPropertiesRegistrar::registerListener(const sp<IBatteryPropertiesListener>& listener) {
    {
        Mutex::Autolock _l(mRegistrationLock);
        // check whether this is a duplicate
        for (size_t i = 0; i < mListeners.size(); i++) {
            if (mListeners[i]->asBinder() == listener->asBinder()) {
                return;
            }
        }

        mListeners.add(listener);
        listener->asBinder()->linkToDeath(this);
    }
    mBatteryMonitor->update();
}

void BatteryPropertiesRegistrar::unregisterListener(const sp<IBatteryPropertiesListener>& listener) {
    Mutex::Autolock _l(mRegistrationLock);
    for (size_t i = 0; i < mListeners.size(); i++) {
        if (mListeners[i]->asBinder() == listener->asBinder()) {
            mListeners[i]->asBinder()->unlinkToDeath(this);
            mListeners.removeAt(i);
            break;
        }
    }
}

void BatteryPropertiesRegistrar::binderDied(const wp<IBinder>& who) {
    Mutex::Autolock _l(mRegistrationLock);

    for (size_t i = 0; i < mListeners.size(); i++) {
        if (mListeners[i]->asBinder() == who) {
            mListeners.removeAt(i);
            break;
        }
    }
}

}  // namespace android

這個類是對 \system\core\healthd\BatteryPropertiesRegistrar.h 的實現。  真正 呼叫registerListener(listener); 與unregisterListener(listener); 的地方。

這個BatteryPropertiesRegistrar:其實就是註冊監聽的類,而且監聽的介面叫IBatteryPropertiesListener。

IBatteryPropertiesListener :

檔案路徑:

\frameworks\native\include\batteryservice\IBatteryPropertiesListener.h

\frameworks\native\services\batteryservice\IBatteryPropertiesListener.cpp

檔案內容:

IBatteryPropertiesListener.h

#ifndef ANDROID_IBATTERYPROPERTIESLISTENER_H
#define ANDROID_IBATTERYPROPERTIESLISTENER_H

#include <binder/IBinder.h>
#include <binder/IInterface.h>

#include <batteryservice/BatteryService.h>

namespace android {

// must be kept in sync with interface defined in IBatteryPropertiesListener.aidl
enum {
        TRANSACT_BATTERYPROPERTIESCHANGED = IBinder::FIRST_CALL_TRANSACTION,
};

// ----------------------------------------------------------------------------

class IBatteryPropertiesListener : public IInterface {
public:
    DECLARE_META_INTERFACE(BatteryPropertiesListener);

    virtual void batteryPropertiesChanged(struct BatteryProperties props) = 0;
};

// ----------------------------------------------------------------------------

}; // namespace android

#endif 

咦,這個依然用的是Binder 機制。這裡進行代理與服務端的宣告。

IBatteryPropertiesListener.cpp:

#include <stdint.h>
#include <sys/types.h>
#include <batteryservice/IBatteryPropertiesListener.h>
#include <binder/Parcel.h>

namespace android {

class BpBatteryPropertiesListener : public BpInterface<IBatteryPropertiesListener>
{
public:
    BpBatteryPropertiesListener(const sp<IBinder>& impl)
        : BpInterface<IBatteryPropertiesListener>(impl)
    {
    }

    void batteryPropertiesChanged(struct BatteryProperties props)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IBatteryPropertiesListener::getInterfaceDescriptor());
        data.writeInt32(1);
        props.writeToParcel(&data);
        status_t err = remote()->transact(TRANSACT_BATTERYPROPERTIESCHANGED, data, &reply, IBinder::FLAG_ONEWAY);
    }
};

IMPLEMENT_META_INTERFACE(BatteryPropertiesListener, "android.os.IBatteryPropertiesListener");

// ----------------------------------------------------------------------------

}; // namespace android

這裡進行代理的實現。 但是並沒有對服務端進行實現。這個應該是在BatteryService.java 中的:
    private final class BatteryListener extends IBatteryPropertiesListener.Stub {
        public void batteryPropertiesChanged(BatteryProperties props) {
            BatteryService.this.update(props);
       }

中進行實現的。

到這裡我們對於第二個問題:屬性變化後呼叫誰註冊的監聽。 還沒有解決, 只是瞭解下注冊類與註冊介面。那麼真正註冊在那呢? 是在\frameworks\base\services\java\com\android\server\BatteryService.java中:

這個BatteryService 繼承於Binder 類,在他的建構函式中,是這麼註冊的:

        mBatteryPropertiesListener = new BatteryListener();

        IBinder b = ServiceManager.getService("batterypropreg");
        mBatteryPropertiesRegistrar = IBatteryPropertiesRegistrar.Stub.asInterface(b);

        try {
            mBatteryPropertiesRegistrar.registerListener(mBatteryPropertiesListener);
        } catch (RemoteException e) {
            // Should never happen.
        }

大家不禁要問了。這裡是Java 程式碼呀,怎麼掉的C++的呢,這就是Binder機制了。 而且上面所述的 IBatteryPropertiesListener  、IBatteryPropertiesRegistrar 在Java層都有對應的aidl 檔案。目錄:

\frameworks\base\core\java\android\os\IBatteryPropertiesListener.aidl  

package android.os;

import android.os.BatteryProperties;

/**
 * {@hide}
 */

oneway interface IBatteryPropertiesListener {
    void batteryPropertiesChanged(in BatteryProperties props);
}


\frameworks\base\core\java\android\os\IBatteryPropertiesRegistrar.aidl

package android.os;

import android.os.IBatteryPropertiesListener;

/**
 * {@hide}
 */

interface IBatteryPropertiesRegistrar {
    void registerListener(IBatteryPropertiesListener listener);
    void unregisterListener(IBatteryPropertiesListener listener);
}

當編譯的時候會自動生成 IBatteryPropertiesListener.java  與 IBatteryPropertiesRegistrar.java 檔案。這個我就不多贅述了。

好吧,我們總結下第二個問題:


1、在BatteryService.java 實現回撥函式中的介面,並註冊到BatteryPropertiesRegistrar 中。

2、Healthd 中監控PMU 驅動,事件變更,呼叫BatteryMonitor中的update()函式中回撥BatteryPropertiesRegistrar註冊的介面,呼叫的就是BatteryService.java 實現的介面

到此,我們電池電量管理底層分析(C\C++層) 的分析已經完成。  如果你要了解 BatteryService.java 中被回撥後執行了哪些事情,請觀看我的部落格 :

android 4.4 電池電量顯示分析(低電量提醒與電池圖示)Java 層 (http://blog.csdn.net/daweibalang717/article/details/40615453)

相關推薦

android 4.4 電池電量管理底層分析(C\C++)

參考文獻:http://blog.csdn.net/wlwl0071986/article/details/38778897 簡介: Linux電池驅動用於和PMIC互動、負責監聽電池產生的相關事件,例如低電報警、電量發生變化、高溫報警、USB插拔等等。 Android電池

android 監聽電池電量的變化

package com.example.test; import android.app.Activity; import android.app.Dialog; import android.content.BroadcastReceiver; import andro

Android usb子系統的 電源管理 流程分析

對的處理器是高通MSM8260,主要是針對一些掛起喚醒流程進行分析,以便對整個usb框架流程更好的理解。 由於linux中的電源管理比較複雜,我就找了一個統一的介面,也就是 要想操縱usb的電源管理 必定要調的函式。順便說下,跟蹤程式碼最好的方法是用WARN_ON(1

Android 4.4 電池電量顯示相關。

最近遇到個新的需求,當電池溫度過高以及OVP狀態的時候,在使用者介面提示資訊。 電池電源資訊相關在Framework層/ 與電池電量資訊等相關類: 1.BatteryManager.java 2.BatteryProperties.java 3.BatterySt

android原始碼4.4.2----系統啟動過程分析

public class SystemServer {   private static final String TAG = "SystemServer";   public static final int FACTORY_TEST_OFF = 0;   public static final int F

Android系統載入Apk檔案的時機和流程分析(1)--Android 4.4.4 r1的原始碼

Android系統在啟動時安裝應用程式的過程,這些應用程式安裝好之後,還需要有一個Home應用程式來負責把它們在桌面上展示出來,在Android系統中,這個預設的Home應用程式就是Launcher了。Android系統的Home應用程式Launcher是由Activit

android電池充電以及電量檢測驅動分析

http://www.cnblogs.com/riskyer/p/3275632.html    前段時間比較煩躁,各種不想學習不想工作,於是休息了幾天。這幾天又下來任務了--除錯充電電路和電池電量檢測電路,於是又開始工作,順便把除錯過程記錄下來。   平臺: cpu  

【SSH專案實戰】國稅協同平臺-4.使用者管理需求分析&CRUD方法2

下面我們繼續來完成我們的使用者管理模組 回顧一下我們的列表部分介面: 然後我們開始寫新增方法,原來的列表介面的HTML如下:<%@ page contentType="text/html;charset=UTF-8" language="java" %> <

Android 4.4.4 -Andoird 5.0.0代理(ProxySlector 中select函式)導致的BUG分析

tag d3c92892dd20b7362fe5039f99a0c49304425e30 tagger The Android Open Source Project <[email protected]> Mon Mar 02 08:26:28 2015 -0800 objec

android 4.4 按鍵分析四--鍵盤新增

這部分簡單介紹Keypad的基本知識。(圖片上傳不了,後續再補) 對於輸入裝置, 一般支援的API功能如下, 分配/釋放一個輸入裝置: struct input_dev *input_allocate_device(void); void input_free_

Android 4.4 自動撥打分機流程分析

Android 自動撥打分機流程分析,現在我們只關注framework層,以CDMA為例,GSM同理。 至於什麼是自動撥打分機,如下圖,輸入一個電話號碼,再選擇“等待時間延長2秒”,就會顯示一個分號,接著就可以輸入分機號碼了 本文來自http://b

[Android]異常4-javax.mail.AuthenticationFailedException

llb src pop set com ava smtp exceptio .net javax.mail.AuthenticationFailedException 背景:JavaMail發送電子郵件 異常原因: 可能一>發件人帳號、密碼有誤 可能二>需要使用

[Android 4.4.2] 泛泰A850 Mokee4.4.2 20140509 RC2.0 by syhost

無線 tails 新的 ble safe 機會 color 替代 them 感謝: tenfar(R大師),zhaochengw(z大)。windxixi(雪狐),xuefy(大星星)。suky, cofface 感謝參考代碼: Cyanogenmod , mar

OAuth2.0學習(4-11)spring-oauth-server分析 - http元素使用的是何種AuthenticationManager?

認證 lte filters -1 oauth2 authent spring src 自己 1、在加載配置文件定義時,判斷使用哪個AuthenticationManager 在配置文件Security.xml加載時,首先創建一個ProviderManager

GetPathFromUri4kitkat【Android 4.4 kitkat以上及以下根據uri獲取路徑的方法】

under als providers textview href 數據權限 res activit nload 版權聲明:本文為博主原創文章,未經博主允許不得轉載。 前言 在Android4.4之前和之後,通過Intent調用文件管理器選擇文件,獲取的文件uri地址形

Android 4.4.2引入的超炫動畫庫

4.5 1.4.1 name api level image orm 基本 aca 概述 概述 Scene Transition TransitionManager 常用API 1.4.1. AutoTransition 1.4.2. Chan

Python數據分析(二): Numpy技巧 (4/4)

div 基本 images atp 工具 cnblogs note 屬性。 html numpy、pandas、matplotlib(+seaborn)是python數據分析/機器學習的基本工具。 numpy的內容特別豐富,我這裏只能介紹一下比較常見的方法和屬性。

Mongo 3.4.7 權限管理

war create 連接數 連接 tab 使用權限管理 真的是 格式 pretty 今天早上剛上班,看到公司數據庫裏多了一個Warning庫,打開一看,嚇了一跳,收到勒索! 在網上找了一些解決方案,結果真的是解決方案。http://bbs.chinaunix.net/th

13.4 mysql用戶管理 13.5 常用sql語句 13.6 mysql數據庫備份恢復

13.4 mysql用戶管理 13.5 常用sql語句 13.6 mysql數據庫備份恢復- 13.4 mysql用戶管理 - 13.5 常用sql語句 - 13.6 mysql數據庫備份恢復 - 擴展 - SQL語句教程 http://blog.51cto.com/zt/206 - 什麽是事務?事務的特性

使用VS2017開發APP中使用VUE.js開發遇到打包出來的android文件 在低版本的android4.3)中無法正常使用

vue.js 文件 默認 項目 let ons dir file 開發app 使用VS2017開發VUE的APP應用遇到的問題集合 1, 打包出來的apk文件在Android 6.0版本以上手機可以正常打開,在Android 4.3版本手機上無法打開 原因:一開