第一部分, c/c++代码



Android系统源代码目录里面: hardware/ril 目录包含了所有有关于telephony的底层代码.



1.目录架构(20101215的git版本):

ril

|-- CleanSpec.mk

|-- include

| |-- telephony

| |-- ril_cdma_sms.h //CDMA SMS

| |-- ril.h //Android RIL 框架的一些接口和数据结构

|-- libril

| |-- Android.mk

| |-- MODULE_LICENSE_APACHE2

| |-- NOTICE

| |-- ril_commands.h //RIL命令列表

| |-- ril.cpp

| |-- ril_event.cpp

| |-- ril_event.h

| |-- ril_unsol_commands.h //RIL 主动上报信息列表

|-- reference-cdma-sms

| |-- Android.mk

| |-- reference-cdma-sms.c

| |-- reference-cdma-sms.h

|-- reference-ril

| |-- Android.mk

| |-- atchannel.h //负责向modem读写数据

| |-- atchannel.c

| |-- at_tok.h

| |-- at_tok.c

| |-- misc.h

| |-- misc.c

| |-- MODULE_LICENSE_APACHE2

| |-- NOTICE

| |-- reference-ril.c //主要负责与modem进行交互

|-- rild

|-- Android.mk

|-- MODULE_LICENSE_APACHE2

|-- NOTICE

|-- radiooptions.c //调试时配置Modem参数

|-- rild.c //RIL守护进程



其中include/telephony目录下面的ril.h文件,定义了104个如下的宏:

RIL_REQUEST_XXXX

这些宏代表客户进程向Android telephony发送的命令,包括SIM卡相关的功能,打电话,发短信,网络信号查询等等。



2.目录hardware/ril/libril

本目录下代码负责与客户进程进行交互。在接收客户进程命令后,调用相应函数进行处理,然后将命令响应结果传回客户进程。在收到来自网络端的事件后,也传给客户进程。



v 文件ril_commands.h:列出了telephony可以接收的命令;每个命令对应的处理函数;以及命令响应的处理函数。

v 文件ril_unsol_commands.h:列出了telephony可以接收的事件类型;对每个事件的处理函数;以及WAKEType???

v 文件ril_event.h/cpp:处理与事件源(端口,modem等)相关的功能。ril_event_loop监视所有注册的事件源,当某事件源有数据到来时,相应事件源的回调函数被触发(firePending-> ev->func())

v 文件ril.cpp:

? RIL_register函数:打开监听端口,接收来自客户进程的命令请求(s_fdListen =android_get_control_socket(SOCKET_NAME_RIL);),当与某客户进程连接建立时,调用listenCallback函数;创建一单独线程监视并处理所有事件源(通过ril_event_loop)

? listenCallback函数:当与客户进程连接建立时,此函数被调用。此函数接着调用 processCommandsCallback处理来自客户进程的命令请求

? processCommandsCallback函数:具体处理来自客户进程的命令请求。对每一个命令,ril_commands.h中都规定了对应的命令处理函数(dispatchXXX),processCommandsCallback会调用这个命令处理函数进行处理。

? dispatch系列函数:此函数接收来自客户进程的命令己相应参数,并调用onRequest进行处理。

? RIL_onUnsolicitedResponse函数:将来自网络端的事件封装(通过调用responseXXX)后传给客户进程。

? RIL_onRequestComplete函数:将命令的最终响应结构封装(通过调用responseXXX)后传给客户进程。



? response系列函数:对每一个命令,都规定了一个对应的response函数来处理命令的最终响应;对每一个网络端的事件,也规定了一个对应的response函数来处理此事件。response函数可被onUnsolicitedResponse或者onRequestComplete调用。



3. 目录hardware/ril/reference-ril分析:

本目录下代码主要负责与modem进行交互。

v 文件reference-ril.c:此文件核心是两个函数:onRequest和onUnsolicited

? onRequest 函数:在这个函数里,对每一个RIL_REQUEST_XXX请求,都转化成相应的ATcommand,发送给modem,然后睡眠等待。当收到此ATcommand的最终响应后,线程被唤醒,将响应传给客户进程(RIL_onRequestComplete-> sendResponse)。

? onUnsolicited函数:这个函数处理modem从网络端收到的各种事件,如网络信号变化,拨入的电话,收到短信等。然后将时间传给客户进程(RIL_onUnsolicitedResponse -> sendResponse)



v 文件atchannel.c:负责向modem读写数据。其中,写数据(主要是ATcommand)功能运行在主线程中,读数据功能运行在一个单独的读线程中。

? at_send_command_full_nolock函数:运行在主线程里面。将一个ATcommand命令写入modem后进入睡眠状态(使用pthread_cond_wait或类似函数),直到modem读线程将其唤醒。唤醒后此函数获得了ATcommand的最终响应并返回。

? readerLoop函数: 运行在一个单独的读线程里面,负责从modem中读取数据。读到的数据可分为三种类型:网络端传入的事件;modem对当前ATcommand的部分响应;modem对当前AT command的全部响应。对第三种类型的数据(ATcommand的全部响应),读线程唤醒(pthread_cond_signal)睡眠状态的主线程。







第二部分, Java代码



1.package简介:

Android中,telephony相关的java代码主要在下列目录中:

v frameworks/base/telephony/java/android/telephony

提供Android telephony的公开接口,任何具有权限的第三方应用都可使用,如接口类TelephonyManager、SMSManager。

v frameworks/base/telephony/java/com/android/internal/telephony

v frameworks/base/services/java/com/android/server

提供一系列内部接口,目前第三方应用还不能使用。当前似乎只packages/apps/Phone能够使用.

v packages/apps/Phone

目录packages/apps/Phone是一个特殊应用,或者理解为一个平台内部进程。其他应用通过intent方式调用这个进程的服务。

2.详细介绍

v TelephonyManager(telephony/java/android/telephony/TelephonyManager.java)主要使用两个IBinder接口(AIDL接口)来访问telephony功能:

? ITelephony, 提供与telephony进行操作,交互的接口,在packages/apps/Phone中由PhoneInterfaceManager.java实现。

? ITelephonyRegistry,其提供一个通知机制,将一些底层状态或变更通知给电话服务的用户,如网络状态、信号强度等。它的服务实现在框架代码中,即:frameworks/base/services/java/com/android/server/TelephonyRegistry.java。

底层通知的来源是GSMPhone/CDMAPhone通过PhoneNotifier接口的实现者DefaultPhoneNotifier将具体的事件转化为函数调用,通知到TelephonyRegistry。TelephonyRegistry再通过两种方式通知用户:

§ Broadcast机制广播事件;

§ 通过服务用户在TelephonyRegistry.java中注册的IPhoneStateListener接口,实现回调机制。注册函数是用户可见的:

TelephonyManager.listen();

->TelephonyRegistry.listen(,IPhoneStateListener callback,,);

v 接口PhoneNotifier定义电话事件的通知方法

v 类DefaultPhoneNotifier从PhoneNotifier派生而来。在其方法实现中,通过调用service ITelephonyRegistry来发布电话事件。

v 接口Phone描述了对电话的所有操作接口。 PhoneBase直接从Phone派生而来。而另外两个类,CDMAPhone和GSMPhone,又从PhoneBase派生而来,分别代表对CDMA和GSM的操作。

v PhoneProxy也从Phone直接派生而来。当当前不需要区分具体是CDMA Phone还是GSMPhone时,可使用PhoneProxy。

备注:

在PhoneApp创建时,

sPhoneNotifier = new DefaultPhoneNotifier();

...

sCommandsInterface = newRIL(context, networkMode, cdmaSubscription);

然后根据当前phone是cdma还是gsm,创建对应的phone,如

sProxyPhone = newPhoneProxy(new GSMPhone(context,sCommandsInterface, sPhoneNotifier));





v PhoneFactory.java: 获取电话实例,如GSMPhone/CDMAPhone.

PhoneFactory.makeDefaultPhones();

->PhoneFactory.makeDefaultPhone();//注册相应的Phone实例

->Phone phone = (Phone)PhoneFactory.getDefaultPhone();

v 接口IPhoneStateListener: 手机状态监听接口(AIDL),其服务实现在/frameworks/base/telephony/java/android/telephony/PhoneStateListener.java

v 接口CommandsInterface 描述了对电话的所有操作接口,如命令, 查询状态,以及电话事件监听等。



v 类BaseCommands是CommandsInterface的直接派生类,实现了电话事件的处理(发送message给对应的handler)。

v 类RIL又派生自BaseCommands。RIL负责实际实现CommandsInterface中的接口方法。RIL通过Socket和rild守护进程进行通讯。对于每一个命令接口方法,如acceptCall,或者状态查询,将它转换成对应的RIL_REQUEST_XXX,发送给rild。RIL中的几个类如下:

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

? RIL.RILSender:负责处理命令的发送;

? RIL.RELReceiver:负责处理命令相应以及主动上报信息的接受;线程RILReceiver监听socket,当有数据上报时,读取该数据并处理。读取的数据有两种。

§ 电话事件,RIL_UNSOL_xxx, RIL读取相应数据后,发送message给对应的handler(详见函数processUnsolicited);

§ 命令的异步响应。(详见函数processSolicited)

v RILConstants.java : 定义了电话服务的具体命令。

v 抽象类Call代表一个call,有两个派生类CdmaCall和GsmCall。



第三部分, 流程分析



1.Outgoing Call流程。

v TwelveKeyDialer.java

|_onKeyUp()

|_placeCall()

v OutgoingCallBroadcaster.java,

|_onCreate()

|_sendOrderedBroadcast(broadcastIntent, PERMISSION,

new OutgoingCallReceiver(), null, Activity.RESULT_OK, number,null);

|_ OutgoingCallReceiver

|_onReceive()

|_ doReceive()

|_context.startActivity(newIntent);

v InCallScreen.java

|_ onCreate()

|_onNewIntent()

|_placeCall()

v PhoneUtils.java

|_placeCall()

v GSMPhone.java,

|_dial()

v GsmCallTracker.java,

|_dial()

v RIL.java

|_dial()

|_ RILRequest rr = RILRequest.obtain(RIL_REQUEST_DIAL, result);

|...

|send(rr);



2. Incoming Call的流程:

v 创建GsmPhone时,mCT = new GsmCallTracker(this);

v 创建GsmCallTracker时:

? cm.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE,null);

? mCallStateRegistrants.add(r);

v RIL中的RILReceiver线程首先读取从rild中传来的数据:

? processResponse()

? processUnsolicited()

v 对应于incoming call,RIL收到RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED消息,触发mCallStateRegistrants中的所有记录。

v GsmCallTracker处理EVENT_CALL_STATE_CHANGE,调用pollCallsWhenSafe

v 函数pllCallsWhenSafe 处理:

§ lastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);

§ cm.getCurrentCalls(lastRelevantPoll);

v RIL::getCurrentCalls

§ RILRequestrr = RILRequest.obtain(RIL_REQUEST_GET_CURRENT_CALLS,result);

§ ...

§ send(rr);

v 接着RIL调用processSolicited处理RIL_REQUEST_GET_CURRENT_CALLS的返回结果

v GsmCallTracker的handleMessage被触发,处理事件EVENT_POLL_CALLS_RESULT,调用函数 handlePollCalls

v handlPollCalls 调用phone.notifyNewRingingConnection(newRinging);

v PhoneApp中创建CallNotifier

v CallNotifier注册:

§ registerForNewRingingConnection ->mNewRingingConnectionRegistrants.addUnique(h, what, obj);



第四部分, 参考文档



1.《Android系统原理及开发详解》

2. http:/www.meegozu.com/thread-391-1-1.html

3. http://www.netmite.com/android/mydroid/development/pdk/docs/telephony.html

4. http://wenku.baidu.com/view/8d57336aaf1ffc4ffe47ac75.html

5. http:/wenku.baidu.com/view/ca78fabef121dd36a32d8258.html

备注
在PhoneApp创建时,

sPhoneNotifier = new DefaultPhoneNotifier();

...

sCommandsInterface = newRIL(context, networkMode, cdmaSubscription);

然后根据当前phone是cdma还是gsm,创建对应的phone,如

sProxyPhone = newPhoneProxy(new GSMPhone(context,sCommandsInterface, sPhoneNotifier));

更多相关文章

  1. GitHub 标星 2.5K+!教你通过玩游戏的方式学习 VIM!
  2. 如何在后台运行Linux命令?
  3. No.11 使用firewall配置的防火墙策略的生效模式
  4. 一款霸榜 GitHub 的开源 Linux 资源监视器!
  5. Android(安卓)L 64位兼容32 应用程序的认识
  6. Mac OS下Android开发环境配置详解
  7. Android(安卓)代码分析 私有析构函数
  8. android之退出应用程序
  9. Android(安卓)adb shell 启动java程序

随机推荐

  1. mysql 常用命令
  2. 前端框架LayUI介绍及用法
  3. 编程语言之问:何时该借用,何时该创造?
  4. 用python分析1225万条淘宝数据,终于搞清楚
  5. GIL 已经被杀死了么?
  6. AQS之ReentrantReadWriteLock精讲分析上
  7. UNIX系列之AIX克隆系统盘
  8. 用鸿蒙开发AI应用(六)UI篇
  9. 用《矛盾论》来解读 Python
  10. 对比 C++ 和 Python,谈谈指针与引用