转自: http://blog.csdn.net/muxiang1988/article/details/6231923
摘要:
本文试图通过代码来深入剖析Qualcomm手机开机的整个过程,即从按下开机键一直到出现待机界面,Qualcomm的手机软件在整个流程中究竟完成了哪些工作。本文的主要目标是理清手机的初始化流程,并为今后Amoi定做初始化工作提供一个参考。
关键字:开机、Rex、TMC、ui_task、CoreApp
一、开机的简要流程分析
Qualcomm的平台软件支持两种启动方式:一种是Nor Flash启动方式,另外一种就是Nand Flash启动方式。Nor Flash启动方式就相当于硬件直接找到一个入口点开始执行代码,相比较而言会比较简单,且Amoi没有采用此种方式,所以本文对于这种方式不做详细分析。另外一种就是Nand Flash启动方式,这种方式和PC的启动方式比较相像,也是Amoi采用的Boot方式,下面将详细分析在此方式下面的开机过程。
按下开机键之后,将产生一个时钟中断,从而通知AMSS主芯片的Boot Load硬件去将放置于Nand Flash上面的第一个Block(8K)里面的Boot代码Copy到内核内存(RAM,这个内存应该是CPU自带的内存,同后面提到的SDRAM有一定区别,可以把它当作CPU的Cache)的0xFFFF0000地址,并开始执行Boot代码。Boot的主要任务是完成整个系统的硬件初始化工作(类似于PC上面的BIOS所完成的硬件自检工作,至于Boot的详细工作机制,后文会有详细描述)。Boot所完成的工作里面,最重要的一件事就是会将整个手机软件代码(AMSS软件包)拷贝到SDRAM中,并最后将控制权交给AMSS软件。说白了,就是Boot执行完成之后,代码的执行点将由Boot跳转到AMSS软件的的入口点函数main().(此函数在mobile.c里实现)。
代码运行到了Main()之后,在这个函数里面将完成操作系统(rex)的初始化工作,其实现方法是调用 rex_init()。Rex_init()完成的工作很简单:
1.完成操作系统必要的一些数据结构(timer链表、任务链表等))的初始化之外;
2.接下来,它创建了三个任务,分别是:rex_idle_task、rex_dpc_task和tmc_task。
Idle任务没什么好解释的,目前这个任务为空,什么也没做,dpc_task目前不知道是做什么的,暂时可以不用管。前面的这两个任务都属于操作系统层面的,由操作系统来维护,和手机软件关系不大。哪一个和手机软件关系大呢?答案是:tmc_task。大家可以把这个当作操作系统的入口(主)任务,也可以把它当作整个手机软件的入口任务。即AMSS软件里的所有其它任务的创建和维护就是由这个tmc_task来完成的。
到此为止,整个AMSS软件还并没有跑起来,只是跑到了tmc_task里面了。在tmc_task里面,会调用tmc_init()来完成整个AMSS软件包的初始化工作,其中最重要的一项工作就是调用tmc_define_tasks()将AMSS软件包所有需要的任务都创建起来了。比如说slee_task、dog_task、cm_task、wms_task、ui_task等。这些任务,一般不需要直接和AL层软件打交道,但请大家记住,手机上所有功能的实现最根本点就是由这些服务组件(Service Task)来完成的。将来大家跟踪一个具体的功能模块时,比如说通话模块,如果需要,可以再去深入研究它的具体实现。
好了,到现在为止,所有的AMSS核心软件就全部跑起来了(手机的功能模块,在软件方面就体现为OS层面的一个任务)。但现在大家还根本看不到Brew和AEE的影子。呵呵,各位不要急。到了这个层面之后,我想稍微多说几句。最早的Qualcomm平台,比如说5xxx系列,是根本没有Brew的,那个时候的AL(Application Layer)层软件开发,是直接调用底层Service task所提供的API来完成相应的工作的。从这种角度来看的话,显然那时的开发是比较郁闷和难度较高的。不过,到了65xx之后,Qualcomm平台引入了Brew,手机开发商就没必要去从这么底层(Service API)的层面进行手机开发了,他们完全可以基于Brew来实现一台手机的所有功能(Qualcomm给我们的参考代码,就是全Brew平台的)。
Brew的运行环境AEE是如何跑起来的呢?关键在于ui_task(),由于ui_task和我们手机开发的关系非常密切,其地位也相当重要,所以,后文我将单独对它进行一个深入的研究与分析。到目前为止,大家只需要知道ui_task将AEE加载起来了,并且,它起到了一个中间层的作用,即所有AMSS底层服务组件的消息,都将经由ui_task而转到AEE,并最终转到具体的App(Applet)的执行代码里面(HandleEvent())。
注意:
1.上述的开机过程,在每一次按开机键都需要走一遍,即关机之后,整个系统的所有功能都将消失,而不像有些手机,看起来是关了机,但实际上底层还是有一些软件模块在跑。为什么可以肯定地说上述开机过程每次都必须走一遍,原因很简单,因为我们的平台软件是基于Nand Flash启动的,所有的代码都需要Copy到SDRAM才能运行,而关机断电之后,SDRAM里的东东会全部丢失,所以,毫无疑问,上述的过程必须每次开机都执行;
2.关机的过程相对比较简单,系统检测到关机中断之后,将调用tmc_powerdown_handler()来完成关机动作,它将把所有AMSS的任务都Stop掉,并最后调用rex_exit()退出Rex,从而完成整个关机动作。
3.显然,关机动作前,如果有必要,每一个任务必须将它希望保存的信息保存到Flash上面,以便下次开机时可以得到这些信息;
开机流程简图
说明:
1.Tmc是操作系统层面和AMSS软件关系最密切的一个任务,不过需要OEM商在此处修改的地方应该不多;
2.ui_task是在操作系统层面,OEM商需要重点研究清楚的一个任务,它是连接底层Task和上层AL的一个中间层,有可能需要加入OEM商的操作流程;
3.CoreApp是在Brew层面的一个AL层的入口Applet,它其着管理整个上层AL层软件的作用,根据产品需求,这个App需要定做;
4.AEE是整个上层App的运行环境,目前Qualcomm没有公开它的源码,但它的运行机制,Amoi需要好好研究清楚,我将在另外一篇《Qualcomm平台AEE运行机制深入分析与研究》中探讨它的运行机理和调度机制,大家有兴趣可以参考此文;
二、Boot代码深入分析
Boot代码大部分是用汇编语言写的,也有小部分,可能需要由OEM商修改,所以用C语言来写。另外,Boot代码属于Driver范围,所以大家可以在drivers/boot目录里面找到相应的代码。Boot的代码组织得非常模块化,整个boot的入口点是在Boot_function_table.s里面,这个汇编代码里面实际上是将Boot需要完成的任务封装成了不同的函数,由不同的函数来完成相应的工作,接下来,我将深入分析这些函数所完成的工作,如下所述。
a)mmu_enable_instruction_cache;
这个只有在Nand启动模式时才需要,打开ARM的指令Cache.
b)boot_hw_ctrl_init
此函数主要是完成两条总线(EBI1、EBI2)控制器的初始化,这个函数执行完了之后,系统就可以知道两条总线上连接了哪些设备,同时也可以找得到这些设备,不过,至于单个设备自身的初始化,则不在这里。
[注]
这个函数很重要,OEM商如果需要加新的设备到系统中(挂在两条总线上),则需要定做此模块,目前阶段主要是内存。另外,如前文所述,这个函数是由C语言来写的,主要目的就是为了方便OEM商定做。内存设备的修改,可以在这个模块里找到相应的数据结构,相对还是比较简单的。
c)boot_hw_tlmm_init
1.晶振时钟的初始化;
2.中断表的初始化;
3.GPIO的初始化;
4.Msm本身的驱动,除了EBI2;
d)boot_rom_test
这个函数非常简单,只是做一个很简单的Rom检查.(比对两个标志位来检查,并没有一块一块地去检查)。
e)boot_ram_test
Ram自检,具体算法其实也很简单,就是读、写内存以判断是否成功。
f)boot_ram_init
1.拷贝手机代码从Nand Flash到SDRAM。
a.Image__BB_RAM__Base:Core Code;
b.Image__APP_RAM__Base:App Code;
[注]
上述动作是分块进行的,原因是因为Qualcomm支持分块Boot Load.
2.将Image__ZI_REGION__ZI区域初始化为0;
3.初始化OEM要求的动态Heap;
4.至于代码段里的数据初始化,直接在Image里就完成了(编译器完成);
g)boot_stack_initialize
ARM栈初始化,主要是为分块代码加载而预留的.
h)boot_cache_mmu_init
ARM Mmu初始化
注意:到此为止,整个Boot的工作就告完结了,那么,它又是如何跳到AMSS的main入口点呢?原因很简单,ARM编译器在链接的时候会自动做出一个__rt_entry(),由此函数来完成ARM库函数的初始化,并最后将代码执行点跳转到main()。而__rt_entry()会在boot_reset_handler.s里调用,具体细节,大家可以不用太过关心,只需要明白,Boot跑完之后,手机软件就跑到了main里就Ok了。
三.Ui_task的深入分析
从大的方向来讲,ui_task只完成两件事,一件是必要的初始化工作(这个也是我们所关心的,即ui_task到底完成了哪些工作);另外一件事就是各种信号量的事件处理,这也是我们比较关心的,即ui_task到底将哪些事件转发给了上层App。搞清楚了上述两点,我们也就能大致把ui_task的承上启下的工作机理研究清楚。
1.ui_Init;
初始化过程中,ui_task主要完成了如下几件事。
a)创建一个用于Kick Watchdog的定时器,这样WatchDog能够及时得到Kick,假如今后发现手机在ui_task里面自动重启,很有可能就是这个定时器的Timeout设置得过短而造成的;
b)注册通话相关的回调,主要是和紧急呼叫相关;
c)电话本初始化,之所以要进行这个工作,主要是加快开机之后AL层软件操作电话本的速度,但这样将有可能导致开机速度过慢,如果开机速度过慢,可以考虑进入待机界面之后,在后台开一个task去完成这项工作;
d)初始化Sound设备;
e)向底层服务任务wms_task注册wms回调,这个回调是在IWms组件里实现的。从这种角度来看,u帮我们把wms_task和IWMS组件联系起来了,但并没有去将AL层软件和IWMS联系起来,这个工作将是由AL层软件自己去完成。当然,注册回调的这个工作也是可以在AL层完成,之所以在这里完成,而不是在AL层完成,其主要目的是这个工作可以做到与AL层无关,即AL层不需要关心这个事情,但这个事情是短消息功能得于实现的必须步骤;
f)注册键盘消息回调;
通过这个回调,所有的按键消息都将经由底层的hs_task传到此回调函数里。然后回调函数将把所有的按键信息放到一个全局变量ui_key_buffer里面,接着发送一个UI_KEY_SIG信号给ui_task通知它去处理按键信息,至于ui_task如何处理按键消息的,后面的ui_handleSignals里会有详细描述。
g)初始化Lcd,这个工作不是LCD硬件设备的真正初始化,只是一些UI需要用到的LCD数据结构的初始化,和我们关系不大;
[注]
硬件的初始化,全部都在hs_task里面完成,从这种角度来看的话,系统能跑到ui_task里面,表明所有的硬件设备的驱动都已经成功加载。
h)置开机标志ui_powerup为True;
i)注册IPC信号量UI_IPC_SIG,这个可以暂时不管;
j)bridle_InitSWITable的初始化,这个目标,暂时不知道,也可以先略过;
k)初始化资源文件,其主要工作就是在Rom里面建立资源文件的符号链表,这样就可以让系统找到这些资源文件了(资源文件是被编译在代码段的,假如不这样做的话,系统将找不到这些资源文件);
l)Brew运行环境AEE的初始化:AEE_Init,这个函数看不到代码,大家只需要知道,到了这一步,整个Brew也就Run起来了,在AEE初始化完成之后,它将自动启动一个Applet,即CoreStartApp,而CoreStartApp将把CoreApp启动起来;
m)到此为止,ui_task的初始化工作完成;
[注意]
1) 从上述的ui_task的初始化工作可以看出,ui_task并没有完成手机AL层软件的基本功能的初始化,比如说Sim卡检测、网络初始化等,这些工作,应该是在CoreApp里完成的。
2) 真正和手机功能相关的初始化工作,是在CoreApp里完成的,这个Applet的工作机理,后面也会有详细描述;
2.ui_HandleSignals;
ui_task主要完成如下事件的处理。
a)看门狗喂食;
b)TASK_STOP_SIG信号,任务Stop,目前这个任务为空,没做任何事;
c)TASK_OFFLINE_SIG的处理,这几个任务都属于操作系统层面的事件,目前我们可以暂时不管;
d)处理关机信号:CoreAppHandleStopSig(),这个只是处理ui_task在关机前需要完成的任务,比如说发送一个消息给CoreApp让它关掉自己,然后将ui_task关闭;
系统的真正关机信号是由tmc来处理,当它发现需要关机时,调用tmc_powerdown_handler来完成相应的工作,在这里就是给所有的任务发送TASK_STOP_SIG的信号。
深层次的关机处理,不需要我们了解,也没必要去知道,我们只需要知道在ui_task里面把该关的关掉就Ok了。
关机是一个层层深入的过程,每一个App或者任务只需要负责将它们自己创建的资源释放掉就Ok了。而关机的导引线,显然是在CoreApp里截获到关机键之后发送出来的,事实上也是如此。
e)网络掉线时,发送掉线信号给CoreApp;
其实这个信号完全可以在CoreApp里面,自己去注册,然后及时更新自己的网络状态,就不知有没有这种接口函数。
f)处理按键消息,其主要完成如下的工作:
i.打开背光;
ii.特理按键到虚键值的转换;
iii.按键声音的处理;
iv.将按键消息传送到AEE执行环境,由它去负责按键的派发;
[注]
1.背光的打开是由ui默认完成的,那这样的话,假如我不想按键时有背光,是否可行?看来就得修改此处的代码;
2.AEE的按键派发机制如何?它能否保证处于显示最上层的App永远是可以得到Key的App,即假如一个Applet将自身Hide,它是否依然可以得到Key,而其它的Applet是否就不可以得到了?很怕也像EMP一样出现焦点丢失的情况;
g)处理AEE_APP_SIG信号量,完成AEE的调度工作,这个任务是ui完成的最重要的一项工作,因为上层的App需要定时进行调度,目前看来,这个调度工作是由AEE_APP_SIG触发的,而AEE_APP_SIG这个信号量,则由操作系统层面的一个定时器定时发送的。现在大家只要了解,AEE_Dispatch会定时调用就Ok了,至于更详细的AEE调度机制,可以参考我的另外一篇《AEE运行机制深入分析与研究》;
h)处理AEE_SIO_SIG信号量,这个看不到代码,暂时略过不管;
3.结论
通过上述对于ui_task的分析,可以看出,ui_task真正和手机功能有关系的(即可能需要定制或者修改的地方),主要就是初始化资源文件和处理按键消息这两部分。至于其它部分,目前都不需要Amoi关心。手机真正功能的实现,比如说开机Logo的显示、Sim卡的检查、Pin码校验等,都是在CoreApp里面完成的。
四.CoreApp的深入分析
目前参考代码里面的CoreApp所完成的工作比较多且杂,主要说来有如下几件事。
a)系统组件初始化;
b)开机Logo的显示;
c)Sim卡检测和Pin码校验;
d)系统状态信息更新;
i.电池状态;
ii.网络信号;
iii.网络模式;
e)IAnnunciator的维护与更新;
f)通话处理,打电话的输入框;
g)主菜单处理;
h)手机各种设置功能的处理;
i)关机键的处理;
目前CoreApp里面的代码,完成了太多的事,其实完全可以剥离成不同的模块来完成,大致可以分成如下几个部分。
1、总控模块;(CoreApp)
总控模块,主要完成手机按下开机键之后的各种初始化工作,同时此模块也是整个手机的控制中心,由它来完成手机的一些全局性工作,主要有如下几项。
1.系统初始化、Sim卡检测和Pin码校验;
2.开机Logo或者开机动画的显示;
3.底层服务程序的启动;(WmsApp、DialApp等);
4.系统配置信息的统一管理;
由于写配置信息到NV上面是一件非常慢的工作,每次上层App改变配置之后都去操作NV,很影响速度。所以,可以在内存中开一个配置信息的Buffer,上层App操作的实际上是这个Buffer,然后由Core在空闲的时候再统一写到NV上去。
5.关机处理;
[注]
由于CoreApp是在Idle Applet的界面之下,所以,为了能够实现“一键回菜单”的功用,有可能需要修改ui_task里面的Key处理函数,将所有的Key消息转发给Core,这样Core就可以得到所有的Key事件了。(现在的ui_task只把Key事件发送给了AEE,而AEE只会将Key事件发送给当前活动Applet)。
2、Idle模块;
主要完成待机界面的画图工作,主要有两部分:
1.系统信息指示栏;
2.待机界面(位图、动画、时钟、日历等);
3.软键
[注]
Idle只负责界面工作,不负责具体的系统状态信息的获取工作,这个工作将由其它模块完成。
3、Polling
手机状态信息查询模块,主要是完成手机各种状态信息的更新与维护。主要有如下几种:
a.电池强度;
b.网络信号强度;
c.网络模式(C/G);
d.PLMN网络名;
e.短消息、通话状态、闹铃;(这个由专门的模块完成,不在Polling之列);
f.各种外设信息;(USB、耳机插入等);
g.其它各种杂项信息;
4、Menu模块
菜单模块主要分两部分,一部分是主菜单的实现,另一个子菜单的实现。一般来讲,手机上的菜单系统应该是由Menu模块去统一完成,而不是由每一个子程序去手动完成。菜单模块一般只需要负责到主菜单、二级菜单和三级菜单就Ok了。三级菜单之后的界面,就由每一个App单独去维护了。
5、其它功能App模块;
每一个功能模块,由一个专门的App来完成,这样的话,模块的独立性强,便于单独开发。模块间通过App启动和消息传送的方式来发生关系和进行模块间通信。
五.后记
到此为止,Qualcomm整个手机从按下开机键到跑到主菜机界面,整个流程一目了然。对于Amoi而言,目前需要关心和定做的部分其实不多,最头疼的 当属CoreApp的改造工作,当然这个就是后话了,笔者将在今后的文章中加以详述。
希望本文对于大家理解Qualcomm手机软件的运行流程有一定的帮助,如果有什么问题,请直接联系我,最后谢谢大家耐心把本文看完,谢谢。
六.参考文档
a)80-V1072-1_E_Boot_Block_Downloader.pdf
b)80-V5316-1_K_QCT_Ext_API_RG.pdf
c)driver/boot目录源码
d)service/tmc目录源码
e)app/core目录源码