【转】android 电池(二):android关机充电流程、充电画面显示
关键词:android 电池关机充电 androidboot.mode charger关机充电 充电画面显示
平台信息:
内核:linux2.6/linux3.0
系统:android/android4.0
平台:S5PV310(samsungexynos 4210)
作者:xubin341719(欢迎转载,请注明作者)
欢迎指正错误,共同学习、共同进步!!
android 电池(二):android关机充电流程、充电画面显示
android电池(四):电池 电量计(MAX17040)驱动分析篇
android电池(五):电池 充电IC(PM2301)驱动分析篇
上一篇我们讲了锂电池的充放电的流程和电池的一些特性,这一节我们重点说一下android关机充电是怎么、充电画面显示是怎么实现的,这个在工作中也比较有用,我们开始做这一块的时候也走了不少的弯路。我记得我们做adnroid2.3的时候,关机状态和充电logo显示是在uboot中做的。应该是有两种做法,回头我再看下uboot中做画面显示那一块是怎么做的,这一节我们重点说系统中的充电logo显示。
一、android正常开机流程、关机充电流程
在写这篇文章之前我们先看两个流程:正常开机流程,关机充电系统启动流程
1、正常开机流程,按开机键。
可大致分成三部分
(1)、OS_level:UBOOT、kenrel、init这三步完成系统启动;
(2)、Android_level:这部分完成android部的初始化;
(3)、Home Screen:这部分就是我们看到的launcher部分。
2、关机充电系统启动流程
与前面相比,这个流程只走到init这一部分,就没有往后走了,这部分我们会在后面的代码中分析。
二、关机充电逻辑硬件逻辑
1、插入DC,charger IC从硬件上唤醒系统,相当于长按开机键开机。
下面这部分是charger IC连接系统的控制部分。
三、软件逻辑。
DC插入,其实相当于关机状态下“按开机键”开机。第一步要走UBOOT、kernel
、android init这一流程。
1、UBOOT
UBOOT启动代码我们不在这里详细分析,这里我们只要注意二个问题:
a:如何判断是DC插入;
b:设定setenv("bootargs", "androidboot.mode=charger"),androidboot.mode这个参数相当重要,这个参数决定系统是正常启动、还是关机充电状态。
Uboot/board/samsung/smdk4212/smkd4212.c
int board_late_init (void)
{
int keystate = ;
printf("check start mode\n");
if ((*(int *)0x10020800==0x19721212) || (*(int *)0x10020804==0x19721212)
|| (*(int *)0x10020808==0x19721212)) //(1)、检查是否有DC插入;
{
setenv ("bootargs", "");//(2)、没有DC插入;
} else {//DC插入
int tmp=*(int *)0x11000c08;
*(int *)0x10020800=*(int *)0x10020804=0x19721212;
*(int *)0x11000c08=(tmp&(~0xc000))|0xc000;
udelay();
if ((*(int *)0x11000c04 & 0x80)!=0x80 && INF_REG4_REG != 0xf) {
setenv ("bootargs", "androidboot.mode=charger");//(3)、设定bootargs为charger状态
printf("charger mode\n");
} else {
setenv ("bootargs", "");
}
*(int *)0x11000c08=tmp;
}
#ifdef CONFIG_CPU_EXYNOS4X12
int charge_status=CheckBatteryLow();//(4)、检查电池电量;
keystate=board_key_check();//(5)、检查按键状态;
// fuse bootloader
if(second_boot_info != ) {
boot_symbol=;
INF_REG2_REG =0x8;
run_command(CONFIG_BOOTCMD_FUSE_BOOTLOADER, NULL);
}
if((INF_REG4_REG == 0xd)) {
// reboot default
char buf[];
sprintf(buf, "%d", CONFIG_BOOTDELAY);
setenv ("bootdelay", buf);
setenv ("reserved", NULL);
saveenv();
} else if((INF_REG4_REG == 0xe) || keystate == (0x1 | 0x2)) {//(6)、按键进入fastboot模式;
// reboot bootloader
boot_symbol=;
INF_REG2_REG =0x8;
printf("BOOTLOADER - FASTBOOT\n");
setenv ("reserved", "fastboot");
setenv ("bootdelay", "");
} else if((INF_REG4_REG == 0xf) || keystate == (0x1 | 0x2 | 0x4)) {//(7)、按键进入recovery模式;
// reboot recovery
printf("BOOTLOADER - RECOVERY\n");
boot_symbol=;
INF_REG2_REG =0x8;
setenv ("reserved", CONFIG_BOOTCMD_RECOVERY);
setenv ("bootdelay", "");
} else
if(keystate == (0x1 | 0x4) || second_boot_info != || partition_check()) {//(8)、按键进入卡升级模式;
// 2nd boot
printf("BOOTLOADER - 2ND BOOT DEVICE\n");
boot_symbol=;
INF_REG2_REG =0x8;
setenv ("bootcmd", CONFIG_BOOTCOMMAND);
setenv ("reserved", CONFIG_BOOTCMD_FUSE_RELEASE);
setenv ("bootdelay", "");
} else {//(9)、正常启动;
// normal case
char buf[];
sprintf(buf, "%d", CONFIG_BOOTDELAY);
setenv ("bootdelay", buf);
}
INF_REG4_REG = ;
return ;
}
(1)、检查是否有DC插入;
if ((*(int *)0x10020800==0x19721212) || (*(int *)0x10020804==0x19721212)|| (*(int *)0x10020808==0x19721212))
这部分检查寄存器的值。
(2)、没有DC插入;
(3)、设定bootargs为charger状态
if ((*(int *)0x11000c04 & 0x80)!=0x80 && INF_REG4_REG != 0xf) {
setenv ("bootargs", "androidboot.mode=charger");
这是这部分的重点,如果能过寄存器判断是DC插入,把androidboot.mode设定为charger状态。
以下这部分根据需要加入,通过判断不同的情况进入不同的功能,如fastboot\revovery…………,这部分不做详细解释。
(4)、检查电池电量;
这个在正常开机状态下,如果检测电量太低,则不开机,这部分代码就不做分析。
(5)、检查按键状态;
我们这个平台有几种模式:fastboot\recovery\卡升级等……
(6)、按键进入fastboot模式;
(7)、按键进入recovery模式;
(8)、按键进入卡升级模式
(9)、正常启动;
2、kernel
这部分和正常启动是一样的。
3、init
前面所有的描述其实只有一点和正常启动不太一样,那就是在UBOOT中把androidboot.mode设定为charger状态,内核正常流程启动,然后到init时要对charger这种状态处理。
system\core\init\init.c
int main(int argc, char **argv)
{
………………
action_for_each_trigger("early-init", action_add_queue_tail); queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");
queue_builtin_action(property_init_action, "property_init");
queue_builtin_action(keychord_init_action, "keychord_init");
queue_builtin_action(console_init_action, "console_init"); //(1)、显示initlogo.rle,也就是android第二张图片;
queue_builtin_action(set_init_properties_action, "set_init_properties"); /* execute all the boot actions to get us started */
action_for_each_trigger("init", action_add_queue_tail); /* skip mounting filesystems in charger mode */
if (strcmp(bootmode, "charger") != ) {//(2)、这里就是UBOOT中设定的bootmode,如果是charger模式,跳过下面初始化;
action_for_each_trigger("early-fs", action_add_queue_tail);
action_for_each_trigger("fs", action_add_queue_tail);
action_for_each_trigger("post-fs", action_add_queue_tail);
action_for_each_trigger("post-fs-data", action_add_queue_tail);
} queue_builtin_action(property_service_init_action, "property_service_init");
queue_builtin_action(signal_init_action, "signal_init");
queue_builtin_action(check_startup_action, "check_startup"); if (!strcmp(bootmode, "charger")) {//(3)、如果为charger,则调用charger.c。
action_for_each_trigger("charger", action_add_queue_tail);
} else {
action_for_each_trigger("early-boot", action_add_queue_tail);
action_for_each_trigger("boot", action_add_queue_tail);
}
……………………
}
(1)、显示initlogo.rle,也就是android第二张图片;
queue_builtin_action(console_init_action,"console_init");调用console_init_action
static int console_init_action(int nargs, char **args)
{
int fd;
char tmp[PROP_VALUE_MAX];
if (console[]) {
snprintf(tmp, sizeof(tmp), "/dev/%s", console);
console_name = strdup(tmp);
}
fd = open(console_name, O_RDWR);
if (fd >= )
have_console = ;
close(fd);
if( load_565rle_image(INIT_IMAGE_FILE) ) {//这里定义rle文件的名称#define INIT_IMAGE_FILE "/initlogo.rle"
fd = open("/dev/tty0", O_WRONLY);
if (fd >= ) {//如果没有这张图片,就显示android字样,在屏幕左上角;
const char *msg;
msg = "\n"
"\n"
"\n" // console is 40 cols x 30 lines
"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
" A N D R O I D ";
write(fd, msg, strlen(msg));
close(fd);
}
}
return ;
}
(2)、这里就是UBOOT中设定的bootmode,如果是charger模式,跳过下面初始化;
/* skip mounting filesystems in charger mode */
if (strcmp(bootmode, "charger") != ) {
action_for_each_trigger("early-fs", action_add_queue_tail);
action_for_each_trigger("fs", action_add_queue_tail);
action_for_each_trigger("post-fs", action_add_queue_tail);
action_for_each_trigger("post-fs-data", action_add_queue_tail);
}
(3)、如果为charger,则调用charger.c
我们在后面细分charger这部分。
4、charger.c
这部分就是我们充电部分,充电画面显示的实现。
system\core\charger\charger.c
int main(int argc, char **argv)
{
………………
klog_set_level(CHARGER_KLOG_LEVEL);
dump_last_kmsg();
LOGI("--------------- STARTING CHARGER MODE ---------------\n"); gr_init();
gr_font_size(&char_width, &char_height); //(1)、初始化graphics,包括buf大小; ev_init(input_callback, charger);//(2)初始化按键; fd = uevent_open_socket(*, true);
if (fd >= ) {
fcntl(fd, F_SETFL, O_NONBLOCK);
ev_add_fd(fd, uevent_callback, charger);
} charger->uevent_fd = fd;
coldboot(charger, "/sys/class/power_supply", "add");//(3)、创建/sys/class/power_supply结点,把socket信息通知应用层; ret = res_create_surface("charger/battery_fail", &charger->surf_unknown);
if (ret < ) {
LOGE("Cannot load image\n");
charger->surf_unknown = NULL;
}
for (i = ; i < charger->batt_anim->num_frames; i++) {//(4)、这里是显示charger logo,res_create_surface显示图片函数;
struct frame *frame = &charger->batt_anim->frames[i];
ret = res_create_surface(frame->name, &frame->surface);
if (ret < ) {
LOGE("Cannot load image %s\n", frame->name);
/* TODO: free the already allocated surfaces... */
charger->batt_anim->num_frames = ;
charger->batt_anim->num_cycles = ;
break;
}
}
ev_sync_key_state(set_key_callback, charger);
gr_fb_blank(true); charger->next_screen_transition = now - ;
charger->next_key_check = -;
charger->next_pwr_check = -;
reset_animation(charger->batt_anim);
kick_animation(charger->batt_anim);
event_loop(charger);//(5)、event_loop循环,电池状态,检测按键是否按下;
return ; }
(1)、初始化graphics,包括buf大小
android/bootable/recovery/minui/graphics.c
gr_init():minui/graphics.c[settty0 to graphic mode, open fb0],设制tty0为图形模式,打开fb0;
int gr_init(void)
{
gglInit(&gr_context);
GGLContext *gl = gr_context;
gr_init_font();
gr_vt_fd = open("/dev/tty0", O_RDWR | O_SYNC);
if (gr_vt_fd < ) {
// This is non-fatal; post-Cupcake kernels don't have tty0.
perror("can't open /dev/tty0"); } else if (ioctl(gr_vt_fd, KDSETMODE, (void*) KD_GRAPHICS)) {
// However, if we do open tty0, we expect the ioctl to work.
perror("failed KDSETMODE to KD_GRAPHICS on tty0");
gr_exit();
return -;
}
gr_fb_fd = get_framebuffer(gr_framebuffer);
if (gr_fb_fd < ) {
gr_exit();
return -;
}
get_memory_surface(&gr_mem_surface);
fprintf(stderr, "framebuffer: fd %d (%d x %d)\n",
gr_fb_fd, gr_framebuffer[].width, gr_framebuffer[].height);
/* start with 0 as front (displayed) and 1 as back (drawing) */
gr_active_fb = ;
set_active_framebuffer();
gl->colorBuffer(gl, &gr_mem_surface);
gl->activeTexture(gl, );
gl->enable(gl, GGL_BLEND);
gl->blendFunc(gl, GGL_SRC_ALPHA, GGL_ONE_MINUS_SRC_ALPHA);
gr_fb_blank(true);
gr_fb_blank(false);
return ; }
(2)android/bootable/recovery/minui/events.c
ev_init():minui/events.c[open /dev/input/event*]打开 /dev/input/event*
这部分是在,充电状态下,按键操作的初始化,比如:短按显示充电logo,长按开机,初始化代码如下。
int ev_init(ev_callback input_cb, void *data)
{
DIR *dir;
struct dirent *de;
int fd;
dir = opendir("/dev/input");//打开驱动结点;
if(dir != ) {
while((de = readdir(dir))) {
unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)];
// fprintf(stderr,"/dev/input/%s\n", de->d_name);
if(strncmp(de->d_name,"event",)) continue;
fd = openat(dirfd(dir), de->d_name, O_RDONLY);
if(fd < ) continue;
/* read the evbits of the input device */
if (ioctl(fd, EVIOCGBIT(, sizeof(ev_bits)), ev_bits) < ) {
close(fd);
continue;
}
/* TODO: add ability to specify event masks. For now, just assume
* that only EV_KEY and EV_REL event types are ever needed. */
if (!test_bit(EV_KEY, ev_bits) && !test_bit(EV_REL, ev_bits)) {
close(fd);
continue;
}
ev_fds[ev_count].fd = fd;
ev_fds[ev_count].events = POLLIN;
ev_fdinfo[ev_count].cb = input_cb;
ev_fdinfo[ev_count].data = data;
ev_count++;
ev_dev_count++;
if(ev_dev_count == MAX_DEVICES) break;
}
}
return ;
}
(3)、创建/sys/class/power_supply结点,把socket信息通知应用层
uevent_open_socket这个函数是通过kobject_uevent的方式通知的应用层,就是往一个socket广播一个消息,只需要在应用层打开socket监听NETLINK_KOBJECT_UEVENT组的消息,就可以收到了,主要是创建了socket接口获得uevent的文件描述符,然后触发/sys/class/power_supply目录及其子目录下的uevent,然后接受并创建设备节点,至此设备节点才算创建。
(4)、这里显示charger logo,res_create_surface显示图片函数;
res_create_surface:minui/resource.c[create surfaces for all bitmaps used later, include icons, bmps]
创建surface为所以的位图,包括图标、位图。 这些图片的位置为:system\core\charger\images
(5)、event_loop循环,电池状态,检测按键是否按下;
5、event_loop
这个函数判断按键状态,DC是否插拔。如果长按开机:执行android_reboot(ANDROID_RB_RESTART,0, 0);如果拔出DC:执行android_reboot(ANDROID_RB_POWEROFF,0, 0);
static void event_loop(struct charger *charger)
{
int ret;
while (true) {
int64_t now = curr_time_ms();//(1)、获得当前时间;
LOGV("[%lld] event_loop()\n", now);
handle_input_state(charger, now);//(2)、检查按键状态;
handle_power_supply_state(charger, now);// (3)、检查DC是否拔出;
/* do screen update last in case any of the above want to start
* screen transitions (animations, etc)
*/
update_screen_state(charger, now);//(4)、对按键时间状态标志位的判断,显示不同电量的充电logo;
wait_next_event(charger, now);
}
}
(1)、获得当前时间;
int64_t now = curr_time_ms();
这个时间来判断,有没有屏幕超时,如果超时关闭屏幕充电logo显示。
(2)、检查按键状态;
static void handle_input_state(struct charger *charger, int64_t now)
{
process_key(charger, KEY_POWER, now);
if (charger->next_key_check != - && now > charger->next_key_check)
charger->next_key_check = -;
}
我们再看下:process_key(charger, KEY_POWER, now);
static void process_key(struct charger *charger, int code, int64_t now)
{
………………
if (code == KEY_POWER) {
if (key->down) {
int64_t reboot_timeout = key->timestamp + POWER_ON_KEY_TIME;
if (now >= reboot_timeout) {//如果长按power键,就重新启动,也就是重启开机;
LOGI("[%lld] rebooting\n", now);
android_reboot(ANDROID_RB_RESTART, , );//重启命令;
}
………………
} key->pending = false;
}
(3)、检查DC是否拔出;
handle_power_supply_state(charger, now);
static void handle_power_supply_state(struct charger *charger, int64_t now)
{
if (charger->num_supplies_online == ) {
if (charger->next_pwr_check == -) {
charger->next_pwr_check = now + UNPLUGGED_SHUTDOWN_TIME;
LOGI("[%lld] device unplugged: shutting down in %lld (@ %lld)\n",
now, UNPLUGGED_SHUTDOWN_TIME, charger->next_pwr_check);
} else if (now >= charger->next_pwr_check) {
LOGI("[%lld] shutting down\n", now);
android_reboot(ANDROID_RB_POWEROFF, , );//如果DC拔出,则关机;
}
………………
}
(4)、对按键时间状态标志位的判断,显示不同电量的充电logo;
update_screen_state(charger, now);
这个函数比较长了,其实做用就是:我们在状态的过程中,充电logo的电量是要增加的,比如电量是20%时,要从第一格开始闪烁;如果是80%时,则要从第三格开始闪烁,电量显示就是通过这个函数来计算实现的。
下面是不能容量时显示logo的函数:
【转】android 电池(二):android关机充电流程、充电画面显示的更多相关文章
- Android入门(二):Android工程目录结构
首先我们来看看Android工程的目录结构,如下图: 下面我们来看看每个文件夹都是用来做什么的? 1.src:这个不用多说,它就是保存Java源文件的目录: 2.gen:该文件夹用来保存自动生成的R. ...
- android 电池(二):android关机充电流程、充电画面显示【转】
本文转载自:http://blog.csdn.net/xubin341719/article/details/8498580 上一篇我们讲了锂电池的充放电的流程和电池的一些特性,这一节我们重点说一下a ...
- Android 电池关机充电
android 电池(一):锂电池基本原理篇 android 电池(二):android关机充电流程.充电画面显示 android 电池(三):android电池系统 android电池(四):电池 ...
- Android Framework层Power键关机流程(二,关机流程)
二,关机流程 从前一篇博文我们知道,当用户长按Power键时会弹出(关机.重启,飞行模式等选项)对话框,我们点击关机,则会弹出关机确认对话框.那么从选项对话框到关机确认对话框又是一个什么流程呢.下面我 ...
- 【转】android电池(五):电池 充电IC(PM2301)驱动分析篇
关键词:android 电池 电量计 PL2301任务初始化宏 power_supply 中断线程化 平台信息:内核:linux2.6/linux3.0系统:android/android4.0 ...
- Android实训案例(二)——Android下的CMD命令之关机重启以及重启recovery
Android实训案例(二)--Android下的CMD命令之关机重启以及重启recovery Android刚兴起的时候,着实让一些小众软件火了一把,切水果,Tom猫,吹裙子就是其中的代表,当然还有 ...
- 【转】android电池(四):电池 电量计(MAX17040)驱动分析篇
关键词:android 电池 电量计 MAX17040 任务初始化宏 power_supply 平台信息:内核:linux2.6/linux3.0系统:android/android4.0 平台: ...
- 【转】android 电池(三):android电池系统
关键词:android电池系统电池系统架构 uevent power_supply驱动 平台信息: 内核:linux2.6/linux3.0系统:android/android4.0 平台:S5PV3 ...
- 【转】android 电池(一):锂电池基本原理篇
关键词:android 电池关机充电 androidboot.mode charger 平台信息:内核:linux2.6/linux3.0系统:android/android4.0 平台:S5PV3 ...
随机推荐
- yum笔记
rpm --> yum HTML: HyperText Mark LanguageXML: eXtended Mark Language XML, JSON: 半结构化的数据 yum仓库中的元数 ...
- [转载]Linux网络编程IPv4和IPv6的inet_addr、inet_aton、inet_pton等函数小结
转载:http://blog.csdn.net/ithomer/article/details/6100734 知识背景: 210.25.132.181属于IP地址的ASCII表示法,也就是字符串形式 ...
- 程序员求职之道(《程序员面试笔试宝典》)之看着别人手拿大把的offer,不淡定了怎么办?
不管是在哪里,不管发生什么事,不要随便放下自己. --<当男人恋爱时> 很多求职者都会面临一个问题:别人手拿大把大把的offer了,而自己却是两手空空,别人签约之后已经过着"猪狗 ...
- nyoj 36 最长公共子序列
描述 咱们就不拐弯抹角了,如题,需要你做的就是写一个程序,得出最长公共子序列. tip:最长公共子序列也称作最长公共子串(不要求连续),英文缩写为LCS(Longest Common Subseque ...
- hdu 5288 OO’s Sequence(计数)
Problem Description OO has got a array A of size n ,defined a function f(l,r) represent the number o ...
- Codeforces 549F Yura and Developers
probelm 题意 给定一个序列和一个mod值,定义[l,r]合法当l到r的全部元素和减去当中的最大值的结果能够整除mod.问共同拥有多少区间合法. 思路 一開始想的分治. 对于一个[l,r]我们能 ...
- 第04章-VTK基础(4)
[译者:这个系列教程是以Kitware公司出版的<VTK User's Guide -11th edition>一书作的中文翻译(出版时间2010年,ISBN: 978-1-930934- ...
- NET中级课--浅谈委托,事件,异步调用,回调等概念
直接说题. 委托 首先明确它是什么,其实就是一个类,定义一个委托即定义一个类,那么它是什么类?用来说明方法的类型的类.字段有类型,那么方法其实也有类型,就是委托. 委托是某 ...
- Js 实现 C# Format方法
参考网友的, 挺好用的: String.prototype.format = function (args) { if (arguments.length > 0) { var result = ...
- Html5移动端页面布局通用模板暨移动端问题总结
最近的移动端项目终于告一段落了,其中遇到了不少问题,在此和大家总结分享. 首先,说一下结构.一般的手机页面大致可以分为五块:head, content, foot,solidbar,dialog. 针 ...