Android Framework 电源子系统(06)电池管理

123 篇文章 94 订阅

该系列文章总纲链接:专题分纲目录 Android Framework 电源子系统


本章关键点总结 & 说明:

本章节主要关注➕ 电池管理  部分 即可。该章节 主要是 BatteryService、Healthd守护进程 、BatteryMonitor类 部分 进行 详细解读。

1 BatteryService 的 启动 和 作用

1.1 BatteryService启动

PowerManagerService中调用了 BatteryService类的一些接口 来获得电池的状态,启动过程从SystemServer中开始,在SystemServer中 创建BatteryService、PowerManagerService、ActivityManagerService,这里关注在startCoreServices方法中 创建的BatteryService,代码如下:

private void startCoreServices() {
    // Manages LEDs and display backlight.
    mSystemServiceManager.startService(LightsService.class);

    // Tracks the battery level.  Requires LightService.
    mSystemServiceManager.startService(BatteryService.class);
    //...
}

其中,BatteryService的构造方法 代码如下:

public BatteryService(Context context) {
    super(context);
    mContext = context;
    mHandler = new Handler(true /*async*/);

    //控制 充电 呼吸灯颜色
    mLed = new Led(context, getLocalService(LightsManager.class));

    //获得BatteryStatsService对象,统计和记录电池参数 信息
    mBatteryStats = BatteryStatsService.getService();

    //读取res中常用的battery配置信息,各种低电量的报警值:低电量提醒、高温关机等
    //表示 电量 严重不足时的值,低于这个值 系统将关闭
    mCriticalBatteryLevel = mContext.getResources().getInteger(
            com.android.internal.R.integer.config_criticalBatteryWarningLevel);
    //表示 电量 严重不足时的值,低于这个值 系统将发出警告
    mLowBatteryWarningLevel = mContext.getResources().getInteger(
            com.android.internal.R.integer.config_lowBatteryWarningLevel);
    //表示 停止 电量不足 警告的值,电量高于这个值后 系统将停止电量不足的警告
    mLowBatteryCloseWarningLevel = mLowBatteryWarningLevel + mContext.getResources().getInteger(
            com.android.internal.R.integer.config_lowBatteryCloseWarningBump);
    //表示 电池温度太高的值,高于这个温度 系统将关机
    mShutdownBatteryTemperature = mContext.getResources().getInteger(
            com.android.internal.R.integer.config_shutdownBatteryTemperature);

    //监听下面文件:无效的充电设备
    if (new File("/sys/devices/virtual/switch/invalid_charger/state").exists()) {
        //监听uevent事件 对象,用于监听设备插入无效充电的事件,事件发生时会执行回调函数
        mInvalidChargerObserver.startObserving(
                "DEVPATH=/devices/virtual/switch/invalid_charger");
    }
}

这里 主要 监听底层上报的battery事件,广播电池发生改变的消息(Intent.ACTION_BATTERY_CHANGED),在 构造函数 最后部分 执行了 mInvalidChargerObserver的startObserving方法,mInvalidChargerObserver是一个 监听Uevent事件的对象,这里主要用于 监听 设备 插入了 无效充电器的 事件,事件发生时 将会调用 改对象的onUevent设备文件方法,代码 如下所示:

private final UEventObserver mInvalidChargerObserver = new UEventObserver() {
    @Override
    public void onUEvent(UEventObserver.UEvent event) {
        final int invalidCharger = "1".equals(event.get("SWITCH_STATE")) ? 1 : 0;
        synchronized (mLock) {
            /*
              确保mInvalidCharger = invalidCharger,这样
              通过BatteryService查询充电器是否匹配
            */
            if (mInvalidCharger != invalidCharger) {
                mInvalidCharger = invalidCharger;
            }
        }
    }
};

1.2 onStart 方法的分析

在SystemServer种,由SystemServiceManager对象来启动 BatteryService,就会调用其对应的onStart方法,因此这里也会详细分析下这部分,代码如下:

@Override
public void onStart() {
    IBinder b = ServiceManager.getService("batteryproperties");
    final IBatteryPropertiesRegistrar batteryPropertiesRegistrar =
            IBatteryPropertiesRegistrar.Stub.asInterface(b);
    try {
        batteryPropertiesRegistrar.registerListener(new BatteryListener());
    } catch (RemoteException e) {
        // Should never happen.
    }

    publishBinderService("battery", new BinderService());
    publishLocalService(BatteryManagerInternal.class, new LocalService());
}

这里创建了一个BatteryListener对象 并 把它 加入到 batteryprogpreg服务的回调接口中,这里先分析下 BatteryListener类的定义:

private final class BatteryListener extends IBatteryPropertiesListener.Stub {
    @Override
    public void batteryPropertiesChanged(BatteryProperties props) {
        final long identity = Binder.clearCallingIdentity();
        try {
            BatteryService.this.update(props);
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
   }
}

BatteryListener是一个Binder服务类,因此batteryprogpreg服务通过它传递数据,传回的数据类型是BatteryProperties,定义如下:

public class BatteryProperties implements Parcelable {
    public boolean chargerAcOnline; //正在用AC充电器 充电
    public boolean chargerUsbOnline; //正在用 USB充电器 充电
    public boolean chargerWirelessOnline; // 正在用 无线充电器 充电
    public int batteryStatus; //电池状态值
    public int batteryHealth; //电池健康度
    public boolean batteryPresent; //设备是否在使用电池供电
    public int batteryLevel; //电量级别
    public int batteryVoltage; //电压值
    public int batteryTemperature; //电池温度
    public String batteryTechnology; // 电池制造商信息

    public BatteryProperties() {
    }
    //...
}

2 Healthd 守护进程

该守护进程路径位置 为 system/core/healthd, healthd 一方面监听来自底层的电池事件,另一方面 传递电池数据信息给Framework层的BatteryService用以 计算 电池电量 相关信息,healthd在电池管理系统中起着承上启下的作用。在init.rc 中 是这样启动的:

service healthd /sbin/healthd
    class core
    critical
    seclabel u:r:healthd:s0

healthd 的代码位置在/system/core/healthd下,main函数 代码实现如下:

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

    klog_set_level(KLOG_LEVEL);
    healthd_mode_ops = &android_ops;

    //解析参数
    //...
    ret = healthd_init();
    //...

    //进入主循环
    healthd_mainloop();
    KLOG_ERROR("Main loop terminated, exiting\n");
    return 3;
}

这里 专注分析 两个函数 healthd_init 和 healthd_mainloop

2.1 healthd_init 分析

healthd_init代码实现如下:

static int healthd_init() {
    epollfd = epoll_create(MAX_EPOLL_EVENTS);
    //...

    healthd_board_init(&healthd_config);
    healthd_mode_ops->init(&healthd_config);
    wakealarm_init(); //创建一个定时器 文件句柄
    uevent_init();    //初始化uevent环境
    //创建 BatteryMonitor 对象
    gBatteryMonitor = new BatteryMonitor();
    gBatteryMonitor->init(&healthd_config);
    return 0;
}

继续分析wakealarm_init的实现,代码如下:

static void wakealarm_init(void) {
    // 创建 一个 定时器 的 文件句柄
    wakealarm_fd = timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK);
    if (wakealarm_fd == -1) {
        KLOG_ERROR(LOG_TAG, "wakealarm_init: timerfd_create failed\n");
        return;
    }
    //将wakealarm_fd 加入到 epoll 监听列表中
    if (healthd_register_event(wakealarm_fd, wakealarm_event))
        KLOG_ERROR(LOG_TAG,"Registration of wakealarm event failed\n");
    //设置定时器 超时 时间
    wakealarm_set_interval(healthd_config.periodic_chores_interval_fast);
}

这个定时器 在healthd_mainloop 中有意义;再看下 uevent_init的实现,代码如下:

static void uevent_init(void) {
    uevent_fd = uevent_open_socket(64*1024, true);
    //错误处理
    //...
    fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
    //将 uevent_fd 加入到 epoll 监听列表中
    if (healthd_register_event(uevent_fd, uevent_event))
        KLOG_ERROR(LOG_TAG,"register for uevent events failed\n");
}

这里实际上 将 uevent_fd 和 wakealarm_fd的句柄 均加入到 epoll 的 监听列表中。

2.2 healthd_mainloop 分析

healthd_mainloop代码实现如下:

static void healthd_mainloop(void) {
    while (1) {
        struct epoll_event events[eventct];
        int nevents;
        int timeout = awake_poll_interval;
        int mode_timeout;

        mode_timeout = healthd_mode_ops->preparetowait();
        if (timeout < 0 || (mode_timeout > 0 && mode_timeout < timeout))
            timeout = mode_timeout;
        nevents = epoll_wait(epollfd, events, eventct, timeout);
        //...
        //错误处理
        //...
        for (int n = 0; n < nevents; ++n) {
            if (events[n].data.ptr)
                //调用 事件的处理函数
                (*(void (*)(int))events[n].data.ptr)(events[n].events);
        }

        if (!nevents)//nevents = 0,表示没有nevents
            periodic_chores();

        healthd_mode_ops->heartbeat();
    }
    return;
}

之前 在healthd_init中 将 uevent_fd 和 wakealarm_fd 的句柄 均加入到 epoll 的 监听列表中,而这里主要是epoll 接收到数据的 处理。针对 uevent 事件 和 wakealarm 事件的处理以及 没有事件的处理流程分别如下。

@1 uevent 事件处理

static void uevent_event(uint32_t /*epevents*/) {
    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)) {
            healthd_battery_update();
            break;
        }

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

这里主要 调用了 healthd_battery_update方法,实现如下:

void healthd_battery_update(void) {
    /*
      调用gBatteryMonitor->update() 函数来读取电池的
      状态,根据返回值来决定是否更新定时器的时间周期
      这样,系统的电池状态就会持续更新。
    */
    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);
    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;
}

@2 wakealarm 事件处理

static void wakealarm_event(uint32_t /*epevents*/) {
    unsigned long long wakeups;

    if (read(wakealarm_fd, &wakeups, sizeof(wakeups)) == -1) {
        KLOG_ERROR(LOG_TAG, "wakealarm_event: read wakealarm fd failed\n");
        return;
    }

    periodic_chores();
}

这里主要是 把事件 从wakealarm_fd中读取后调用periodic_chores方法。与 空事件处理一致,参考@3。

@3 空事件处理

static void periodic_chores() {
    healthd_battery_update();
}

healthd_battery_update 的 分析 参考@1。

3 读取电池 各种参数 BatteryMonitor类 分析

上面 healthd_battery_update 分析中调用了gBatteryMonitor->update() 函数来读取电池的状态,根据返回值来决定是否更新定时器的时间周期,这样系统电池状态就会持续更新。接下来对BatteryMonitor类 进行分析,在healthd_init中创建 BatteryMonitor,之后执行了 BatteryMonitor的init方法。之后在healthd_mainloop中 执行了BatteryMonitor的update方法,因此 对于BatteryMonitor 我们对 BatteryMonitor 的 init 方法 和 update方法 进行分析。

3.1 BatteryMonitor 的 init 代码分析

代码实现如下:

#define POWER_SUPPLY_SUBSYSTEM "power_supply"
#define POWER_SUPPLY_SYSFS_PATH "/sys/class/" POWER_SUPPLY_SUBSYSTEM

void BatteryMonitor::init(struct healthd_config *hc) {
    String8 path;
    char pval[PROPERTY_VALUE_MAX];

    mHealthdConfig = hc;
    /*
      打开文件夹 /sys/class/power_supply
      battery存放的是电池信息
      usb目录表示usb充电器信息,online为1表示正在充电
      wireless表示无线充电器信息。
      ups usb_dcp usb_cdp usb_aca表示不同的AC充电器信息
      
    */
    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:
                mBatteryDevicePresent = true;

                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;
                }
                //...
                break;

            case ANDROID_POWER_SUPPLY_TYPE_UNKNOWN:
                break;
            }
        }
        closedir(dir);
    }
    //日志输出...
    if (property_get("ro.boot.fake_battery", pval, NULL) > 0
                                               && strtol(pval, NULL, 10) != 0) {
        mBatteryFixedCapacity = FAKE_BATTERY_CAPACITY;
        mBatteryFixedTemperature = FAKE_BATTERY_TEMPERATURE;
    }
}

init函数主要功能就是生成所有 这些文件的文件名并保存到 成员变量中,方便以后读取。

3.2 BatteryMonitor 的 update 代码分析

代码实现如下:

bool BatteryMonitor::update(void) {
    bool logthis;

    props.chargerAcOnline = false;
    props.chargerUsbOnline = false;
    props.chargerWirelessOnline = false;
    props.batteryStatus = BATTERY_STATUS_UNKNOWN;
    props.batteryHealth = BATTERY_HEALTH_UNKNOWN;
    //读取 /sys/class/power_supply文件夹下 各种文件信息(电池信息)来构建props
    if (!mHealthdConfig->batteryPresentPath.isEmpty())
        props.batteryPresent = getBooleanField(mHealthdConfig->batteryPresentPath);
    else
        props.batteryPresent = mBatteryDevicePresent;

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

    props.batteryTemperature = mBatteryFixedTemperature ?
        mBatteryFixedTemperature :
        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());
                }
            }
        }
    }
    //...
    //日志处理
    //...
    healthd_mode_ops->battery_update(&props);
    return props.chargerAcOnline | props.chargerUsbOnline |
            props.chargerWirelessOnline;
}

这里关注最后的healthd_mode_ops->battery_update(&props); 如果是android的正常开机模式,则healthd_mode_ops(函数指针)的实际函数是healthd_mode_android_battery_update,它的实现如下所示:

void healthd_mode_android_battery_update(
    struct android::BatteryProperties *props) {
    if (gBatteryPropertiesRegistrar != NULL)
        gBatteryPropertiesRegistrar->notifyListeners(*props);
    return;
}

这里会通过gBatteryPropertiesRegistrar变量的notifyListeners函数把保存在props中的电池信息传递到BatteryService中。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

图王大胜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值