android系统学习笔记七

Android电话部分综述

主要部分:

呼叫

短信

数据连接

SIM

电话本

电话部分分为以下几层:

Modem驱动

RIL(radiointerfacelayer)

电话服务框架

应用层

Modem通信模块

Chip-on-board
Modem硬件上一般使用两个渠道:

一个是用于AT命令:一般使用UARTUSB方式,AT命令由Hayes公司发明

AT开头,用于完成调制解调器之间的交互

另一个用于数据传输:通过usb方式传输数据

如果基带与应用处理器集成一般通过共享内存方式传输

本地的RIL代码
本地代码的路径:\hardware\ril

部分文件;

include:RIL头文件

Libril:RIL,最终生成libril.so是一个辅助库

Rild:守护进程安装在system/bin目录下

Rdference-ril:参考库,生成动态库libreference-ril.so

Include目录中ril.h头文件是RIL框架结构和接口

Rild守护进程

Rild是一个可执行程序:获取参数------->r打开功能库------->建立事件循环----------->执行RIL-Init------>register

ril.c

staticstructRIL_Envs_rilEnv={

RIL_onRequestComplete,//RIL请求完成

RIL_onUnsolicitedResponse,//主动上报的响应

RIL_requestTimedCallback//用户定义响应的回调函数

};

主函数部分代码如下:

intmain(intargc,char**argv)

{

...

//获取参数并解析

dlHandle=dlopen(rilLibPath,RTLD_NOW);

//启动线程进入事件循环

RIL_startEventLoop();

rilInit=(constRIL_RadioFunctions*(*)(conststructRIL_Env*,int,char**))dlsym(dlHandle,"RIL_Init");

//处理参数

funcs=rilInit(&s_rilEnv,argc,rilArgv);

RIL_register(funcs);

...

}

通过select多路复用机制,读取来自上层的Socket接口的具体操作命令

init.rc中启动这个守护进程,如果使用-l则可以指定所使用的功能库

Libril

Libril.so主要提供了用于注册的RIL_register(),

几个回调函数

RIL_onRequestComplete(RIL_Tokent,RIL_Errnoe,void*response,size_tresponselen){}

voidRIL_onUnsolicitedResponse(intunsolResponse,void*data,size_tdatalen){}

staticUserCallbackInfo*internalRequestTimedCallback(RIL_TimedCallbackcallback,void*param,

conststructtimeval*relativeTime){}

字符串转换函数

extern"C"constchar*requestToString(intrequest);

extern"C"constchar*failCauseToString(RIL_Errno);

extern"C"constchar*callStateToString(RIL_CallState);

extern"C"constchar*radioStateToString(RIL_RadioState);

RIL的实现库ReferenceRIL

libreference-ril.so功能库的一个参考实现,完成从具体电话服务命令到实际的AT命令之间的转换

Request请求流程

首先由java层通过socket将命令发送到RIL层的RILD守护进程,负责监听的ril_event_loop消息循环中

RILDSocket有了请求链接信号,会建立起一个record_system,打通与上层的数据通道开始接收请求数据

数据通道的回调函数processCommandsCallback()会保证收到一个完整的Request(Request包的完整性由record_stream的机制保证),将其送达processCommandBuffer()函数,

staticint

processCommandBuffer(void*buffer,size_tbuflen){

Parcelp;

status_tstatus;

int32_trequest;

int32_ttoken;

RequestInfo*pRI;

intret;

p.setData((uint8_t*)buffer,buflen);

//statuscheckedatend

status=p.readInt32(&request);

status=p.readInt32(&token);

if(status!=NO_ERROR){

LOGE("invalidrequestblock");

return0;

}

if(request<1||request>=(int32_t)NUM_ELEMS(s_commands)){

LOGE("unsupportedrequestcode%dtoken%d",request,token);

//FIXMEthisshouldperhapsreturnaresponse

return0;

}

pRI=(RequestInfo*)calloc(1,sizeof(RequestInfo));

pRI->token=token;

pRI->pCI=&(s_commands[request]);

//互斥量上锁

ret=pthread_mutex_lock(&s_pendingRequestsMutex);

assert(ret==0);

pRI->p_next=s_pendingRequests;

s_pendingRequests=pRI;

//互斥量解锁

ret=pthread_mutex_unlock(&s_pendingRequestsMutex);

assert(ret==0);

/*sLastDispatchedToken=token;*/

//调用分派函数

pRI->pCI->dispatchFunction(p,pRI);

return0;

}

processCommandBuffer()函数正式进入命令的解析流程它从socket中序列化的数据流里还原信息,将其组织到RequestInfo,每个命令将以下形式存在

typedefstructRequestInfo{

int32_ttoken;//thisisnotRIL_Token

CommandInfo*pCI;

structRequestInfo*p_next;

charcancelled;

charlocal;//responsestolocalcommandsdonotgobacktocommandprocess

}RequestInfo;

在还原出来的信息中,最重要的是request号它在RIL层和上层之间,ril_commands.h中定义

/**Index==requestNumber*/

staticCommandInfos_commands[]={

#include"ril_commands.h"

};

RIL层中采用表驱动方式分派请求,分派的基础是ruquest,头文件按以下方式被包含

commandInfo结枸表示命令信息,关联了request号和实际的请求函数,及响应函数之间的关系

typedefstruct{

intrequestNumber;

void(*dispatchFunction)(Parcel&p,structRequestInfo*pRI);

int(*responseFunction)(Parcel&p,void*response,size_tresponselen);

}CommandInfo;

接下来的分发流程,

s_callbacks.onReauest()完成这一操作,s-callbacks是获取libreference-rilRILRadioFunctions的结构指针,请求在这里转入底层libreference-ril处理,handlerreferece-ril.cRequest

例如:RIL——REQUEST——DIAL请求流程如下

onRequest()---->requestDial()-这里将命令和参数转换成对应的AT命令----------->at_send_connand------->at_command_full()------>at_send_command_full_nolock()---->writeline()

Response流程

RIL的移植工作

当宏RIL——SHLIB被定义时,将使用库的行式,

没有被定义时,将使用守护进程的方式

移植需要考虑的问题:

RIL设备所使用的不同端口

RIL_RadioFunctionsonRequest函数中需要处理的不同命令(差异部分在数据连接和呼叫状态查询等方面)

电话部分Java框加及应用

代码路径为:\frameworks\base\telephony\java

Java层与RIL本地代码的接口,是一个名为rildsocket接口

RIL.java中的几个类

RILRequest代表一个电话服务命令请求

RILSender负责命令的发送

RILReceiver处理信命令响应和主动上报信息的响应

RILConstants.java定义了电话报务的具体命令

classRILRequest{

staticRILRequestobtain(intrequest,Messageresult){}

voidrelease(){}

StaticvoidresetSerial(){}

StringserialString(){}

voidonError(interror,Objectret){}

}

RILRIL.RIL_SenderRIL.RILReceiver几个类的关系

publicfinalclassRILextendsBaseCommandsimplementsCommandsInterface{}

Connamds为命令响应或主动上报提供回调函数的注册机制

commandInterface提供具体的电话服务接口

RILJava中一个命令的发送标准流程是:

RILRequest.obtain--->复制参数----->通过send()函数发送EVENT_SEND----->RILSender线程中处理EVENT_SEND------>将命令写到outstream(socket)

Socket的取得,是在RILReceiver中建立

staticfinalStringSOCKET_NAME_RIL="rild";

s=newLocalSocket();

l=newLocalSocketAddress(SOCKET_NAME_RIL,

LocalSocketAddress.Namespace.RESERVED);

s.connect(l);

响应和主动上报消息的流程:

RILReceiver线程监视mSocketinput------>readRilMessage(读取完整响应)---------->processResponse---------->分别处理RESPONSE_UNSOLICITEDRESPONSE_SOLICITED(前者为主动上报,后者为命令响应)

注:sendprocessResponse是异步的,电话服务的发送和响应是异步的

RIL直接同RIL本地代码打交道,对上层应用来说他并不是直接的接口,GSMPhone.java他继承了PhoneBase,phoneBase实现了phone接口,GSMPhoneRIL进行了一层封装,通过phone接口来实现功能

Phone应用程式序中:

通过PhoneFactory来获取GSMPhone

流程是:

PhoneFactory.makeDefaultPhones------>PhoenFactory.useNewRIL------>PhoneFactory.registerPhone

然后Phone就可以获取GSMPhone的实例(Phone接口)

拔打电话和获取网络状态,是由telephonyManager来完成

TelephoneManager通过两个IBander接口ITelephonyITelephonyRegistry来完成

ITelephony是电话服务的用户主动进行RIL访问的路径(如拔打电话),它的服务实现类不在框架代码中,而在phone应用中phoneInterfaceManager.java

ITelephonyRegistry提供一个通知机制,将底层状态或变更通知给电话服务如网络状态/信号强弱

底层通知的来源是GSMPhone通过PhoneNotifier的实现者DefaultPhoneNotifier.java

telephonyRegistry通过两种方式通知用户

一种是Broadcast

另一种是在TelephoneRegistry.java中注册的IPhoneStateListener接口实现回调机制

interfaceITelephonyRegistry{

voidlisten(Stringpkg,IPhoneStateListenercallback,intevents,booleannotifyNow);

}

传递的是IPhoneStateListenercallback参数

呼叫

ITelephony接口实现在Phone应用中的phone服务,通过TelephonyManager提供访问接口

服务内部通过PhoneFactory获取GSMPhone来访问URI提供如拔号/接通/挂断

在呼叫部分中,GSMPhoneRIL的路径中用到的几个数据结构如下:

GSMCall基本的呼叫控制结构,每个接通的GSMCall都拥有一个GSMConnection结构

GSMConnection该结构用于存放呼叫时长等信息

CallTracker是呼叫模块的核心它提供与呼叫相关的接口

GSMPhone拥有CallTracker的实例,通过调用CommandsInterface实现

维护当前的GSMCall,实现追踪的方法为:pollCallsWhenSafe

getCurrentCalls取得当前活动的呼叫列表

短信部分

SMSManager实现短信的发送与sim卡短信相关的操作通过ISms接口实现对应操作

ISms的服务端实现是:simsmsInterfaceManager

SMSDispatacher是短信的核心部分,负责发送接收短信,同样也集成在GSMPhone

发送方面

提供了textpdu两种方式.SmsTracker跟踪短信的发送过程

发送结果根据PendingIntent回传

接收方面

SMSDispatcher启动时会通过CommandInterface注册新短信和返回报告的回调接口

mCm.setOnNewSMS(this,EVENT_NEW_SMS,null);

mCm.setOnSmsStatus(this,EVENT_NEW_SMS_STATUS_REPORT,null);

mCm.setOnIccSmsFull(this,EVENT_ICC_FULL,null);

mCm.registerForOn(this,EVENT_RADIO_ON,null);

有新消息上来时,相应的消息会被发送到SMSDispatcher的消息处理函数

dispatchMessage会读取SMSHeader分析是否需要拼接,完在后由dispatchPdus通过

Intentintent=newIntent(Intents.SMS_REJECTED_ACTION);

intent.putExtra("result",result);

mWakeLock.acquire(WAKE_LOCK_TIMEOUT);

mContext.sendBroadcast(intent,"android.permission.RECEIVE_SMS");

广播出去

数据联接

Android数据联接是通过ppp方式实现的

数据联接分两个步骤:

首先是通过AT命令激活PDP联接

pppd通过数据端口完成拔号联接

GSMPhone拥有其实例,基入口点是:

DataConnectionTrackr.trySetupData------>setupData------->pdpConnection.connect------>commandsInterface.setupDefaultPDP

数据连接部分的结构

注:pppd是一个单独的进程,需要在init.rc里注册此服务

猜你喜欢

转载自201206260201.iteye.com/blog/1688927