文档章节

Android Healthd电池服务分析

o
 osc_zoa3moe9
发布于 2019/12/07 16:05
字数 1673
阅读 19
收藏 0

精选30+云产品,助力企业轻松上云!>>>

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电池系统框架

image

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模式不再分析。

o
粉丝 1
博文 500
码字总数 0
作品 0
私信 提问
加载中
请先登录后再评论。
android6.0系统Healthd分析及低电量自动关机流程

系统平台:android6.0 概述 Healthd是android4.4之后提出来的一种中介模型,该模型向下监听来自底层的电池事件,向上传递电池数据信息给Framework层的BatteryService用以计算电池电量相关状态...

osc_tjdfnjyo
2018/12/25
2
0
[日更-2019.5.19] Android 系统内的守护进程(二)--core类中的服务 : healthd

声明 其实很好奇Android系统中的一些关键守护进程服务的作用; 暂且大概分析下它们的作用,这样有助于理解整个系统的工作过程; 0 写在前面的 只要是操作系统,不用说的就是其中肯定会运行着...

Captain_小馬佩德罗
2019/06/13
49
0
Android4.4电池管理

一、概述 Android4.4的电池管理功能用于管理电池的充、放电功能。整个电池管理的部分包括Linux电池驱动、Android电池服务、电池属性和参数、电池曲线优化四个部分。 Linux电池驱动用于和PMI...

sflfqx
2015/01/26
356
0
Android内核开发:学会分析系统的启动log

本文是《Android内核开发》系列的第八篇文章,本文主要关注如何分析Android系统的启动log,学会通过搜索重要的TAG标签,找到Android启动过程中的重要节点。 要学会分析系统的启动log信息,首...

Jhuster
2015/06/17
0
0
Android 休眠唤醒频繁问题分析的一些工具

大家都知道目前的手机,平板等电子设备耗电都比较大,Android系统因为历史和开源等原因,一直对耗电支持的不是很好。特别现在很多apk完全不care耗电,动不动给你装上全家桶,还会相互间互相唤...

android之子
2017/09/01
0
0

没有更多内容

加载失败,请刷新页面

加载更多

【Nginx】实现负载均衡、限流、缓存、黑白名单和灰度发布,这是最全的一篇了!

写在前面 在《【高并发】面试官问我如何使用Nginx实现限流,我如此回答轻松拿到了Offer!》一文中,我们主要介绍了如何使用Nginx进行限流,以避免系统被大流量压垮。除此之外,Nginx还有很多...

osc_6l5fg87g
28分钟前
9
0
一小时完成后台开发:DjangoRestFramework开发实践

DjangoRestFramework开发实践 在这之前我写过一篇关于Django与Drf快速开发实践的博客,Django快速开发实践:Drf框架和xadmin配置指北,粗略说了一下Drf配置和基本使用,不过里面只是涉及到最...

osc_z2ru77w0
29分钟前
14
0
数据载入、存储及文件格式知识图谱-《利用Python进行数据分析》

所有内容整理自《利用Python进行数据分析》,使用MindMaster Pro 7.3制作,emmx格式,源文件已经上传Github,需要的同学转左上角自行下载或者右击保存图片。

osc_161difcz
31分钟前
8
0
Java异常

一、异常? java系统中将java.lang.Throwable类作为异常的最根类 [java.lang.Throwable是所有异常或错误的顶级类,可以处理任何异常] * java.lang.Throwable * |-----java.lang.Error:一般...

osc_o44vh5qb
32分钟前
23
0
(1)Linux系统中到底应该怎么理解系统的平均负载

每次发现系统变慢时,我们通常做的第一件事,就是执行 top 或者 uptime 命令,来了解系统的负载情况。比如像下面这样,我在命令行里输入了 uptime 命令,系统也随即给出了结果。 $ uptime...

osc_i5oyb1xr
33分钟前
10
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部