<7> 紫光展锐[ENGPC] EngPC框架和执行流程

本次来说一下EngPC的框架,如下图是EngPC的大致框架:

我们再来看它交互手机和PC的一个大致流程:

Engpc服务主要功能为解析cmdline中相关参数、建立手机AP端与计算机、手机AP端与CP端、手机CP端与计算机之间收发指令的通道,以及对指令的解析并进行相应处理等.其中最为主要的是vdiag指令写线程(eng_vdiag_wthread),线程中完成了手机AP端通过USB从计算机工具端获取DIAG指令,并对指令进行解析,通过指令类型判断是否将指令传给手机CP端处理,若AP端能够处理则调用相应处理函数进行处理,并将处理结果封装成DIAG指令格式反馈给计算机工具端。若AP端无法处理则通过SIPC通道将指令传输给CP端,由CP端进行处理。

EngPC代码量虽然不多,但是麻雀虽小,五脏俱全,它相当于一个什么地位呢?相当于一个完整上层执行框架(依赖于Android 文件系统),手机在开机状态下能执行的驱动程序,EngPC都能执行,只不过,目前EngPC还比较弱小,执行效果和执行样式还不能达到手机开机状态执行效果,这后面可以扩展,从此看来,EngPC就像是一个小型的Framework一样,在进行自动化测试(EngPC校准模式)中,Autotest模块会启动,并且其中之后,会执行关闭zygote service,关闭zygote就意味着Framework就无法启动了,但是测试时,驱动依然可以正常调用(数据给autotest,然后autotest执行),所以,虽然代码量不多,但是设计的范围比较广,且知识点也是很多的,目前架构还在调整当中,计划在Android P上实现全新架构.在新的架构当中,EngPC将只负责命令的传输,剩余的工作通过加载动态库的形式完成,也就是需要AP侧执行的任务将在动态库中实现,届时将取代Autotest模块,在经过一定的过渡期之后,autotest手机端模块将"退出舞台",其负责的任务将由autotest的PC和EngPC加载的动态库配合完成.

EngPC的使用有两种方式:①开机使用; ②关机使用. 根据使用的模式不同,EngPC运行的效果不同,也就是使用的服务不同.下面我们来分别简单介绍一下.

①开机使用---->Normal mode

通过分析engpc.rc文件可以知道,在Normal模式下,EngPC是以Android service的形式启动,在engpc.rc文件中总共定义了7个服务.7个服务对应7种不同的功能,7个服务定义如下:

service engpcclientt /vendor/bin/engpc -p t -a /dev/ttyGS0 -d /dev/ttyGS1 -l /dev/ttyGS4
    class core
    user root
    group system radio shell
    disabled
    oneshot

service engpcclientlte /vendor/bin/engpc -p l -a /dev/ttyGS5 -d /dev/ttyGS6 -l /dev/ttyGS7
service engpcclientwcn /vendor/bin/engpc -p wcn -a /dev/ttyGS2 -d /dev/ttyGS3
service engpcclientw /vendor/bin/engpc -p w -a /dev/ttyGS0 -d /dev/ttyGS1
service engpcclienttl /vendor/bin/engpc -p tl -a /dev/ttyGS5 -d /dev/ttyGS6
service engpcclientlf /vendor/bin/engpc -p lf -a /dev/ttyGS5 -d /dev/ttyGS6 -l /dev/ttyGS7
service engpcclientag /vendor/bin/engpc -p ag -l /dev/ttyGS4

从上面可以看到,启动的可执行文件是同一个,主要的区别就是传递的端口,事实上也确实如此,传递的端口不同,测试的功能也就不同,当手机在开机情况下,我们连接PC和手机,这时手机就会注册PC端的端口,我们这里以Pandora工具来说明,插入手机,打开Pandora,我们会看到如下7个端口:

可以看到7个端口,每个端口对应上面一种service.可以通过连接不同的端口使用不同的功能.

②关机使用---->calibration mode

校准模式下,只有一个service启动,service如下:

service engpcclient /system/bin/engpc 
    class cali 
    user root 
    group root

校准模式比较常用吧.

以上是EngPC两种模式的一个简单介绍,下面,我们看一下EngPC的工作流程

如上图,可以看出,EngPC是PC和手机之间的一个桥接器件,它的整体工作框架如下:

看了上述框图之后,我们就应该对EngPC有了一个整体上的概念,有了整体概念之后,我们来讲一下具体代码的执行流程,代码我选用的是Android 8.1上的,因为在Android O之前,架构就是固定代码,添加删除功能都需要修改代码,在Android O之后,代码开始向加载动态库的方式实现功能的控制,所以Android 8.1上的代码有前面的影子,也有后面的雏形,我们维护也不只是新版本,旧版本也需要维护,当然,最终,我们想要看到的就是EngPC可以和版本无关,所有版本就用同一套代码,这样对谁都有好处,对吧,下面我们从EngPC的main函数开始,熟悉它的大概流程,看完之后,我们结合代码消化一下,应该就可以有一个入门级别的水平了,下面是main函数的流程:

上图就是EngPC的主函数,它的位置在eng_pcclient.c中,main函数基本上反应了整个EngPC的框架,我们只要把main函数展开分析,就可以细细地分析出整个流程,再结合代码分析,就基本上可以入门了.上图中青蓝色的方框是调用的外部函数,大多主要是创建线程,main函数主要是一个初始化的作用,真正执行,一般都分布在青蓝色方框中,接下来我们就展开这些外部函数,分别如下:

①eng_init_test_file()         @ eng_diag.c
②eng_sqlite_create()         @ eng_sqlite.c
③initialize_ctrl_file()     @ adc_calibration.c
④eng_printlog_thread()     @ eng_debug.c
⑤eng_timesync_thread()        @ eng_ap_modem_time_sync.c
⑥eng_socket_thread()        @ eng_socket.c
⑦eng_uevt_thread()            @ eng_uevent.c
⑧eng_agdsp_log_thread()    @ vlog.c
⑨eng_vlog_thread()            @ vlog.c
⑩eng_vdiag_wthread()        @ vdiag.c
⑪eng_vdiag_rthread()        @ vlog.c
⑫eng_at_pcmodem()            @ eng_at.c
⑬eng_wcnat_pcmodem()        @ sprd_wcn_at.c
我们按照调用顺序来逐一地介绍.

①首先是eng_init_test_file();  // 初始化测试文件,    它的框图如下:

②eng_sqlite_create();  // 创建数据库,    它的框图如下:

③initialize_ctrl_file();  // 初始化ADC相关文件,    它的框图如下:

④eng_printlog_thread();  // 创建和保存EngPC log的线程,    它的流程图如下:

从流程如中,我们可以看到,它创建了一个文件叫eng.log的文件用来保存EngPC的log,位置在/data/local/eng.log,当我们想直接看EngPC log的时候,或者,无法抓取log(比如校准模式)时,都可以通过查看此文件的方式查看EngPC相关的log.

⑤eng_timesync_thread();  // 时间同步线程,  它的执行流程如下:

特别的,我们来看一下时间同步线程执行的整体流程:

在以下情况下会发生同步,其它情况还没想到:

1).AP系统启动时,engpc通过Unix domain socket连接refnotify进程,以便接收AP/MODEM时间对应消息。
当engpc进程收到来自Logel的CMD_USER_GET_TIME_SYNC_INFO命令后,engpc在TIME_SYNC_INFO消息中返回AP/MODEM的时间对应关系。

2).AP系统启动时,engpc连接refnotify和modemd进程,以便接收时间对应消息和MODEM状态变化消息。
    当MODEM发生故障需要重启时,modemd会重启MODEM,同时通知engpc进程。
    待MODEM重启后,MODEM上的RefNotify_RcvHandler线程又会把MODEM的时间通知给AP上的refnotify进程,进而依次传递给engpc和Logel软件。
需要说明的是:
    MODEM向refnotify发送REF_CPTIME_CMD消息的时间为MODEM初始化完成,此时Logel软件与MODEM之间没有诊断消息交互,因此engpc发出TIME_SYNC_INFO(是诊断消息)时不需要解析MODEM与Logel之间的诊断数据码流,节省了AP的CPU和程序复杂度。
    MODEM向refnotify发送REF_CPTIME_CMD消息的时间,与MODEM重启后开始输出log的时间比较接近,彼此的先后关系并不确定。因此Logel在收到TIME_SYNC_INFO消息前,可能已经收到少量log,但因为在MODEM重启的时候,engpc已经发送CP_EVENT_NOTIFY(MODEM_RESET)消息给Logel,所以Logel是知道哪些log需要使用新的时间对应关系的。

⑥eng_socket_thread();  // 创建socket服务端,接收客户端配置信息,并设置相关配置,    它的流程图如下:

⑦eng_uevt_thread();  // 创建uevent相应线程,    它的流程图如下:


⑧eng_agdsp_log_thread();  // 获取modem的ag.log, ag.pcm, ag.mem的数据,加工之后给PC,    它的流程图如下:


⑨eng_vlog_thread();  // 从log通道(dev_log)获取数据,并把数据传给PC,    它的流程图如下:


⑩eng_vdiag_wthread();  // 读PC端数据,根据条件发送给AP或者CP处理,    它的流程如下:


⑪eng_vdiag_rthread();  // 如果处于校准模式,且engcplog是1,则AP log给PC, CP log给SD卡,否则log给PC,    它的流程图如下:


⑫eng_at_pcmodem();  // 读取PC的AT命令,调用动态库(AP侧),如果有则执行,如果没有则转发给CP,    它的执行流程如下:


⑬eng_wcnat_pcmodem();  // 执行和wcn相关的AT命令,    它的流程图如下:

还有一个函数,在这里没有显示调用,但是也很重要,所以这里也说一下,他就是eng_diag() @ eng_diag.c,它的执行流程如下:

好啦,以上就是EngPC的一个基本流程,结合代码看一下,基本上入门还是可以的,代码不是一个人写的,代码风格一个人一个样,不过有一点是统一的,就是代码基本上没有注释,我花了5天的时间给所有代码注释,又花了3天时间把整个流程联系起来,花了两天时间把流程图和教程写了出来,而代码量在Android 8.1上其实也就27K多行而已,就先说这么多吧,后边这套代码由我维护,到时候又是另一种代码风格...

猜你喜欢

转载自blog.csdn.net/qq_23922117/article/details/81185545
今日推荐