关机充电的第一张logo:
/vendor/mediatek/proprietary/bootable/bootloader/lk/dev/logo/rules.mk
RESOURCE_OBJ_LIST += \
$(BOOT_LOGO_DIR)/$(1)/$(1)_uboot.raw \
$(BOOT_LOGO_DIR)/$(1)/$(1)_battery.raw \
$(BOOT_LOGO_DIR)/$(1)/$(1)_low_battery.raw \
$(BOOT_LOGO_DIR)/$(1)/$(1)_charger_ov.raw \
$(BOOT_LOGO_DIR)/$(1)/$(1)_num_0.raw \
$(BOOT_LOGO_DIR)/$(1)/$(1)_num_1.raw \
... ...
/vendor/mediatek/proprietary/bootable/bootloader/lk/lib/libshowlogo/cust_display.h
#define LOW_BATTERY_INDEX 2
/vendor/mediatek/proprietary/bootable/bootloader/lk/target/tb8321p3_bsp/include/target/board.h
//Project specific header file
#define CFG_DISPLAY_WIDTH (DISP_GetScreenWidth())
return primary_display_get_width();
if (pgc->plcm == NULL)
pgc->plcm = disp_lcm_probe(NULL, LCM_INTERFACE_NOTDEFINED);
if (pgc->plcm->params)
return pgc->plcm->params->width;
#define CFG_DISPLAY_HEIGHT (DISP_GetScreenHeight())
return primary_display_get_height();
if (pgc->plcm == NULL)
pgc->plcm = disp_lcm_probe(NULL, LCM_INTERFACE_NOTDEFINED);
if (pgc->plcm->params)
return pgc->plcm->params->height;
#define CFG_DISPLAY_BPP (DISP_GetScreenBpp())
/vendor/mediatek/proprietary/bootable/bootloader/lk/kernel/main.c
kmain //main.c
platform_early_init(); //lk/platform/mt6580/platform.c
thread_t *thread_bs2 = thread_create("bootstrap2", &bootstrap2, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
if (thread_bs2)
thread_resume(thread_bs2);
static int bootstrap2(void *arg) //lk/kernel/main.c
platform_init //lk/platform/mt6580/platform.c
mt65xx_bat_init(); //mt_battery.c
if (kernel_charging_boot() == 1) //如果是关机充电
//mt_disp_show_low_battery(); //公版是直接显示一张低电logo //mt_logo.c
init_fb_screen();
fill_animation_logo(LOW_BATTERY_INDEX, mt_get_fb_buf(), (void *)mt_get_tempfb_addr(), logo_addr, phical_screen);
mt_disp_update(0, 0, CFG_DISPLAY_WIDTH, CFG_DISPLAY_HEIGHT);
int boot_capacity = get_battery_capacity(); //我们可以改成下面这种根据不同capacity显示不同电量
mt_disp_show_battery_capacity(boot_capacity) //void mt_disp_show_battery_capacity(UINT32capacity) //lk/platform/mt6580/mt_logo.c
init_fb_screen();
fill_animation_battery_by_ver(capacity, mt_get_fb_buf(), (void *)mt_get_tempfb_addr(), logo_addr, phical_screen, show_animationm_ver); //lk/lib/libshowlogo/show_animation_common.c
switch (version)
case VERION_OLD_ANIMATION:
fill_animation_battery_old(capacity, fill_addr, dec_logo_addr, logo_addr, phical_screen);
case VERION_NEW_ANIMATION:
fill_animation_battery_new(capacity, fill_addr, dec_logo_addr, logo_addr, phical_screen); //lk/lib/libshowlogo/show_animation_common.c
case VERION_WIRELESS_CHARGING_ANIMATION:
fill_animation_battery_wireless_charging(capacity, fill_addr, dec_logo_addr, logo_addr, phical_screen);
mt_disp_update(0, 0, CFG_DISPLAY_WIDTH, CFG_DISPLAY_HEIGHT);
vendor\mediatek\proprietary\bootable\bootloader\lk\target\tb8167p5_64_bsp\include\target\cust_battery.h
/************Isaac add start***************/
typedef struct _BATTERY_PROFILE_STRUCT {
signed int percentage;
signed int voltage;
} BATTERY_PROFILE_STRUCT, *BATTERY_PROFILE_STRUCT_P;
BATTERY_PROFILE_STRUCT battery_profile_t2[] = {
{ 0 , 4182 },
{ 1 , 4170 },
{ 2 , 4159 },
... ...
{ 99 , 3576 },
{ 100 , 3516 },
};
// add by xuce for charging animation start Isaac
int get_battery_capacity()
{
int vol;
int t2_size;
BATTERY_PROFILE_STRUCT *temp = battery_profile_t2;
int capacity = 0;
int i;
#if defined(SWCHR_POWER_PATH)
vol = get_i_sense_volt(1);
#else
vol = get_bat_sense_volt(1);
#endif
if( vol > temp[0].voltage){
//printf("%s capacity = 100\n", __FUNCTION__);
return 100;
}else if( vol < BATTERY_LOWVOL_THRESOLD ){
return 0;
}else{
t2_size = sizeof(battery_profile_t2) / sizeof(BATTERY_PROFILE_STRUCT);
//printf("%s size=%d", __FUNCTION__, t2_size);
for(i=0; i<t2_size-1; i++){
//printf("%s voltage=%d voltage[i]=%d voltage[i+1]=%d \n", __FUNCTION__, vol, temp[i].voltage, temp[i+1].voltage);
if(vol >= temp[i+1].voltage && vol <= temp[i].voltage){
//printf("%s return capacity=%d\n", __FUNCTION__, temp[i].percentage);
capacity = 100 - temp[i].percentage;
if(capacity < 0){
capacity = 0;
}
}
}
}
return capacity;
}
// add by xuce for charging animation end
/*************Isaac add end**************/
=========================================================================
关机充电的动画阶段:
/vendor/mediatek/proprietary/external/libshowlogo/Android.mk
LOCAL_SRC_FILES := show_logo_common.c\
decompress_common.c\
show_animation_common.c\
charging_animation.cpp\
utils.cpp
LOCAL_MODULE := libshowlogo
/vendor/mediatek/proprietary/external/charger/kpoc_charger.rc
on charger
start kpoc_charger
service kpoc_charger /system/bin/kpoc_charger
class charger
group system wakelock
capabilities BLOCK_SUSPEND SYS_ADMIN SYS_BOOT
/vendor/mediatek/proprietary/external/charger/Android.mk
LOCAL_SRC_FILES:= \
common.cpp \
lights.cpp \
bootlogo.cpp \
main.cpp \
key_control.cpp \
charging_control.cpp
LOCAL_MODULE:= kpoc_charger
# Move to system partition for Android O migration
#LOCAL_PROPRIETARY_MODULE := true
#LOCAL_MODULE_OWNER := mtk
LOCAL_INIT_RC := kpoc_charger.rc
LOCAL_SHARED_LIBRARIES := \
libshowlogo \
android.hardware.health@2.0 \
... ...
/vendor/mediatek/proprietary/external/libshowlogo/cust_display.h
#define CHARGER_OV_INDEX 3
/* The option of new charging animation */
#define ANIMATION_NEW
/vendor/mediatek/proprietary/external/libshowlogo/show_animation_common.h
#define MAX_SUPPORT_ANIM_VER 2
#define VERION_OLD_ANIMATION 0
#define VERION_NEW_ANIMATION 1
#define VERION_WIRELESS_CHARGING_ANIMATION 2
// Use health HAL
#include <android/hardware/health/2.0/IHealth.h>
#include <healthhalutils/HealthHalUtils.h>
/vendor/mediatek/proprietary/external/charger/main.h
using ::android::binder::Status;
using ::android::hardware::light::BrightnessMode;
using ::android::hardware::light::FlashMode;
using ::android::hardware::light::HwLight;
using ::android::hardware::light::HwLightState;
using ::android::hardware::light::ILights;
using ::android::hardware::light::LightType;
using ::android::hardware::health::V2_0::get_health_service;
using ::android::hardware::health::V2_0::HealthInfo;
using ::android::hardware::health::V2_0::IHealth;
using ::android::hardware::health::V2_0::Result;
using ::android::sp;
/vendor/mediatek/proprietary/external/charger/main.cpp
int main(__attribute__((unused))int argc, __attribute__((unused))char *argv[])
set_draw_anim_mode(1); //void set_draw_anim_mode(int running_mode) //charger/bootlogo.cpp
if(running_mode == 1) {
draw_anim_mode = DRAW_ANIM_MODE_FB;
else
draw_anim_mode = DRAW_ANIM_MODE_SURFACE;
set_draw_mode(draw_anim_mode); //libshowlogo/charging_animation.cpp //void set_draw_mode(int draw_mode)
if ((draw_mode != (DRAW_ANIM_MODE_FB)) && (draw_mode != (DRAW_ANIM_MODE_SURFACE))) {
draw_anim_mode = DRAW_ANIM_MODE_SURFACE;
else
draw_anim_mode = draw_mode; //DRAW_ANIM_MODE_FB
bootlogo_init //charger/bootlogo.cpp
sync_anim_version();
#ifdef ANIMATION_NEW
set_anim_version(VERION_NEW_ANIMATION); //libshowlogo/charging_animation.cpp //void set_anim_version(int version)
show_animationm_ver = version;
#else
set_anim_version(VERION_OLD_ANIMATION);
KPOC_LOGI("[ChargingAnimation %s %d]not define ANIMATION_NEW:show old animation \n",__FUNCTION__,__LINE__);
#endif
anim_init() //libshowlogo/charging_animation.cpp
->init_charging_animation_ui_dimension(); //libshowlogo/show_animation_common.c
lcm_width = vinfo.xres; //假横屏电量百分比错位,需要修改这里调换xres和yres
lcm_height = vinfo.yres;
int rotation = getRotation();
->anim_logo_init();
->if (draw_anim_mode == (DRAW_ANIM_MODE_FB))
anim_fb_init(); //libshowlogo/charging_animation.cpp
if(ORIENTATION_270 == rotation){//270 //充电动画方向
phical_screen.rotation = 270;
} else if(ORIENTATION_90 == rotation){//90
phical_screen.rotation = 90;
} else if((ORIENTATION_180 == rotation) && (phical_screen.need180Adjust == 1)){//180
phical_screen.rotation = 180;
} else {
phical_screen.rotation = 0;
}
->else
anim_surface_init();
charging_control() //charger/charging_control.cpp
pthread_cond_t cond;
pthread_cond_init(&cond, NULL);
pthread_create(&uevent_thread, &attr, uevent_thread_routine, NULL);
pthread_create(&draw_thread, &attrd, draw_thread_routine, NULL);
do {
inDraw = 1; //表明正在画充电动画
bootlogo_show_charging(bc, 1); // @@@ draw fb again to refresh ddp //charger/bootlogo.cpp
if (get_battnotify_status()) //其实就是读取kernel创建的BatteryNotify节点
show_charger_ov_logo(); //libshowlogo/charging_animation.cpp
anim_show_logo(CHARGER_OV_INDEX);
return; //如果高温,这里直接return,不跑下面的show_battery_capacity
if (showLowBattLogo) //由external/charger/key_control.cpp key_thread_routine()线程里赋值
show_low_battery();
return;
show_battery_capacity(capacity); //libshowlogo/charging_animation.cpp //显示电量百分比、充电动画
int has_fast_charging = getValue("ro.vendor.mtk_pump_express_plus_support" , "0" );
if (draw_anim_mode == (DRAW_ANIM_MODE_FB)) {
if( has_fast_charging == 1) {
if (2 != show_animationm_ver && get_fast_charging_state()) {
fill_animation_battery_fast_charging(capacity, (void *)fb_addr, dec_logo_addr, logo_addr, phical_screen, draw_anim_mode);
} else {
fill_animation_battery_by_ver(capacity, (void *)fb_addr, dec_logo_addr, logo_addr, phical_screen, show_animationm_ver);
}
} else { /libshowlogo/show_animation_common.c
fill_animation_battery_by_ver(capacity, (void *)fb_addr, dec_logo_addr, logo_addr, phical_screen,show_animationm_ver);
switch (version)
case VERION_OLD_ANIMATION:
fill_animation_battery_old(capacity, fill_addr, dec_logo_addr, logo_addr, phical_screen);
case VERION_NEW_ANIMATION:
fill_animation_battery_new(capacity, fill_addr, dec_logo_addr, logo_addr, phical_screen); //最终显示电量百分比、充电动画的函数
case VERION_WIRELESS_CHARGING_ANIMATION:
fill_animation_battery_wireless_charging(capacity, fill_addr, dec_logo_addr, logo_addr, phical_screen);
}
}
inDraw = 0; //充电动画画图结束
pthread_cond_wait(&cond, &mutex);
} while(1);
key_control(pwrkeys, ARRAY_SIZE(pwrkeys)); //will loop inside //charger/key_control.cpp
static int longPressDuration = LONG_PRESS_DEFAULT_DURATION; //#define LONG_PRESS_DEFAULT_DURATION500 //设置powerKey超时时间为500ms
long_press_control();
->pthread_t pwrkey_thread;
->pthread_cond_init(&keycond, NULL);
->ret = pthread_create(&pwrkey_thread, &attr, key_thread_routine, NULL); //开了一个线程等待powerkey按下发来的等待队列keycond
pthread_cond_t keycond;
static bool bootingUp = false; //默认为false
while (!bootingUp) { //如果系统不是正在启动
{
pthread_cond_wait(&keycond, &mutex); //应该类似于等待队列
gettimeofday(&start, NULL); //start 为powerKey按下的启动时间
while(powerKeyPressed) //如果powerKey一直按着,那么powerKeyPressed就保持为true
{
usleep(1000*100); //200ms //每200ms检测一次按键时长是否达到要求
long_press = time_exceed(start, longPressDuration); //charger/common.cpp
struct timeval now;
gettimeofday(&now, NULL); //获取当前时间
if((now.tv_sec - start.tv_sec)*1000000 + now.tv_usec - start.tv_usec > duration_msec*1000) //判断now - start > longPressDuration ?
return true; //如果满足时长要求,则返回true
else
return false;
if(long_press)
{
KPOC_LOGI("pwr key reaches boot condition\n");
if(get_voltage() > VBAT_POWER_ON) //int VBAT_POWER_ON = VBAT_POWER_ON_DEFAULT; #define VBAT_POWER_ON_DEFAULT 3450000
{ // ready to boot up.
inotify_rm_watch(ufds[0].fd, wd);
if (keyDownPressed || keyUpPressed) //这两个变量默认为false,并没看到任何赋值,所以这里条件不成立
exit_charger(EXIT_REBOOT_UBOOT); //charger/main.cpp
reboot(RB_AUTOBOOT);
else
exit_charger(EXIT_POWER_UP); //正常来说,跑这里,机器重启,进入正常开机!
reboot(RB_POWER_OFF);
bootingUp = true;
}else {
showLowBattLogo = 1; //如果低电,那么会在线程draw_thread_routine()show一张log,猜测后面应该是关机了,然后检测到充电器存在,再次进入关机充电
KPOC_LOGI("VBAT <= %d\n", VBAT_POWER_ON);
}
}
}
}
if (!long_press) //如果powerKey是短按
showLowBattLogo = 0; //设置标志位,不显示低电logo,而是显示充电动画
if(!bootingUp) //如果机器机器是短按,或者长按但是低电
{
start_charging_anim(TRIGGER_ANIM_KEY); //显示充电动画 //charging_control.cpp
{
KPOC_LOGI("%s: inDraw:%d, reason:%d\n",__FUNCTION__, inDraw, reason);
trigger_anim();
if(inDraw) { //如果处于动画画图当中
key_trigger_suspend = 1;
return;}
if (!is_charging_source_available()) {
HealthInfo info = {};
get_health_info(&info); //获取hal层信息
usb_online = info.legacy.chargerUsbOnline;
ac_online = info.legacy.chargerAcOnline;
wireless_online = info.legacy.chargerWirelessOnline;
for (i = 0; i < ARRAY_SIZE(chg_volt_path); i++) { /* Find path for charger voltage */
vchr = get_int_value(chg_volt_path[i]);
return (usb_online || ac_online || wireless_online || vchr >= 2500);
KPOC_LOGI("no charging source, skip drawing anim\n");
return;
} //如果电池信息能获取到,那么继续往下跑
key_trigger_suspend = 0;
pthread_cond_signal(&cond); //唤醒draw_thread_routine线程
}
}
KPOC_LOGI("pwr key long press check end\n");
->if (ret != 0) //如果key_thread_routine线程创建失败,那么直接关机
KPOC_LOGI("create key pthread failed.\n");
exit_charger(EXIT_ERROR_SHUTDOWN);
while (1) { //判断powerKey是否按下
ufds = (struct pollfd*)calloc(1, sizeof(ufds[0])); //static struct pollfd *ufds;
pollres = poll(ufds, num_fds, -1);
if (ufds[0].revents & POLLIN) {
read_notify(INPUT_DEVICE_PATH, ufds[0].fd); //#define INPUT_DEVICE_PATH "/dev/input"
for (i = 1; i < num_fds; i++) {
... ...
if (EV_KEY == event.type) {
for (j = 0; j < pwrkeys_num; j++) {
if (event.code == pwrkeys[j]) {
if (1 == event.value) {
powerKeyPressed = true;
pthread_cond_signal(&keycond);
} else
powerKeyPressed = false;
break;
}
}
}
}
}
/vendor/mediatek/proprietary/external/charger/charging_control.cpp
static const char *chg_volt_path[] = {
"/sys/devices/platform/charger/ADC_Charger_Voltage",
"/sys/devices/platform/battery/ADC_Charger_Voltage",
};
/kernel-4.19-lc/drivers/power/supply/mediatek/battery_common.c
/* / */
/* // Create File For EM : ADC_Charger_Voltage */
/* / */
static ssize_t show_ADC_Charger_Voltage(struct device *dev, struct device_attribute *attr, char *buf)
{
battery_log(BAT_LOG_CRTI, "[EM] show_ADC_Charger_Voltage : %d\n", BMT_status.charger_vol);
return sprintf(buf, "%d\n", BMT_status.charger_vol);
}
static ssize_t store_ADC_Charger_Voltage(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
battery_log(BAT_LOG_CRTI, "[EM] Not Support Write Function\n");
return size;
}
static DEVICE_ATTR(ADC_Charger_Voltage, 0664, show_ADC_Charger_Voltage, store_ADC_Charger_Voltage);
/vendor/mediatek/proprietary/external/charger/common.cpp
int get_int_value(const char * path)
{
int size = 32;
char buf[size];
if(!read_from_file(path, buf, size))
return -1;
return atoi(buf);
}
static const char *bat_notify_path[] = {
"/sys/devices/platform/charger/BatteryNotify",
"/sys/devices/platform/mt-battery/BatteryNotify",
};
/*
* return value:
* 1: abnormal status
* 0: normal status
* If path is not found, return 0
*/
int get_battnotify_status()
{
int i = 0;
int bat_status = 0;
/* Find path for battery status */
for (i = 0; i < ARRAY_SIZE(bat_notify_path); i++) {
bat_status = get_int_value(bat_notify_path[i]);
if (bat_status != -1)
break;
}
KPOC_LOGI("charger battStatus=%d, idx=%d\n", bat_status, i);
if (bat_status > 0)
return 1;
return 0;
}