android下调试3G之Ril库分析

一、基本架构概述

Android RIL (Radio Interface Layer)提供了Telephony服务和Radio硬件之间的抽象层。RIL负责数据的可靠传输、AT命令的发送

以及response(响应)的解析。一般的,应用处理器(AP)通过AT命令集与无线通讯模块(基带/BP)通信。通信的方式又分为主动

请求的request(诸如拨号、发短信……),以及Modem主动上报的例如信号强度、基站信息、来电、来短信等,称之为

unsolicitedresponse(未经请求的响应)。系统框架如下图:

二、ril-daemon的启动:

ril-daemon进程是由init进程在系统开机时负责启动的,该进程在我们系统启动之后就一直存在在系统里面了。

在init.rc(.../out/target/product/sabresd_6dq/root/init.rc对应源码
 .../system/core/rootdir/init.rc)中可以看到如下代码:

service ril-daemon /system/bin/rild -l /system/lib/libreference-ril.so -- -d /dev/ttyUSB2 # -u /dev/ttyUSB0

class main

socket rild stream 660 root radio

socket rild-debug stream 660 radio system

user root

group radio cache inet misc audio sdcard_rw log

ril-daemon守护进程指的是system/bin/下的可执行程序rild,而rild是由.../hardware/ril/rild/目录下的rild.c文件编译生成的。

三、rild启动流程分析

1、rild(hardware/ril/rild/rild.c):仅实现main函数作为整个ril层的入口点,负责完成初始化。

2、libril.so(hardware/ril/libril/*):与rild结合相当紧密,是其共享库,编译时就已经建立了这一关系。

组成部分为:rild.cpp、ril_event.cpp。libril.so驻留在rild这一守护进程中,主要完成同上层通信的工作,接受ril请求并传递

给libreference-ril.so,同时把libreference-ril.so的反馈传给调用进程。

3、libreference-ril.so(hardware/ril/libreference-ril/*):rild通过dlopen方式加载,主要负责跟Modem硬件通信。它转换来自

librild.so的请求为AT命令,同时监控Modem的反馈信息,并传递回libril.so。在初始化时,rild通过符号RIL_Init获取一组函数

指针并以此与之建立联系。

4、radiooptions(hardware/ril/rild/radiooptions.c):radiooptions通过获取启动参数。利用socket与rild通信,可供调试时配置

Modem参数。

5、rild.c 代码分析

1)dlHandle = dlopen(rilLibPath, RTLD_NOW);//打开动态链接库,根据上面脚本中的语句打开的为:

/system/lib/libreference-ril.so库

2)rilInit = (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))dlsym(dlHandle, "RIL_Init");

根据动态链接库操作句柄与符号,返回对应的地址,这里返回"RIL_Init"函数地址,该函数在libreference-ril.so库里面定义

rilLibPath是通过property属性值的方式来获取的。它的值为:“/system/lib/libreference-ril.so “动态库文件的属

性值。

3)RIL_startEventLoop():开启libril.so中的event机制,在RIL_startEventLoop()中是最核心的由多路I/O驱动的信息循环。

4)RIL_Init:初始化libreference-ril.so,也就是跟硬件或模拟硬件Modem通信的部分,通过RIL_Init函数完成,函数的返回值

为rilInit为一个RIL_RadioFunctions类型的结构体的指针。

5)RIL_register( ):通过RIL_Init获取一组函数指针RIL_RadioFunctions
 s_callbacks,并通过RIL_register完成注册,并打开

接受上层命令的socket通道。

四、RIL_startEventLoop(
)函数分析

1、ret = pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL):创建一个消息循环的s_tid_dispatch线程,它的回调函数

eventLoop( )。

2、while (s_started == 0) {

pthread_cond_wait(&s_startupCond, &s_startupMutex);

}:如果eventLoop( )方法不执行,RIL_startEventLoop(
)方法就不会返回。

五、eventLoop(
)函数分析

1、s_started = 1:改变s_started 的值,让RIL_startEventLoop(
)能正常结束。

2、ril_event_init():初始化ril_event.cpp几个非常重要的成员变量:readFds、timer_list、pending_list、watch_table。

3、ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true,processWakeupCallback,
NULL):注册进程唤醒时的回调。

4、ril_event_loop( ):建立起消息队列机制。

六、ril_event.cpp代码分析

每个ril_event结构,与一个fd句柄绑定(可以是文件,socket,管道等),并且每一个func指针所指的函数是个回调函数,它指定

了当所有绑定的fd准备好进行读取时所要进行的操作。

1、fd_set  readFds:存放所有的ril_event对应的fd信息,便于通socket()来查找对应的ril_event消息。

2、fil_event  * watch_table[ MAX_FD_EVENTS ]:监听事件队列,就是一个ril_event数据类型的链表或者数组。

3、ril_event  timer_list:超时事件队列,也就是说本来某某事件是在time_table里面的,表示正在被监听,过了些时间,超时了

还没有被触发,那么这个事件被扔pending_list里面,待执行。

4、ril_event  pending_list:待执行的事件集合。

5、Ril_event_loop就是一个for的无限循环,在这个for内部看到select函数了,其实select只监测read的fd_set,所要监听的

fd都存放在全局变量readFds中,ptv决定select
block的形态,要么设定时间block直到到期,要么无限block直到有监听fd上

数据可读,当select返回后就会查找是哪个事件的fd的触发的,然后通过firePending()呼叫该事件的callback。注意这是循

环的内部,也就是说每当select返回并执行其他动作之后,又会重新把readFds加到select中。熟悉Linux的同学应该很清楚这

种IO多路复用的select机制。

七、RIL_Init()函数分析

首先通过参数获取硬件接口的设备文件或模拟硬件接口的socket. 接下来便新开一个线程继续初始化,即mainLoop。mainLoop

的主要任务是建立起与硬件的通信,然后通过read方法阻塞等待硬件的主动上报或响应在注册一些基础回调(timeout,readerclose)

后,mainLoop首先打开硬件设备文件,建立起与硬件的通信,s_device_path和s_port是前面获取的设备路径参数,将其打开。

RIL_Init的主要任务:

1、向librefrence.so注册libril.so提供的接口RIL_Env;

2、创建一个mainLoop工作线程,用于初始化AT模块,并监控AT模块的状态,一旦AT被关闭,则重新打开并初始化AT;

3、当AT被打开后,mainLoop工作线程将向Rild提交一个定时事件,并触发eventLoop来完成对modem的初始化;

4、创建一个readLoop工作线程,用于从AT串口中读取数据;

5、返回librefrence.so提供的接口RIL_RadioFunctions;

6、ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL):创建一个mainLoop线程

7、RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0):有了响应机制,通过此函数跑到

initializeCallback中,执行一些Modem的初始化命令,主要都是AT命令方式。

八、at_open( )函数分析

1、ret = pthread_create(&s_tid_reader, &attr, readerLoop, &attr):创建readerLoop工作线程,该线程用于从串口读取

数据。AT指令都是以/r/n或/n/r的换行符作为分隔符的,所以readerLoop是line驱动的,除非出错,超时等,否则会读到一

行完整的相应或主动上报,才会返回,这个循环跑起来以后,基本的AT响应机制已经建立起来了。

2、readerLoop()函数分析

for (;;) {

. . . . . .

line2 = readline();//AT命令都是以/n/r/t结束,都是一行为单位读取

processLine(line); //处理接收到的数据,根据line中的指令调用不同的回调函数

. . . . . .

}

九、RIL_register(
)函数分析

在RIL_init结束时的返回值为rilInit(RIL_RadioFunctions结构体类型),先来看看RIL_RadioFunctions结构体的构成,其中

最重要的是onRequest,上层来的请求都由这个函数进行映射后转换成对应的AT命令发给硬件。RIL_register的另外一个重要的作用

是:打开和上层通信的socket管道。有了这样一个通道,上层App就可以同过这个通道来和Modem端通信,Modem端也可以通过这个通

道向上层App发送响应消息了。

1、typedef struct {

int version;       //Rild版本 /* set to RIL_VERSION */

RIL_RequestFunc onRequest;//AP请求接口

RIL_RadioStateRequest onStateRequest;//BP状态查询

RIL_Supports supports;

RIL_Cancel onCancel;

RIL_GetVersion getVersion;//动态库版本

} RIL_RadioFunctions;

2、监听rild  Socket管道

s_fdListen = android_get_control_socket(SOCKET_NAME_RIL);// 得到名为rild的socket句柄

ret = listen(s_fdListen,
4);

此处即监听上层RIL_java中创建的那个“rild”的socket。

3、监听rild——deBug
 Socket管道

s_fdDebug = android_get_control_socket(SOCKET_NAME_RIL_DEBUG);// 得到调试socket的句柄rild-debug

ret = listen(s_fdDebug, 4);

4、ril_event_set (&s_listen_event, s_fdListen, false,listenCallback,
NULL):设置s_listen_event事件,一旦有客户端连接,即

s_fdListen可读就会导致eventLoop工作线程中的select返回,因为该事件不是持久的,因此调用为listenCallback处理完后,将

从watch_table移除该事件,所以Rild只支持一个客户端连接。

5、rilEventAddWakeup (&s_listen_event): 添加s_listen_event事件,并触发eventLoop工作线程。

十、listenCallback()函数分析

1、s_fdCommand = accept(s_fdListen, (sockaddr *) &peeraddr, &socklen):接收一个客户端的连接,并将该socket连接保存在

变量s_fdCommand中。

2、p_rs = record_stream_new(s_fdCommand, MAX_COMMAND_BYTES):p_rs为RecordStream类型,它内部会分配一个缓冲

区来存储客户端发送过来的数据。

3、ril_event_set (&s_commands_event, s_fdCommand,
1,processCommandsCallback, p_rs):添加一个针对接收到的客户端连

接的处理事件,从而在eventLoop工作线程中处理该客户端的各种请求 。

时间: 2024-10-01 09:14:42

android下调试3G之Ril库分析的相关文章

android下调试3G之USB串口驱动集成配置

一.修改Android内核的编译配置 vi ~/myandroid/kernel_imx/.config文件中,确保下面的的配置项已经被选定. (假如源码在~/myandroid目录下) 1. USB电源管理特性的相关配置项: CONFIG_USB_SUSPEND=y 2. USB串口驱动相关的配置项: CONFIG_USB_SERIAL=y CONFIG_USB_SERIAL_OPTION=y CONFIG_USB_SERIAL_WWAN=y 3. PPP拨号的相关配置项: CONFIG_PP

android下调试3G之gpio控制3G上电

如果是自己开发的板子,需要用GPIO引脚控制3G模块开机/关机时,下面的文章会对你有所帮助,是以处理器IMX6和中兴MG3732模块为例介绍. 一.引脚连接 处理器的gpio3_GPIO[9]连接3G模块的ON/OFF(29)引脚来控制3G的开机/关机. 二.开关机条件 给ON/OFF引脚连续2500~3500毫秒低电平则开机,给再ON/OFF引脚连续2500~3500毫秒低电平则关机. 三.gpio驱动程序 gpio_3g.c #include<linux/module.h> #includ

android下调试3G之手动拨号

当板子识别3G的USB串口设备时,在/dev下会看到ttyUSB0.ttyUSB1.ttyUSB2.ttyUSB3设备文件,就可以进行调试了.在拨号前还需要了解下模块USB串口的各个功能,比如中兴MG3732:Modem-ttyUSB3.AT-ttyUSB0.Debug-ttyUSB2.VoUSB-ttyUSB1,所以这里ttyUSB3用于拨号口,用的移动2G的卡. 一.在板子的 /etc/ppp下创建chat.peers文件夹,把一下对应的脚本文件放到新建的文件夹里. 1.char/evdo

android下调试3G之模块设备识别

3G模块设备和Android系统主要通过USB接口进行数据通信.Android系统上的Linux内核需要根据3G模块设备上报的USB设备接口加载USB 驱动,USB驱动正确加载后,3G模块才能正常工作.下面以添加华为模块设备识别为例: 一.修改 .../kernel/drivers/usb/serial/option.c文件 1.在option_probe()函数内添加红色框部分语句,可以支持 selective  suspend 特性. 2.在 option_driver()函数中添加红色框部

(转)&lt;Unity3D&gt;Unity3D在android下调试

转自:http://blog.csdn.net/zuoyamin/article/details/11827309 一.工具准备 1.JDK——由于android是基于Java平台开发的,jdk是必须要安装的.下载地址:http://www.java.net/download/jdk6/6u10/promoted/b32/binaries/jdk-6u10-rc2-bin-b32-windows-i586-p-12_sep_2008.exe 2.Android SDK——这个就不多说了,要开发a

android下调试unity3d应用

原地址:http://blog.csdn.net/armoonwei/article/details/7032455 目前貌似不支持断点调试,但可以通过日志打印(logcat)来跟踪. 在android SDK中有个adb工具,使用此工具来跟踪运行的android应用: adb logcat 启动logcat,并将设备上运行的android应用的运行时信息全部打印出来. adb logcat -s Unity 如果只想打印Unity的输出信息,使用此命令. adb logcat -d > log

android下调试声卡驱动之I2S音频通信

一.I2S概述 I2S(Inter-IC Sound)总线是飞利浦公司为数字音频设备之间的音频数据传输而制定的一种总线标准,该总线专责于音频设备之 间的数据传输.由4条线组成的数字音频接口,常用于HiFi,STB便携设备.Tx  和Rx信号线用于音频传输.而位时钟和左右时钟 (LRC)用于同步链接.I2S具有灵活性,因为控制器和解码器都可以控制位时钟和左右时钟.位时钟因采样率和主系统时钟而有不 同.LRCLK与采样率相同.少数设备支持独立的ADC和DAC的LRCLK.这使在不同采样率情况下同步捕

android下调试声卡驱动之概述

在Android中音频系统使用的是ALSA系统架构.ASoC--ALSA System on Chip ,是建立在标准ALSA驱动层上,为了更好地支持 嵌入式处理器和移动设备中的音频Codec的一套软件体系,在音频设备驱动中ASoC被分为Machine.Platform和Codec三大部分. Codec部分:负责音频解码,这部分代码完全无平台无关(设备原厂提供),它包含了一些音频的控件(Controls),音频接 口,DAMP(动态音频电源管理)的定义和Codec IO功能.为了保证硬件无关性,

android下调试声卡驱动之wm8960介绍二

三.LINPUT输入通道介绍 有关LINPUT的主要配置如下: R32的bit8(LMN1)置1:LINPUT1连接PGA: R00的bit7(LINMUTE)置0:禁止静音: R25的bit5(AINL)置1:PGA使能: R47的bit5(LMIC)置1:Left Boost Mixer使能: R32的bit3(LMIC2B)置1:boost连接Left Boost Mixer. 四.OUTPUT输出通道介绍 有关OUPUT的主要配置如下: R34的bit8(LD2LO)置1:使LDAC连接