Android从上层到底层完整流程.docx
《Android从上层到底层完整流程.docx》由会员分享,可在线阅读,更多相关《Android从上层到底层完整流程.docx(8页珍藏版)》请在冰豆网上搜索。
Android从上层到底层完整流程
Android上层界面到内核代码的完整的流程分析,以alarm为例子
很久之前写的一个流程文档,从上层界面一直调用到内核的过程,最近同事跟我要,我看了下又在整理了下,纯属个人分析(不过都运行验证过),不对的请大牛指出。
Alarm调用流程,alarm的流程实现了从上层应用一直到下面driver的调用流程,下面简单阐述:
涉及代码;
./packages/apps/DeskClock/src//android/deskclock/Alarms.java
./frameworks/base/core/java/android/app/AlarmManager.java
./frameworks/base/services/java//android/server/AlarmManagerService.java
./frameworks/base/services/jni/_android_server_AlarmManagerService.cpp
./kernel/kernel/drivers/rtc/alarm-dev.c
./kernel/kernel/include/linux/android_alarm.h
./kernel/kernel/drivers/rtc/alarm.c
./kernel/kernel/drivers/rtc/interface.c
./kernel/kernel/drivers/rtc/rtc-pcf8563.c
/packages/apps/DeskClock/src//android/deskclock/AlarmReceiver.java
./kernel/arch/arm/configs/mmp2_android_defconfig
./kernel/kernel/kernel/.config 点击Clock应用程序,然后设置新闹钟,会调到Alarms.java里面的
publicstaticlongsetAlarm(Contextcontext,Alarmalarm){
....setNextAlert(context);
....
}然后这里面也会调用到
publicstaticvoidsetNextAlert(finalContextcontext){
if(!
enableSnoozeAlert(context)){
Alarmalarm=calculateNextAlert(context);//new一个新的alarm
if(alarm!
=null){
enableAlert(context,alarm,alarm.time);
}else{
disableAlert(context);
}
}
}然后继续调用到
privatestaticvoidenableAlert(Contextcontext,finalAlarmalarm,finallongatTimeInMillis){
.......
am.set(AlarmManager.RTC_WAKEUP,atTimeInMillis,sender);//这里是RTC_WAKEUP,这就保证了即使系统睡眠了,都能唤醒,闹钟工作(android平台关机闹钟好像不行)
.....
}然后就调用到了AlarmManager.java里面方法
publicvoidset(inttype,longtriggerAtTime,PendingIntentoperation){
try{
mService.set(type,triggerAtTime,operation);
}catch(RemoteExceptionex){
}
}然后就调用到了AlarmManagerService.java 里面方法
publicvoidset(inttype,longtriggerAtTime,PendingIntentoperation){
setRepeating(type,triggerAtTime,0,operation);
}然后继续调用
publicvoidsetRepeating(inttype,longtriggerAtTime,longinterval,
PendingIntentoperation)
{
.....
synchronized(mLock){
Alarmalarm=newAlarm();
alarm.type=type;
alarm.when=triggerAtTime;
alarm.repeatInterval=interval;
alarm.operation=operation;
//Removethisalarmifalreadyscheduled.
removeLocked(operation);
if(localLOGV)Slog.v(TAG,"set:
"+alarm);
intindex=addAlarmLocked(alarm);
if(index==0)
{
setLocked(alarm);
}
}
}然后就调用到
privatevoidsetLocked(Alarmalarm){
......//mDescriptor这里的文件是/dev/alarm set(mDescriptor,alarm.type,alarmSeconds,alarmNanoseconds);
.....
}这里就调用到jni了
privatenativevoidset(intfd,inttype,longseconds,longnanoseconds);这就调用到了_android_server_AlarmManagerService.cpp里面
staticJNINativeMethodsMethods[]={
/*name,signature,funcPtr*/
{"init","()I",(void*)android_server_AlarmManagerService_init},
{"close","(I)V",(void*)android_server_AlarmManagerService_close},
{"set","(IIJJ)V",(void*)android_server_AlarmManagerService_set},
{"waitForAlarm","(I)I",(void*)android_server_AlarmManagerService_waitForAlarm},
{"setKernelTimezone","(II)I",(void*)android_server_AlarmManagerService_setKernelTimezone},
};
set对应的是android_server_AlarmManagerService_set,具体是
staticvoidandroid_server_AlarmManagerService_set(JNIEnv*env,jobjectobj,jintfd,jinttype,jlongseconds,jlongnanoseconds)
{
#ifHAVE_ANDROID_OS
structtimespects;
ts.tv_sec=seconds;
ts.tv_nsec=nanoseconds;
intresult=ioctl(fd,ANDROID_ALARM_SET(type),&ts);
if(result<0)
{
LOGE("Unabletosetalarmto%lld.%09lld:
%s\n",seconds,nanoseconds,strerror(errno));
}
#endif
}然后ioctl就调用到了alarm-dev.c
staticlongalarm_ioctl(structfile*file,unsignedintcmd,unsignedlongarg)
{
....
caseANDROID_ALARM_SET(0):
if(copy_from_user(&new_alarm_time,(void__user*)arg,sizeof(new_alarm_time))){ rv=-EFAULT;
gotoerr1;
}
from_old_alarm_set:
spin_lock_irqsave(&alarm_slock,flags);
pr_alarm(IO,"alarm%dset%ld.%09ld\n",alarm_type,
new_alarm_time.tv_sec,new_alarm_time.tv_nsec);
alarm_enabled|=alarm_type_mask;
alarm_start_range(&alarms[alarm_type],
timespec_to_ktime(new_alarm_time),
timespec_to_ktime(new_alarm_time));
spin_unlock_irqrestore(&alarm_slock,flags);
if(ANDROID_ALARM_BASE_CMD(cmd)!
=ANDROID_ALARM_SET_AND_WAIT(0)&&cmd!
=ANDROID_ALARM_SET_AND_WAIT_OLD) break;
/*fallthough*/
....
caseANDROID_ALARM_SET_RTC:
if(copy_from_user(&new_rtc_time,(void__user*)arg,
sizeof(new_rtc_time))){
rv=-EFAULT;
gotoerr1;
}
rv=alarm_set_rtc(new_rtc_time);
spin_lock_irqsave(&alarm_slock,flags);
alarm_pending|=ANDROID_ALARM_TIME_CHANGE_MASK;
wake_up(&alarm_wait_queue);
spin_unlock_irqrestore(&alarm_slock,flags);
if(rv<0)
gotoerr1;
break;
....
}然后这边就调用到了alarm_start_range设置闹钟,alarm_set_rtc设置RTC这两个函数在android_alarm.h声明,在alarm.c里实现。
这是android_alarm.h里面的声明
voidalarm_start_range(structalarm*alarm,ktime_tstart,ktime_tend);
intalarm_try_to_cancel(structalarm*alarm);
intalarm_cancel(structalarm*alarm);
ktime_talarm_get_elapsed_realtime(void);/*setrtcwhilepreservingelapsedrealtime*/
intalarm_set_rtc(conststructtimespects);下面看alarm.c里面实现:
intalarm_set_rtc(structtimespecnew_time)
{
....
ret=rtc_set_time(alarm_rtc_dev,&rtc_new_rtc_time);
....
}
alarm.c 里面实现了alarm_suspend alarm_resume函数,就是如果系统没有suspend的时候,设置闹钟并不会往rtc芯片的寄存器上写数据,因为不需要唤醒系统,所以闹钟数据时间什么的就通过上层写到设备文件/dev/alarm,里面就可以了,AlarmThread会不停的去轮寻下一个时间有没有闹钟,直接从设备文件/dev/alarm里面读取。
第二种,系统要是进入susupend的话,alarm的alarm_suspend就会写到下层的rtc芯片的寄存器上去,然后即使系统suspend之后,闹钟通过rtc也能唤醒系统,这里就调用到了interface.c里面 //这里面intrtc_set_alarm(structrtc_device*rtc,structrtc_wkalrm*alarm)差不多也是跟下面一样
intrtc_set_time(structrtc_device*rtc,structrtc_time*tm)
{
....
err=rtc->ops->set_time(rtc->dev.parent,tm);
....
}然后set_time就看到具体的是那个RTC芯片,这边我们是rtc-pcf8563.c
staticconststructrtc_class_opspcf8563_rtc_ops={
.read_time =pcf8563_rtc_read_time,
.set_time =pcf8563_rtc_set_time,
.read_alarm =pcf8563_rtc_read_alarm,
.set_alarm =pcf8563_rtc_set_alarm,
};然后就到了
staticintpcf8563_rtc_set_time(structdevice*dev,structrtc_time*tm)
{
unsignedcharbuf[TIME_NUM];
intret;
ret=data_calc(buf,tm,TIME_NUM);
if(ret<0)
gotoout;
ret=i2c_smbus_write_i2c_block_data(pcf8563_info->client,PCF8563_RTC_SEC,TIME_NUM,buf); //这边就调用i2c统一接口,往pcf8563rtc芯片寄存器里面写出数据
out:
returnret;
}到此,闹钟时间就已经写到rtc芯片的寄存器里面,第二个参数就是寄存器的名字,后面的buf就是要写入的时间,rtc芯片是额外供电的,所以系统suspend之后,系统kernel都关了,但是rtc里面还有电,寄存器里面数据还是有的(掉电就会丢失数据),所以闹钟到了,通过硬件中断机制就可以唤醒系统。
上面那个rtc下面有几十个rtc芯片驱动代码,没有结构基本一样,都有基本操作函数,注册函数,都是对各自芯片上特有的寄存器操作,为什么调用的是pcf8563rtc呢?
这个要看你系统用的是那个芯片,这个可以通过./kernel/kernel/kernel/.config 查看,这边的pcf8563rtc是当前系统正在使用的芯片型号
#CONFIG_RTC_DRV_ISL1208isnotset
#CONFIG_RTC_DRV_X1205isnotset
CONFIG_RTC_DRV_PCF8563=y
#CONFIG_RTC_DRV_PCF8583isnotset
#CONFIG_RTC_DRV_M41T80isnotset下面是系统唤醒之后,闹钟怎么工作的流程,简单阐述系统没有suspend的话直接走下面流程,如果suspend的话会被RTC唤醒,然后还是走下面的流程
privateclassAlarmThreadextendsThread
{
publicAlarmThread()
{
super("AlarmManager");
}
publicvoidrun()
{
while(true)
{
intresult=waitForAlarm(mDescriptor);//这里调用jni调用staticjintandroid_server_AlarmManagerService_waitForAlarm,主要还是对/dev/alarm 操作
....
Alarmalarm=it.next();
try{
if(localLOGV)Slog.v(TAG,"sendingalarm"+alarm);
alarm.operation.send(mContext,0, mBackgroundIntent.putExtra(
Intent.EXTRA_ALARM_COUNT,alarm.count),
mResultReceiver,mHandler);
....
}
}
}
staticjintandroid_server_AlarmManagerService_waitForAlarm(JNIEnv*env,jobjectobj,jintfd)
{
#ifHAVE_ANDROID_OS
intresult=0;
do
{
result=ioctl(fd,ANDROID_ALARM_WAIT);
}while(result<0&&errno==EINTR);
if(result<0)
{
LOGE("Unabletowaitonalarm:
%s\n",strerror(errno));
return0;
}
returnresult;
#endif
}
AlarmManagerService 里面有个AlarmThread会一直轮询/dev/alarm文件,如果打开失败就直接返回,成功就会做一些动作,比如查找时间最近的alarm,比如睡眠被闹钟唤醒的时候,这边就发一个intent出去,然后在AlarmReceiver.java里面弹出里面会收到就会调用下面的
context.startActivity(alarmAlert);然后弹出alarm 这个界面
Classc=AlarmAlert.class;其中publicclassAlarmAlertextendsAlarmAlertFullScreen 所以系统睡眠之后被alarm唤醒弹出的alarm就是这边start的
publicclassAlarmReceiverextendsBroadcastReceiver{
/**IfthealarmisolderthanSTALE_WINDOW,ignore. It
isprobablytheresultofatimeortimezonechange*/ privatefinalstaticintSTALE_WINDOW=30*60*1000;
Override
publicvoidonReceive(Contextcontext,Intentintent){
.........
IntentalarmAlert=newIntent(context,c);
alarmAlert.putExtra(Alarms.ALARM_INTENT_EXTRA,alarm);
alarmAlert.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
|Intent.FLAG_ACTIVITY_NO_USER_ACTION);
context.startActivity(alarmAlert);
........
}到这里alarm就显示出来了我个人添加的log,验证了流程,suspend和不suspend的时候alarm的区别跟上面说的一样