专栏首页linux驱动个人学习Android Healthd电池服务分析

Android Healthd电池服务分析

healthd

healthd是安卓4.4之后提出来的,监听来自kernel的电池事件,并向上传递电池数据给framework层的BatteryService。BatteryService计算电池电量显示,剩余电量,电量级别以及绘制充电动画等信息,其代码位于/system/core/healthd。

android/system/core/healthd/
Android.mk          BatteryMonitor.h                BatteryPropertiesRegistrar.h  healthd.cpp  healthd_mode_android.cpp  images
BatteryMonitor.cpp  BatteryPropertiesRegistrar.cpp  healthd_board_default.cpp     healthd.h    healthd_mode_charger.cpp

下面一张图清晰的表示了Android电池系统框架

healthd服务入口:android/system/core/healthd/healthd.cpp 中main函数。

int main(int argc, char **argv) {
    int ch;
    int ret;
 
    klog_set_level(KLOG_LEVEL);
 
    
    //healthd_mode_ops是一个关于充电状态的结构体变量,
    healthd_mode_ops = &android_ops;//开机充电时,指向android_ops
 
    if (!strcmp(basename(argv[0]), "charger")) {
        healthd_mode_ops = &charger_ops; //
    } else {
        while ((ch = getopt(argc, argv, "cr")) != -1) {
            switch (ch) {
            case 'c':
                healthd_mode_ops = &charger_ops; //关机状态下的充电
                break;
            case 'r':
                healthd_mode_ops = &recovery_ops;//recovery下的操作
                break;
            case '?':
            default:
                KLOG_ERROR(LOG_TAG, "Unrecognized healthd option: %c\n",
                           optopt);
                exit(1);
            }
        }
    }
 
    ret = healthd_init(); //healthed初始化
    if (ret) {
        KLOG_ERROR("Initialization failed, exiting\n");
        exit(2);
    }
 
    healthd_mainloop(); //主循环
    KLOG_ERROR("Main loop terminated, exiting\n");
    return 3;
}

在main函数中,首先根据传入的参数不同区分:开机充电、recovery、关机充电。这三种情况,然后指定不同的healthd_mode_ops回调函数。因此有必要贴出来这三个重要的回调。

///////////////////////////////////////////////////////////////////////////三个相关的ops
static struct healthd_mode_ops android_ops = {            开机充电
    .init = healthd_mode_android_init,
    .preparetowait = healthd_mode_android_preparetowait,
    .heartbeat = healthd_mode_nop_heartbeat,
    .battery_update = healthd_mode_android_battery_update,
};
 
static struct healthd_mode_ops charger_ops = {             关机充电
    .init = healthd_mode_charger_init,
    .preparetowait = healthd_mode_charger_preparetowait,
    .heartbeat = healthd_mode_charger_heartbeat,
    .battery_update = healthd_mode_charger_battery_update,
};
 
static struct healthd_mode_ops recovery_ops = {            recover相关的
    .init = healthd_mode_nop_init,
    .preparetowait = healthd_mode_nop_preparetowait,
    .heartbeat = healthd_mode_nop_heartbeat,
    .battery_update = healthd_mode_nop_battery_update,
};

接着往下看healthd_init()

static int healthd_init() {
    epollfd = epoll_create(MAX_EPOLL_EVENTS);//创建一个epoll变量
    if (epollfd == -1) {
        KLOG_ERROR(LOG_TAG,
                   "epoll_create failed; errno=%d\n",
                   errno);
        return -1;
    }
    //和板子级别的初始化,里面其实是一个空函数,什么也没做
    healthd_board_init(&healthd_config);
    //根据系统所处的模式,有三种情况的init,开机充电,关机充电,recovery
    healthd_mode_ops->init(&healthd_config);
    //wakealarm定时器初始化
    wakealarm_init();
    //uevent事件初始化,用以监听电池的uevent事件。
    uevent_init();
    //BatteryMonitor初始化。
    gBatteryMonitor = new BatteryMonitor();//创建batteryMonitor对象
    gBatteryMonitor->init(&healthd_config);//初始化batteryMonitor,打开/sys/class/power_supply,
                                           //遍历该节点下的电池参数初始化healthd的config参数
    return 0;
}

healthd_mode_ops->init(&healthd_config);根据main函数中传入的参数 有三种模式,Android,charger,recovery。

android模式

void healthd_mode_android_init(struct healthd_config* /*config*/) {
    ProcessState::self()->setThreadPoolMaxThreadCount(0);//获取线程池最大线程数
    IPCThreadState::self()->disableBackgroundScheduling(true);//禁止后台调用
    IPCThreadState::self()->setupPolling(&gBinderFd);//将gBinderFd加入到epoll中
 
    if (gBinderFd >= 0) {
        //将binder_event事件注册到gBinderfd文件节点用以监听Binder事件。
        if (healthd_register_event(gBinderFd, binder_event))
            KLOG_ERROR(LOG_TAG,
                       "Register for binder events failed\n");
    }
 
    gBatteryPropertiesRegistrar = new BatteryPropertiesRegistrar();
    //将batteryProperties注册到ServiceManager中 
    gBatteryPropertiesRegistrar->publish();
}

charger模式就是关机充电模式,Android层只跑一个healthd服务用来显示充电动画和电量百分比。

charger模式
 
void healthd_mode_charger_init(struct healthd_config* config) //做充电动画相关的设置
{
    int ret;
    struct charger *charger = &charger_state;
    int i;
    int epollfd;
 
    dump_last_kmsg();
 
    LOGW("--------------- STARTING CHARGER MODE ---------------\n");
 
    ret = ev_init(input_callback, charger);
    if (!ret) {
        epollfd = ev_get_epollfd();
        healthd_register_event(epollfd, charger_event_handler);
    }
 
    ret = res_create_display_surface("charger/battery_fail", &charger->surf_unknown);
    if (ret < 0) {
        LOGE("Cannot load battery_fail image\n");
        charger->surf_unknown = NULL;
    }
 
    charger->batt_anim = &battery_animation; //指定充电动画相关的属性
 
    gr_surface* scale_frames;
    int scale_count;
    ret = res_create_multi_display_surface("charger/battery_scale", &scale_count, &scale_frames);//读取充电动画资源
    if (ret < 0) {
        LOGE("Cannot load battery_scale image\n");
        charger->batt_anim->num_frames = 0;
        charger->batt_anim->num_cycles = 1;
    } else if (scale_count != charger->batt_anim->num_frames) {
        LOGE("battery_scale image has unexpected frame count (%d, expected %d)\n",
             scale_count, charger->batt_anim->num_frames);
        charger->batt_anim->num_frames = 0;
        charger->batt_anim->num_cycles = 1;
    } else {
        for (i = 0; i < charger->batt_anim->num_frames; i++) {  //读取资源成功,存放起来
            charger->batt_anim->frames[i].surface = scale_frames[i];
        }
    }
 
    ev_sync_key_state(set_key_callback, charger);
 
    charger->next_screen_transition = -1;
    charger->next_key_check = -1;
    charger->next_pwr_check = -1;
    healthd_config = config;
}
//接着到wakealarm_init
static void wakealarm_init(void) {
    //创建一个月wakealarm对应的定时器描述符
    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事件注册到wakealarm_fd文件节点上以监听wakealarm事件。
    if (healthd_register_event(wakealarm_fd, wakealarm_event))
        KLOG_ERROR(LOG_TAG,
                   "Registration of wakealarm event failed\n");
    //设置alarm唤醒间隔
    wakealarm_set_interval(healthd_config.periodic_chores_interval_fast);
}

如果是关机充电模式,则healthd_mode_ops->heartbeat(); 执行的是healthd_mode_charger_heartbeat()函数

void healthd_mode_charger_heartbeat()
{
    struct charger *charger = &charger_state;
    int64_t now = curr_time_ms();
    int ret;
 
    handle_input_state(charger, now);      //处理按键相关的事情,长按开机
    handle_power_supply_state(charger, now);
 
    /* do screen update last in case any of the above want to start
     * screen transitions (animations, etc)
     */
    update_screen_state(charger, now); //绘制充电动画
}
frameworks/base/services/core/java/com/android/server/BatteryService.java 
//将电池监听注册到底层
public void onStart() {
    IBinder b = ServiceManager.getService("batteryproperties");
    final IBatteryPropertiesRegistrar batteryPropertiesRegistrar =
            IBatteryPropertiesRegistrar.Stub.asInterface(b);
    try {
        //注册电池监听,当底层电池电量发生变化调用此监听,并调用update。
        batteryPropertiesRegistrar.registerListener(new BatteryListener());
    } catch (RemoteException e) {
        // Should never happen.
    }
 
    publishBinderService("battery", new BinderService());
    publishLocalService(BatteryManagerInternal.class, new LocalService());
}
//当底层有信息时,会调用update更新BatteryService中相关值。
    private void update(BatteryProperties props) {
        synchronized (mLock) {
            if (!mUpdatesStopped) {
                mBatteryProps = props;
                // Process the new values.
                processValuesLocked(false);
            } else {
                mLastBatteryProps.set(props);
            }
        }
    }
private void processValuesLocked(boolean force) {
        boolean logOutlier = false;
        long dischargeDuration = 0;
        //获取电池电量是否低于critical界限。
        mBatteryLevelCritical = (mBatteryProps.batteryLevel <= mCriticalBatteryLevel);
        //获取电池充电状态,AC,USB,无线,以及什么都没接。
        if (mBatteryProps.chargerAcOnline) {
            mPlugType = BatteryManager.BATTERY_PLUGGED_AC;
        } else if (mBatteryProps.chargerUsbOnline) {
            mPlugType = BatteryManager.BATTERY_PLUGGED_USB;
        } else if (mBatteryProps.chargerWirelessOnline) {
            mPlugType = BatteryManager.BATTERY_PLUGGED_WIRELESS;
        } else {
            mPlugType = BATTERY_PLUGGED_NONE;
        }
 
        if (DEBUG) {
            Slog.d(TAG, "Processing new values: "
                    + "chargerAcOnline=" + mBatteryProps.chargerAcOnline
                    + ", chargerUsbOnline=" + mBatteryProps.chargerUsbOnline
                    + ", chargerWirelessOnline=" + mBatteryProps.chargerWirelessOnline
                    + ", batteryStatus=" + mBatteryProps.batteryStatus
                    + ", batteryHealth=" + mBatteryProps.batteryHealth
                    + ", batteryPresent=" + mBatteryProps.batteryPresent
                    + ", batteryLevel=" + mBatteryProps.batteryLevel
                    + ", batteryTechnology=" + mBatteryProps.batteryTechnology
                    + ", batteryVoltage=" + mBatteryProps.batteryVoltage
                    + ", batteryTemperature=" + mBatteryProps.batteryTemperature
                    + ", mBatteryLevelCritical=" + mBatteryLevelCritical
                    + ", mPlugType=" + mPlugType);
        }
 
        // Let the battery stats keep track of the current level.
        try {
            mBatteryStats.setBatteryState(mBatteryProps.batteryStatus, mBatteryProps.batteryHealth,
                    mPlugType, mBatteryProps.batteryLevel, mBatteryProps.batteryTemperature,
                    mBatteryProps.batteryVoltage);
        } catch (RemoteException e) {
            // Should never happen.
        }
        //低电关机
        shutdownIfNoPowerLocked();
        //电池温度过高关机
        shutdownIfOverTempLocked();
 
        if (force || (mBatteryProps.batteryStatus != mLastBatteryStatus ||
                mBatteryProps.batteryHealth != mLastBatteryHealth ||
                mBatteryProps.batteryPresent != mLastBatteryPresent ||
                mBatteryProps.batteryLevel != mLastBatteryLevel ||
                mPlugType != mLastPlugType ||
                mBatteryProps.batteryVoltage != mLastBatteryVoltage ||
                mBatteryProps.batteryTemperature != mLastBatteryTemperature ||
                mInvalidCharger != mLastInvalidCharger)) {
            //适配器插入状态有更改
            if (mPlugType != mLastPlugType) {
                if (mLastPlugType == BATTERY_PLUGGED_NONE) {
                    // discharging -> charging
 
                    // There's no value in this data unless we've discharged at least once and the
                    // battery level has changed; so don't log until it does.
                    if (mDischargeStartTime != 0 && mDischargeStartLevel != mBatteryProps.batteryLevel) {
                        dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime;
                        logOutlier = true;
                        EventLog.writeEvent(EventLogTags.BATTERY_DISCHARGE, dischargeDuration,
                                mDischargeStartLevel, mBatteryProps.batteryLevel);
                        // make sure we see a discharge event before logging again
                        mDischargeStartTime = 0;
                    }
                } else if (mPlugType == BATTERY_PLUGGED_NONE) {
                    // charging -> discharging or we just powered up
                    mDischargeStartTime = SystemClock.elapsedRealtime();
                    mDischargeStartLevel = mBatteryProps.batteryLevel;
                }
            }
            //电池状态更新
            if (mBatteryProps.batteryStatus != mLastBatteryStatus ||
                    mBatteryProps.batteryHealth != mLastBatteryHealth ||
                    mBatteryProps.batteryPresent != mLastBatteryPresent ||
                    mPlugType != mLastPlugType) {
                EventLog.writeEvent(EventLogTags.BATTERY_STATUS,
                        mBatteryProps.batteryStatus, mBatteryProps.batteryHealth, mBatteryProps.batteryPresent ? 1 : 0,
                        mPlugType, mBatteryProps.batteryTechnology);
            }
            if (mBatteryProps.batteryLevel != mLastBatteryLevel) {
                // Don't do this just from voltage or temperature changes, that is
                // too noisy.
                EventLog.writeEvent(EventLogTags.BATTERY_LEVEL,
                        mBatteryProps.batteryLevel, mBatteryProps.batteryVoltage, mBatteryProps.batteryTemperature);
            }
            if (mBatteryLevelCritical && !mLastBatteryLevelCritical &&
                    mPlugType == BATTERY_PLUGGED_NONE) {
                // We want to make sure we log discharge cycle outliers
                // if the battery is about to die.
                dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime;
                logOutlier = true;
            }
 
            if (!mBatteryLevelLow) {
                // Should we now switch in to low battery mode?
                if (mPlugType == BATTERY_PLUGGED_NONE
                        && mBatteryProps.batteryLevel <= mLowBatteryWarningLevel) {
                    mBatteryLevelLow = true;
                }
            } else {
                // Should we now switch out of low battery mode?
                if (mPlugType != BATTERY_PLUGGED_NONE) {
                    mBatteryLevelLow = false;
                } else if (mBatteryProps.batteryLevel >= mLowBatteryCloseWarningLevel)  {
                    mBatteryLevelLow = false;
                } else if (force && mBatteryProps.batteryLevel >= mLowBatteryWarningLevel) {
                    // If being forced, the previous state doesn't matter, we will just
                    // absolutely check to see if we are now above the warning level.
                    mBatteryLevelLow = false;
                }
            }
            //发送电池状态变换广播
            sendIntentLocked();
 
            // Separate broadcast is sent for power connected / not connected
            // since the standard intent will not wake any applications and some
            // applications may want to have smart behavior based on this.
            if (mPlugType != 0 && mLastPlugType == 0) {
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        Intent statusIntent = new Intent(Intent.ACTION_POWER_CONNECTED);
                        statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
                        mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
                    }
                });
            }
            else if (mPlugType == 0 && mLastPlugType != 0) {
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        Intent statusIntent = new Intent(Intent.ACTION_POWER_DISCONNECTED);
                        statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
                        mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
                    }
                });
            }
            //低电量电池事件通知
            if (shouldSendBatteryLowLocked()) {
                mSentLowBatteryBroadcast = true;
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        Intent statusIntent = new Intent(Intent.ACTION_BATTERY_LOW);
                        statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
                        mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
                    }
                });
            } else if (mSentLowBatteryBroadcast && mLastBatteryLevel >= mLowBatteryCloseWarningLevel) {
                mSentLowBatteryBroadcast = false;
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        Intent statusIntent = new Intent(Intent.ACTION_BATTERY_OKAY);
                        statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
                        mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
                    }
                });
            }
 
            // Update the battery LED
            mLed.updateLightsLocked();
 
            // This needs to be done after sendIntent() so that we get the lastest battery stats.
            if (logOutlier && dischargeDuration != 0) {
                logOutlierLocked(dischargeDuration);
            }
 
            mLastBatteryStatus = mBatteryProps.batteryStatus;
            mLastBatteryHealth = mBatteryProps.batteryHealth;
            mLastBatteryPresent = mBatteryProps.batteryPresent;
            mLastBatteryLevel = mBatteryProps.batteryLevel;
            mLastPlugType = mPlugType;
            mLastBatteryVoltage = mBatteryProps.batteryVoltage;
            mLastBatteryTemperature = mBatteryProps.batteryTemperature;
            mLastBatteryLevelCritical = mBatteryLevelCritical;
            mLastInvalidCharger = mInvalidCharger;
        }
    }

recovery模式不再分析。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • android6.0系统Healthd深入分析

    Healthd是android4.4之后提出来的一种中介模型,该模型向下监听来自底层的电池事件,向上传递电池数据信息给Framework层的BatterySer...

    233333
  • 海思屏幕HAL代码解析

    显示屏幕(LCD)模块提供屏幕相关功能接口,调用者为上层应用模块(含 init、状态机、ui),上下文依赖关系,如图 3-7 所示。

    233333
  • swapper_pg_dir的作用

    在head_32.S中,定义了如下的BSS段,BSS段是在内核映像文件中不占空间,但是在内核被加载到内存时,会保留相应的空间。

    233333
  • 各城市一日内入境究竟有多少人? | Alfred数据室

    近日,在湖北达到连续3天新冠肺炎0新增这个来之不易结果的同时,海外新冠肺炎确诊病例却几乎呈倍数式急剧上升,从入境航班中检测出来的输入型病例也越来越多。

    Alfred数据室
  • SpringCloud源码:Ribbon负载均衡分析

    可以看到,在整合 Ribbon 之前,请求Rest是通过IP端口直接请求。整合 Ribbon 之后,请求的地址改成了 http://applicationNam...

    吴生
  • spring aop注解配置

    spring aop是面向切面编程,使用了动态代理的技术,这样可以使业务逻辑的代码不掺入其他乱七八糟的代码 可以在切面上实现合法性校验、权限检验、日志记录。。。...

    用户1174983
  • 保护隐私,安卓9.0将禁止后台应用调用摄像头和麦克风权限

    由于安卓系统权限管理机制不够完善,黑客可以通过获取麦克风、摄像头等权限在不知情的情况下窃取用户隐私信息。而为了改变这一现状,安卓9.0(初步代号定为Pistac...

    FB客服
  • Pytest | 参数化处理三种类型 [ 列表、元组、字典]

    Pytest参数化测试上期我们介绍到Python自动化测试 | Pytest之参数化 常用的用法如下

    测试小兵
  • java LinkedList简单运用

    package test; import java.util.Iterator; import java.util.LinkedList; public c...

    用户1220053
  • caffe随记(九)---利用FCN和已有的model进行图像语义分割

    1、下载caffemodel 本例中我们使用的是pascalcontext-fcn32的模型,这个下载链接在它的文件夹里有,就是url那个文件 下载  pas...

    TeeyoHuang

扫码关注云+社区

领取腾讯云代金券