Android 源码分析系列综述博文: Android 系统源码分析综述
Platform information: MTK6797(X20)+ Android 7.0
之前做高通的时候,对高通此部分做过粗略的分析,不过当时胡乱做的些笔记,只简单整理了几篇博客,感兴趣可以参考如下路径:
高通平台Android源码bootloader分析之sbl1(一)
高通平台Android源码bootloader分析之sbl1(二)
高通平台Android源码bootloader分析之sbl1(三)
Android不带电量计的电量计算
Android 电源管理架构
Android电池监控系统-BMS-之电池系统架构 (有坑未填)
高通电池管理系统(BMS)驱动分析
高通 smb135x charger 驱动分析
高通 PMIC 架构简析
高通 linear charger 驱动分析
充电简析 充电状态机 电池充电过程分为预充、恒流充电(CC模式)、恒压充电(CV模式)、涓流充电四个流程,MTK的状态机如下:
充电简要流程框图
BMS 架构 MTK 的 BMS 架构如下:
我准备将BMS从硬件到APP分为不同的架构层来分析。接下来分别分析下不同的架构层。
硬件层 硬件层主要分为三个部分:PMIC,Fuel Gauge 和 ADC。本文主要分析软件,所以硬件就不准备深入研究了。
1.1.1 PMIC 智能手机方案一般都会有一个PMIC芯片,有些也还会采用外接充电IC,使不使用外接IC,软件驱动会有一些区别。
Fuel Gauge Fuel Gauge 是 MTK 为充放电、电量算法提供服务的一个硬件电路,电路中的电阻比较重要。
ADC FGADC 和 AUXADC 分别采样电池的电流、电压(还会采样电池温度)。
BootLoader层 BootLoader部分没有在上图表现出来,也可以将其归为driver部分。
1.2.1 Preloader层 此部分会对充电做一些初始设置,比如设置手机尽早开始充电以避免电池低电压不能进入接下来的充电状态,关键路径如下:
1 alps\vendor\mediatek\proprietary\bootable\bootloader\preloader\platform\mt6797\src\drivers\platform.c
LK层 此部分主要针对充电主要做三件事:1. 启动方式、充电状态监测;2. 初始化充电IC;3. 充电器状态监测处理。
启动方式、充电状态监测 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 # alps\vendor\mediatek\proprietary\bootable\bootloader\lk\platform\mt6797\include \platform\boot_mode.h # alps\vendor\mediatek\proprietary\bootable\bootloader\lk\platform\mt6797\boot_mode.c boot_mode_select() # alps\vendor\mediatek\proprietary\bootable\bootloader\lk\platform\mt6797\platform.c platform_init() { upmu_is_chr_det() if (kernel_charging_boot() == 1 ) { mt_disp_power(TRUE); mt_disp_show_low_battery(); mt65xx_leds_brightness_set(6 , 110 ); } } boot_mode_select(); # alps\vendor\mediatek\proprietary\bootable\bootloader\lk\platform\mt6797\mt_kernel_power_off_charging.c set_off_mode_charge_status() kernel_power_off_charging_detection(void ) { get_off_mode_charge_status() if (upmu_is_chr_det() == KAL_TRUE) { if (off_mode_status) { g_boot_mode = KERNEL_POWER_OFF_CHARGING_BOOT; } else { g_boot_mode = NORMAL_BOOT; } return TRUE; } else { mt6575_power_off(); } }
初始化充电IC 充电IC的初始化工作,有些可以被kernel驱动覆盖,有些不能,所以有时候一些修改记得在LK和kernel里面都得完成。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 # alps\vendor\mediatek\proprietary\bootable\bootloader\lk\platform\mt6797\mt_battery.c pchr_turn_on_charging() { bq25890_hw_init(); bq25890_charging_enable(bEnable); bq25890_dump_register(); } # alps\vendor\mediatek\proprietary\bootable\bootloader\lk\platform\mt6797\rules.mk ifeq ($(MTK_BQ25896_SUPPORT),yes) OBJS +=$(LOCAL_DIR)/bq25890.o DEFINES += MTK_BQ25896_SUPPORT DEFINES += SWCHR_POWER_PATH # alps\vendor\mediatek\proprietary\bootable\bootloader\lk\platform\mt6797\include \platform\bq25890.h # alps\vendor\mediatek\proprietary\bootable\bootloader\lk\platform\mt6797\bq25890.c void bq25890_hw_init(void )# 充电IC初始化及电流电压等相关设置
1.2.2.3 充电器状态监测处理 1 2 3 4 5 6 7 8 9 10 11 # alps\vendor\mediatek\proprietary\bootable\bootloader\lk\app\mt_boot\mt_boot.c boot_linux_fdt() { if (kernel_charging_boot() == -1 ) mt6575_power_off(); if (kernel_charging_boot() == 1 ) { if (pmic_detect_powerkey()) { mtk_arch_reset(1 ); } } }
充电图标 MTK之前很多方案是在lk里面绘制关机充电图标,然后采样IPO协议实现关机充电。不过现在已采取高通类似方案在Health部分绘制关机充电图标了。
1 # alps\vendor\mediatek\proprietary\bootable\bootloader\lk\platform\mt6755\mt_logo.c
IPO方式流程图如下:
由于初次接触MTK,又没有深入研究此部分,此部分如有错误,敬请谅解和指出。
Kernel层 Kernel 部分软件流程框图,不过此图是我从MTK文档上截取没有做修改,所以图片中外部充电IC代码为Fan5405,对应于我的代码应该为bq24290(bq24296)。如下:
1.3.1 ADC部分 电流电压采样部分代码没有深入查看,主要看了如下一个文件:
1 2 3 # alps\kernel-3.18\drivers\misc\mediatek\power\mt6797\pmic_auxadc.c pmic_auxadc_init() PMIC_IMM_GetCurrent
HAL部分 此 HAL 并不是真正的 HAL 层,实际是驱动部分,实现部分结构体,针对 MTK 不同充电方案提供支持,读取各项参数。我所阅读的代码使用了外接充电 IC BQ24296(switch charger),驱动不会走 linear_charging.c,走 switch_charging.c + bq25896 驱动部分。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 # alps\kernel-3.18\drivers\misc\mediatek\power\mt6797\charging_hw_pmic.c charging_value_to_parameter() charging_parameter_to_value() charging_hw_init() charging_get/set_current() charging_sw_init() chr_control_interface() # alps\kernel-3.18\drivers\misc\mediatek\include \mt-plat\battery_meter_hal.h BATTERY_METER_CTRL_CMD # alps\kernel-3.18\drivers\misc\mediatek\power\mt6797\battery_meter_hal.c get_hw_ocv read_adc_v_bat_sense () # alps\kernel-3.18\drivers\misc\mediatek\power\mt6797\bq25890.h # alps\kernel-3.18\drivers\misc\mediatek\power\mt6797\bq25890.c bq25890_driver_probe () bq25890_get_xx () bq25890_set_xx () bq25890_hw_init () # alps\kernel-3.18\drivers\misc\mediatek\power\mt6797\charging_hw_bq25890.c is_chr_det () val = pmic_get_register_value(MT6351_PMIC_RGS_CHRDET); charging_hw_init() charging_sw_init() charging_get_xx() charging_get_charger_type() charging_set_xx() charging_set_current()
Common部分 PMIC充电控制、充电控制主线程、SW FG算法等内容在此部分实现。battery_common*.c 是一个关键文件,其是充电控制的主线程,battery 设备也由此文件注册。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 # alps\kernel-3.18\drivers\misc\mediatek\include \mt-plat\charging.h CHARGING_CTRL_CMD CHARGER_TYPE BATTERY_VOLTAGE_ENUM CHR_CURRENT_ENUM # alps\kernel-3.18\drivers\misc\mediatek\include \mt-plat\battery_common.h # alps/kernel-3.18/drivers/power/mediatek/battery_common_fg_20.c power_supply_property xx upmu_is_chr_det() wireless/ac/usb_get_get_property() battery_update() bat_routine_thread() hrtimer_start() battery_init() # alps\kernel-3.18\drivers\misc\mediatek\include \mt-plat\battery_meter.h # alps/kernel-3.18/drivers/power/mediatek/battery_meter_fg_20.c SW FG的原理: a.PMIC adc来获取raw vbat电压。 b.通过ZCV表格,将vbat转换成OCV c.ocv-vbat/r 来获取电流I d.对电流i 进行积分,获取电量。 BMT_status.SOC = battery_meter_get_battery_percentage() gFG_capacity_by_c bmd_ctrl_cmd_from_user() memcpy (&gFG_capacity_by_c,...) nl_data_handler()->data = NLMSG_DATA(nlh) D0值:读取电池电压,将电池电压按对应电池的ZCV表查找对应的百分比,根据一定算法运算出的初始电量。 # alps\kernel-3.18\drivers\power\mediatek\linear_charging.c mtk_tuning_voltage() # alps\kernel-3.18\drivers\power\mediatek\switch_charging.c set_chr_input_current_limit() set_bat_sw_cv_charging_current_limit() ... charging_full_check() # alps\kernel-3.18\drivers\misc\mediatek\power\mt6797\pmic_chr_type_det.c
Fuel Gauge Control 和 Charging Control 框图如下:
客制化部分 不同于高通将电池曲线合入DTS,MTK是以头文件的形式合入电池曲线(好像也有DTS方式)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 # alps\kernel-3.18\drivers\misc\mediatek\include \mt-plat\mt6797\include \mach\mt_battery_meter_table.h BATTERY_PROFILE_STRUCT battery_profile_tx[] R_PROFILE_STRUCT r_profile_t1[] # alps\kernel-3.18\drivers\misc\mediatek\include \mt-plat\mt6797\include \mach\mt_battery_meter.h #define SOC_BY_HW_FG CUST_POWERON_DELTA_CAPACITY_TOLRANCE # alps\kernel-3.18\drivers\misc\mediatek\include \mt-plat\mt6797\include \mach\mt_charging.h
文件节点 电池状态、充电状态等文件节点的创建路径:
1 2 3 4 5 6 7 # alps\kernel-3.18\drivers\power\power_supply.h # alps\kernel-3.18\drivers\power\power_supply_core.c # alps\kernel-3.18\drivers\power\power_supply_sysfs.c power_supply_show_property() power_supply_attrs # alps\kernel-3.18\drivers\power\power_supply_leds.c
Healthd模块 Healtdh模块是一个单独的进程,这部分主要做两件事:1. 读取电池数据,上报(BatteryService.java); 2. 绘制关机图标。
Main函数 healthd.cpp是Healthd模块的入口,也就是Main函数,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 # alps\system\core\healthd\healthd.cpp 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, }; uevent_event () uevent_kernel_multicast_recv (uevent_fd, msg, UEVENT_MSG_LEN) healthd_battery_update () gBatteryMonitor->update () main () healthd_mode_ops = &android_ops/&charger_ops/&recovery_ops; healthd_init epoll_create (MAX_EPOLL_EVENTS) ; healthd_mode_ops->init (&healthd_config) uevent_init () wakealarm_init () new BatteryMonitor (); healthd_mainloop (); if (events[n].data.ptr) (*(void (*)(int ))events[n].data.ptr)(events[n].events); healthd_mode_ops->heartbeat ();
正常开机 正常开机时电池信息更新:
正常开机部分源码分析:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 # alps\system\core\healthd\BatteryPropertiesRegistrar.cpp BatteryPropertiesRegistrar::publish () BatteryPropertiesRegistrar::notifyListeners () BatteryPropertiesRegistrar::registerListener () healthd_battery_update (); BatteryPropertiesRegistrar::getProperty () # alps\system\core\healthd\healthd_mode_android.cpp healthd_mode_android_battery_update gBatteryPropertiesRegistrar->notifyListeners (*props) healthd_mode_android_init () ProcessState::self ()->setThreadPoolMaxThreadCount (0 ); IPCThreadState::self ()->disableBackgroundScheduling (true ); IPCThreadState::self ()->setupPolling (&gBinderFd); if (healthd_register_event (gBinderFd, binder_event)) gBatteryPropertiesRegistrar->publish (gBatteryPropertiesRegistrar); # alps\system\core\healthd\BatteryMonitor.cpp BatteryMonitor::update (void ) initBatteryProperties () path.appendFormat ("%s/%s/online" , POWER_SUPPLY_SYSFS_PATH, mChargerNames[i].string ()); ireadFromFile (path, buf, SIZE) ... healthd_board_battery_update (&props); healthd_mode_ops->battery_update (&props) BatteryMonitor::getXX BatteryMonitor::dumpState () BatteryMonitor::init ()
关机充电 关机充电部分主要就是更新电量、充电状态,更新UI。
1 2 3 4 5 6 7 8 9 10 11 dump_last_kmsg() // dump前记录最后一份log /*绘制关机充电图标*/ draw_xx() redraw_screen() healthd_mode_charger_heartbeat() // 获取最新电池状态,更新 handle_input_state(charger, now); handle_power_supply_state(charger, now); update_screen_state() // 更新屏幕显示 healthd_mode_charger_init() healthd_mode_charger_battery_update()
Framework层 Native层 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 # alps\frameworks\native\services\sensorservice\BatteryService.cpp # alps\frameworks\native\services\batteryservice\BatteryProperties.cpp BatteryProperties::readFromParcel () BatteryProperties::writeToParcel () # alps\frameworks\native\services\batteryservice\BatteryProperty.cpp BatteryProperty::readFromParcel () BatteryProperty::writeToParcel () # alps\frameworks\native\services\batteryservice\IBatteryPropertiesListener.cpp batteryPropertiesChanged ()# alps\frameworks\native\services\batteryservice\IBatteryPropertiesRegistrar.cpp
Framework部分 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 # alps\frameworks\base\services\core\java\com\android\server\BatteryService.java onStart () { IBinder b = ServiceManager.getService("batteryproperties" ); batteryPropertiesRegistrar.registerListener(new BatteryListener ()); publishBinderService("battery" , mBinderService); publishLocalService(BatteryManagerInternal.class, new LocalService ()); processValuesLocked shutdownIfNoPowerLocked () shutdownIfOverTempLocked() sendIntentLocked() class BatteryListener batteryPropertiesChanged atteryService.this .update(props) class Led # alps\frameworks\base\core\java\android\os\BatteryManager.java queryProperty () IBinder b = ServiceManager.getService("batteryproperties" ); mBatteryPropertiesRegistrar = IBatteryPropertiesRegistrar.Stub.asInterface(b); mBatteryPropertiesRegistrar.getProperty(id, prop) # alps\frameworks\base\services\core\java\com\android\server\am\BatteryStatsService.java # alps\frameworks\base\core\java\android\os\BatteryManagerInternal.java # alps\frameworks\base\core\java\android\os\BatteryProperties.aidl # alps\frameworks\base\core\java\android\os\BatteryProperties.java # alps\frameworks\base\core\java\android\os\BatteryProperty.aidl # alps\frameworks\base\core\java\android\os\BatteryProperty.java # alps\frameworks\base\core\java\android\os\BatteryStats.java # alps\frameworks\base\core\java\com\android\internal\os\BatteryStatsImpl.aidl # alps\frameworks\base\core\java\com\android\internal\os\BatteryStatsImpl.java
APP部分 系统UI处理电流的部分路径主要如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 # alps\frameworks\base\core\java\com\android\internal\os\BatterySipper.java # alps\frameworks\base\core\java\com\android\internal\os\BatteryStatsHelper.java # alps\frameworks\base\packages\SystemUI\src\com\android\systemui\BatteryMeterDrawable.java # alps\frameworks\base\packages\SystemUI\src\com\android\systemui\BatteryMeterView.java # alps\frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\policy\BatteryController.java # alps\frameworks\base\packages\SystemUI\src\com\android\systemui\power\PowerUI.java # alps\frameworks\base\packages\SystemUI\src\com\android\systemui\qs\tiles\BatteryTile.java
关机充电流程 关机充电也是在kernel里面充电,充电控制流程与开机是一致的,前面也分析到了。这里补充一个MTK软件流程图。如下:
总结 先留一个坑,等有时间了,再来绘制一个清晰易懂的流程框图。