现在的位置: 首页 > 综合 > 正文

android 电话解析

2013年09月21日 ⁄ 综合 ⁄ 共 17752字 ⁄ 字号 评论关闭

    Android中进行处理Android源码中,hardware/ril目录中包含着Android的telephony源码,下面就由我向大家介绍这些目录其中包含了三个子目录,下面是对三个子目录进行具体的分析说明。

    一、目录hardware/ril/include分析:

    只有一个头文件ril.h包含在此目录下。ril.h中定义了76个如下类型的宏:这些宏代表着客户进程可以向Android源码telephony发送的命令,包括SIM卡相关的功能,打电话,发短信,网络信号查询等。好像没有操作地址本的功能?

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

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

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

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

    对每一个命令,ril_commands.h中都规定了对应的命令处理函数(dispatchXXX),processCommandsCallback会调用这个命令处理函数进行处理。dispatch系列函数:此函数接收来自客户进程的命令己相应参数,并调用onRequest进行处理。

    RIL_onUnsolicitedResponse函数:将来自网络端的事件封装(通过调用responseXXX)后传给客户进程,RIL_onRequestComplete函数:将命令的最终响应结构封装(通过调用responseXXX)后传给客户进程。

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

    三、目录hardware/ril/reference-ril分析。本目录下代码主要负责与modem进行交互。 文件reference-ril.c:此文件核心是两个函数:onRequest和onUnsolicited 。

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

    onUnsolicited函数:这个函数处理modem从网络端收到的各种事件,如网络信号变化,拨入的电话,收到短信等。然后将时间传给客户进程(RIL_onUnsolicitedResponse -> sendResponse)文件atchannel.c:负责向modem读写数据。其中,写数据(主要是AT command)功能运行在主线程中,读数据功能运行在一个单独的读线程中。

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

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

//////////////////////////////////////////////////////////////////////////////////////////

Android call setting 源码分析从顶层到底层(上) - Android -

Android 的 call setting 是用来设定与 simcard 相关的一些内容的应用程序,如网络,PIN等等,算是AP层。这里就选择其中一个项从源代码读下去直到底层,看看大概的结构和流程。
    在 Android 主菜单中选择 setting->call setting->additional call setting->caller ID,会弹出来一个对话框来选择,这个项是用来设定在用电话本拨打电话的时候是否显示对方的电话号码。这里就以这个设定为例来一步步读下去。
AP层:
    call setting 的代码和资源都是放在/packages/apps/Phone 的目录下。其实 Android 的 setting AP 相关的资源都是放在/packages/apps/setting 下的。但是看 \packages\apps\Settings\res\xml\settings.xml 中:

  1.     <PreferenceScreen android:key="call_settings"
             android:title="@string/call_settings_title" 
        android:summary="@string/call_settings_summary">
        <intent android:action="android.intent.action.MAIN"
             android:targetPackage="com.android.phone"         
                     android:targetClass="com.android.phone.CallFeaturesSetting" />
         </PreferenceScreen>



从这里就可以知道,android 的call setting 的包指向了 phone,并且知道了入口是 CallFeaturesSetting 类。
    在/packages/apps/Phone/res/call_featrue_setting.xml 中有call setting 的界面布局:

    
        

  1. <PreferenceScreen android:key="button_more_expand_key" 
             android:title="@string/labelMore" android:persistent="false">
              ...
            <ListPreference android:key="button_clir_key" ... />



    这个button_clir_key就是对应的 caller ID 的那个按钮,从这里可以看出是一个ListPreference,点击会出现一个列表框。里面出现的内容布局都在这里定义。相关的xml档都在/packages/apps/Phone/res 下。
    接着就是AP的代码了,在/packages/apps/Phone/src 下。前面说了入口是 CallFeaturesSetting:

  1. public class CallFeaturesSetting extends PreferenceActivity {
              …
              private PreferenceScreen mSubMenuFDNSettings;

              private ListPreference mButtonCLIR;

              private CheckBoxPreference mButtonCW;
            ...
            protected void onCreate(…) {
              …
              PreferenceScreen prefSet = getPreferenceScreen();

                  mButtonCLIR  =   (ListPreference) prefSet.findPreference(BUTTON_CLIR_KEY);
            ...



      定义的 mButtonCLIR 就是对应caller ID 的变量。在onCreate中初始化,用findPreference来找到XML中对应的资源。然后是对这个按钮的响应代码:

  1. public boolean onPreferenceChange(Preference preference, Object objValue){

             if (preference == mButtonCLIR) {

                handleCLIRClickRequest(mButtonCLIR.findIndexOfValue((String) objValue));

            ...

        }

        private void handleCLIRClickRequest(int i) {
          …
              mPhone.setOutgoingCallerIdDisplay(i,Message.obtain(mSetOptionComplete, EVENT_CLIR_EXECUTED));

        }



可以看到最终是调用 mPhone.setOutgoingCallerIdDisplay 来完成真正的设定。这个 mPhone 是

com.android.internal.telephony.Phone,mPhone 的调用就进入 framework 层了。

Framework层:

    相关的代码在/frameworks/base/telephony/java 中。先从 Phone 开始,这是一个 interface,真正实现是在

com.android.internal.telephony.gsm.GSMPhone 中:

    

  1. public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, Message onComplete) {
                mCM.setCLIR(commandInterfaceCLIRMode,
                        h.obtainMessage(EVENT_SET_CLIR_COMPLETE, commandInterfaceCLIRMode, 0, onComplete));
            }



    这里是调用 mCM.setCLIR。mCM 是一个 CommandsInterface,真正实现是在 RIL.java 文件中。这下到了framework中

真正办实事的地方。同样是在com.android.internal.telephony.gsm 下,RIL类中:

        

  1. public void setCLIR(int clirMode, Message result)
            {
                RILRequest rr = RILRequest.obtain(RIL_REQUEST_SET_CLIR, result);
                rr.mp.writeInt(1);
                rr.mp.writeInt(clirMode);
                

            ...
                send(rr);
            }



    这里顺便说一下,RIL与底层是用socket来通信。所以send(rr)最终是把RIL_REQUEST_SET_CLIR发给底层,底层会有一个守护

进程来接收framework层的信息,并且把结果传达上去。继续看下send的代码:

    

  1. private void  send(RILRequest rr)
            {
                Message msg;
                msg = mSender.obtainMessage(EVENT_SEND, rr);
                acquireWakeLock();
                msg.sendToTarget();
            }



    是发一个EVENT_SEND的message给系统。那么找这个 handle 这个 message 的地方,还是同一个文件里,RIL.RILSender类

里面的handleMessage:

    

  1. public void  handleMessage(Message msg)

        {

            RILRequest rr = (RILRequest)(msg.obj);

            switch (msg.what) {
                    case EVENT_SEND:

                            LocalSocket s;
                            s = mSocket;

                ...
                            byte[] data;
                            data = rr.mp.marshall();
                            rr.mp.recycle();
                            rr.mp = null;
                            // parcel length in big endian
                            dataLength[0] = dataLength[1] = 0;
                            dataLength[2] = (byte)((data.length >> 8) & 0xff);
                            dataLength[3] = (byte)((data.length) & 0xff);
                            s.getOutputStream().write(dataLength);                    
                            s.getOutputStream().write(data);

        ...


    这里的mSocket 在就是与底层沟通的socket,有兴趣可以看看相关代码。

    到这里 framework 层也算告一段落,在下去就是底层的C部分了。放在下一篇文章在写吧。

////////////////////////////////////////////////////////////////////

 1. PhoneInterfaceManager.java: Implementation of the ITelephony interface.

        //PhoneInterfaceManager 是电话接口的实现。其中的一些public的接口是为第三方应用留下的。  像我们打电话的代码中,从DialtActivity.java->TwelvKeyDialer.java->OutgoingBroadcaster.java->......->InCallScreen.java,是自己写的,自己是这样调用的! 第三方也可以直接用PhoneInterfaceManager.java中的接口dial和call,来进入InCallScreen.java打电话!我当时有一个这样的疑问:我自己在打电话的时候,从outgoingCallBroader.java中有intent指向InCallScreen.java
,然后在 PhoneInterfaceManager.java当打电话的时候,也有intent指向IncallScreen。我当时就是不太明白为什么会这样,现在明白了,这些接口主要是给第三方用的,第三方可能会用到这些接口,别人也需要在写程序的时候,调用这些接口,进而走到InCallScreen.java.至于我自己打电话的时候,自己都知道肯定会指向的 InCallScreen.java!    

2.  PhoneFactory.java 用来提供一个Phone实例!

3. TelephneManager.java:  Provides access to information about the telephony services on the device. Applications can use the methods in this class to determine
telephony services and states, as well as to access some
 types of subscriber information. Applications can also register a listener to receive notification of telephony state changes

    提供对设备上的电话服务进行访问。Application可以使用这个类中的这个方法来确定电话服务和状态,也用来访问一些用户信息。Application也可以注册一个Listener来接受电话状态该改变的通知!
4.PhoneApp.java: Top-level Application class for the Phone app
      提供的是电话应用最上层的应用类,只要是与电话相关的都属于这个类上面的
PhoneInterfaceManager.java,PhoneFactory.java,以及TelephneManager.java都属于
       
对PhoneApp.java的一点介绍:作为电话应用的最上层,在PhoneApp.java的on
create()
中,首先,如果没有创建phone,就调用PhoneFactory.makeDefaultPhones 来创建一个默认的phone,然后通过phone=PhoneFactory.getPhoneById来取得创建的phone,接着利用这个phone来实例化phoneInterfaceManager,即phoneMgr
= new PhoneInterfaceManager(this, phone);在static Intent createInCallIntent(int phoneid)中设定如果是来电的话,也就是打电话进来时,intent到InCallScreen.java.当时我有一个疑问,为什么在PhoneApp.javj中只有一个来电的intent,而没有去电的Intent?其实我好笨阿,要想去电的话,首先得拨号,然后再打电话,所以再看一下代码,就豁然开朗了:开始的时候已经
实例化phoneInterfaceManager,她就是实现电话接口,在这里面很容易就找到了public
void dial(String number)和public void call(String number)。

本文转自:http://android.tgbus.com

1. ITelephony接口和ISms接口以及AIDL
 在我们的Android应用中,当需要实现电话拨号时,我们需要进行如下调用
 ITelephony phone = (ITelephony)ITelephony.Stub.asInterface(ServiceManager.getService("phon"))
 phone.dial("10086");
   对于短信应用,我们需要的是调用SmsManager,代码如下
   SmsManager manager = SmsManager.getDefault();
   manager.sendTextMessage("10086",null,"hi,this is sms",null,null);
   这里,SmsManager对ISms做了一层包装,实质上是通过调用
   ISms simISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
   simISms.sendRawPdu....
   
  可以看到,应用都是采用AIDL来实现IPC的跨进程调度。
  对于AIDL应用,调用进程方存在的是一个实现接口的Proxy对象,通过Proxy对象与被调用进程中的Stub对象进行
  通讯来实现IPC的跨进程调度,所以,在被调用进程一端必定有一个ITelephony.Stub类以及ISms.Stub类的实现。

  2. PhoneInterfaceManager和SimSmsInterfaceManager
   ITelephony.Stub 的实现类为com.android.phone.PhoneInterfaceManager
   ISms.Stub的实现类为com.android.internal.telephony.gsm.SimSmsInterfaceManager
   从这两个类的构造器的调用代码里可以很清楚的看到进行了Service的注册工作
   ServiceManager.addService("phone",this);
   ServiceManager.addService("isms",this);

  3. PhoneApp,InCallScreen,PhoneUtils及其他相关类
  从SimSmsInteferManager的相关方法实现中可以看到,具体就是调用GSMPhone的SmsDispatcher实例来进行相关操作的。
  从PhoneInterfaceManager会维持一个Phone对象的引用,当拨号应用时,PhoneInterfaceManager会将构造好的Intent传递
给PhoneApp应用,该Intent的className指定则为InCallScreen,从中我们可以看到InCallScreen具体是通过PhoneUtils调用Phone的
相关方法来实现。
  PhoneInterfaceManager怎么获取到对应的Phone对象,然后又怎么将Phone对象传递到InCallScreen中呢?
  具体这里涉及到了PhoneApp这个类,从这个类维护了一个 PhoneInterfaceManager的引用(phoneMgr)以及一个Phone引用(phone),
从该类的onCreate方法中我们可以清楚的看到,PhoneApp通过PhoneFactory获取了一个Phone实例,并通过该实例实现了PhoneInterfaceManager对象。
因此,我们现在只需要关注PhoneFactory具体提供的是一个什么样的Phone实例了。
  另外,PhoneApp类还提供了一个静态方法getInstance供InCallScreen调用,InCallScreen正是通过调用该方法获得PhoneApp实例从而
获得对应的Phone实例的。
  接下来,我们通过查看PhoneFactory的方法可以看到,Phone对象对应的就是一个GSMPhone实例。

  4。GSMPhone与RIL
  从GSM的构造器可以看出,他依赖一个CommandInterface接口实例,通过PhoneFactory的makeDefaultPhones方法,我们可以看到,根据系统环境变量
ro.radio.noril来判断是否需要采用RIL框架实现,如果该参数不为空,则采用Simultedcommands(主要是为了测试需要提供的模拟实现).否则,采用RIL。
  通过Google才知道,RIL其实是智能手机上实现AP与BP之间通信的一种设计思想,具体大家可以参见这篇文章http://www.eetchina.com/ARTICLES/2006OCT/PDF/CPCOL_2006OCT26_EMB_TA_170.PDF?SOURCES=DOWNLOAD
  在RIL.java 中我们很惊喜的看到,RIL对对消息的处理是将消息通过LocalSocket发送到以rild为名称的有名端口。这个有名Socket的创建在ril.cpp代码中。
  s_fdListen = android_get_control_socket(SOCKET_NAME_RIL)
  原来Android通话和发短信的应用是JAVA与C++代码之间透过Socket连接来传输消息来实现的。

  5.关于C代码与硬件之间的交互
  这部分工作其实就是C代码通过串口发送AT指令来拨号,收发短信。今天有点累了,具体的实现下次我再分析。

///////////////////////////////////////////////////////////////////////////

CallCard.java----->void updateState(Phone phone)----->根据当点电话的状态选择执行下列更新函数,1,updateRingCall(phone)/ 2,updateForegroundCall(phone)/ 3, updateNoCallphone()

    1,
        updateRingCall(phone)----->a, displayMainCallStatus(phone, ringingCall)  && b, displayOnholdingCallStatus(phone, bgCall) &&  c, displayOngoingCallStatus(phone, fgoingCall)
        a, displayMainCallStatus(phone ringingCall)----->{假如无来电,返回, 确定是否横屏状态,蓝牙状态, 如果当前电话已经接通,根据横屏状态和蓝牙状态拿到当前CallCard背景图片资>源,即callCardBackgroundResid, 更新时钟信息,就是打电话的时候屏幕下方计时的时钟, 而如果是保持状态,挂断状态(DISCONNECTED),拨打等待(DIALING)状态,警告状态(ALERTING),来电状态(INCOMING),等待状态(WAITING),也拿到对应的callCardBackgroundResid,
取消计时,空闲状态下,什么也不做 }, 设置好callCardBackgroundResid(就是装头像的那个背景)后,然后进入updat
eCallCardTitleWidgets(Phone phone, Call call), 设置一些widget, getTitleForCallCard(call), 给当前状态找一个条题目,比如“正在拨号”“来电”“当前通话”等等, {如果当前是的Call是激活的也就是接通的,根据蓝牙状态给当前通话找一个图标,设置文字颜色,如果是挂断状态,也配置好图标和字串显示在屏幕上,然后根据挂断与否,显示时钟},到这里为止,显示的都是背景阿,文字什>么的, 当前通话人的信息,比如头像名字还没找出来,接写来就干这个了,
如果当前是会议通话,更新会议界面,否则查找个人信息,如相片,电话号码,名字等,显示在界面上不详细解释.
        b,c 不详细解释
    2,
        updateForgroundCall(phone), 如果当前电话空闲,且有新连接,则displayMainCallStatus(), 然后执行1里面的动作
    3,
        updateNoCallPhone, 也是执行,1里面的三个更新函数,只不过,不同状态下,参数不一样,比如电话在完全空闲状态下,没有新来电,也没有挂起的电话,也没有去电,则参数,ringCall, bgCall, ongoingCall 都为null.

 

源代码如下:

void updateState(Phone phone) {
        if (DBG) log("updateState(" + phone + ")...");

        // Update some internal state based on the current state of the phone.
        // TODO: This code, and updateForegroundCall() / updateRingingCall(),
        // can probably still be simplified some more.

        Phone.State state = phone.getState();  // IDLE, RINGING, or OFFHOOK
        if (state == Phone.State.RINGING) {
            // A phone call is ringing *or* call waiting
            // (ie. another call may also be active as well.)
            updateRingingCall(phone);
        } else if (state == Phone.State.OFFHOOK) {
            // The phone is off hook. At least one call exists that is
            // dialing, active, or holding, and no calls are ringing or waiting.
            updateForegroundCall(phone);
        } else {
            // The phone state is IDLE!
            //
            // The most common reason for this is if a call just
            // ended: the phone will be idle, but we *will* still
            // have a call in the DISCONNECTED state:
            Call fgCall = phone.getForegroundCall();
            Call bgCall = phone.getBackgroundCall();
            if ((fgCall.getState() == Call.State.DISCONNECTED)
                || (bgCall.getState() == Call.State.DISCONNECTED)) {
                // In this case, we want the main CallCard to display
                // the "Call ended" state.  The normal "foreground call"
                // code path handles that.
                updateForegroundCall(phone);
            } else {
                updateNoCall(phone);
            }
        }
    }

一个新来电是由CallNotifier监听到的,CallNotifier类继承与Handler,在CallNotifier.java里面,代表新来点的Message是PHONE_NEW_RINGING_CONNECTION。

mPhone.registerForNewRingingConnection(this, PHONE_NEW_RINGING_CONNECTION, null);

当然,得注册这个信号。有新来电时,CallNotifier收到这个新号,交由onNewRingingConnection((AsyncResult) msg.obj)来处理

在onNewRingingConnection()内,

boolean provisioned = Settings.Secure.getInt(mPhone.getContext().getContentResolver(),
            Settings.Secure.DEVICE_PROVISIONED, 0) != 0;
查询是否设置了拒接电话,如果是,则直接挂断电话。然后,设置音频为响铃状态,通过startIncomingCallQuery(Connection c)开始查询来电信息。

在startincomingCallQuery()里面,先判定是否能查询,如果不是,直接启动来电界面,否则,继续查询来电人的信息,比如对应铃声等,查询完以后,启动来电界面,即调用displayCallScreen();

 

启动来电界面以后,电话控制权就完全交由InCallScreen.java, 但是到现在为止,电话还是没有接通,只是通知了有来电,这就是,CallNotifier.java完成的任务,跟他的名字一样,只是起到Notify的作用。在来电界面,InCallScreen.java监听用户的Key Event, 如果按下的是接听键,则接听电话,如果是挂机键,就挂断电话。

 

按下接听键, CallNotifier会收到一个PHONE_STATE_CHANGED的信号,如果按下,挂机键,会收到一个PHONE_STATE_DICONNECT,如果接听,则设置音频状态为接听电话状态,停止响铃,放置一个接电话的图标在屏幕上,与此同时,InCallScreen也会收到这样一个新号,它做的事情就是更新通话界面,比如点亮屏幕,使菜单消失等等。 但是如果挂断电话,那做的是就是更新通话记录,停止响铃等。

////////////////////////////////////////////////////////////

根据:《Android 源码分析-打电话和发短信》一文(时间:2008-12-24 00:28来源:Android 开发者 作者:wsshy 点击: 2275次)

得知,智能手机的打电话功能是由RIL部分来实现的,见下图:

Linux手机打电话代码分析(Android) - clarkluo2004 - 天翼的博客

 

开始分析Android源代码中的RIL部分。

又上图,以及其他相关资料,我得知在Android中有一个叫rild的守护进程。我猜测此进程与电话的拨打接听有莫大关系。

而且在Android系统中存在这么一个rild的可执行文件,源代码中的"hardware/ril/rild"目录下有rild.c的文件 ,且在rild.c中,我们找到了main函数,即我们已经找到了rild守护进程的程序入口啦~

自赞一个先~

开始分析rild守护进程的代码。

在代码开始部分,有一些关于参数解析的片段,暂时先撇开一边,先讲一下rild守护进程的关于RIL的一些重要流程:

main()

{//省略n行

RIL_startEventLoop();

//省略n行

}

          从名字上看就应该觉得这应该是一个起点——"startEventLoop"——一个开始进入时间循环的一点,让我们跟踪进去看看^_^

在"rild.c"中有这么一行:extern void RIL_startEventLoop();

说明RIL_startEventLoop函数的代码还在别处,经查找,发现是在这里:

"hardware\ril\libril"目录下的Ril.cpp文件中。

Get it~

在Ril.cpp中的RIL_startEventLoop中有这么一行:

ret = pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL);

看来Android是在这里开辟一个线程来执行eventLoop循环,

这个eventLoop函数也在这个文件里(Ril.cpp)。

 

eventLoop中,主要执行了:

    ril_event_init();

    ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true,

                processWakeupCallback, NULL);

    ril_event_add (&s_wakeupfd_event);

    ril_event_loop();

 

由函数名可猜测:

ril_event_set使用了新建一个ril事件的,

而ril_event_add 将该新事件添加进某执行队列中。

最后,在循环ril_event_loop中进行一个轮询,捕获事件,进而完成事件处理。

 

经过对ril_event_set和ril_event_add的代码阅读,证实了之前的两点猜测,

(ril_event_set和ril_event_add以及ril_event_loop函数代码在"hardware\ril\libril"目录下的ril_event.cpp中)

新事件加入了一个叫watch_table的数组中。

 

而 ril_event_loop则调用了一个select函数,目前还在分析该函数中~~(猜测是unix类系统的系统调用,暂时先放过)

 

重新从eventloop的流程开始分析起:

首先,是那个ril_event_init函数。ril_event_init函数在Ril_event.cpp("hardware\ril\libril"),Ril_event.cpp中有一个timer_list的ril_event结构体,这个结构体充当待处理的事件队列(I guest)

而ril_event_init就是在做事件队列的初始化工作(通过init_list(&timer_list),当然还有另外还初始化了pending_list)

然后,就是ril_event_set一个事件结构s_wakeupfd_event

接着,就是ril_event_add该s_wakeupfd_event结构体添加到Ril_event.cpp的watch_table数组中。

最后就是执行ril_event_loop循环了。

 

请注意,以上步骤中并没有将事件添加到事件队列(timer_list)中的部分,但是ril_event_loop的运作就是要基于timer_list的,那事件队列不是空的吗?怎么会这样呢?

在查看了相关代码之后,发现了有一个叫ril_timer_add的函数执行了addToList函数,即猜测应该是某个函数调用了ril_timer_add?是什么函数呢?通过用Source Insight查找函数的caller,发现了internalRequestTimedCallback函数调用了ril_timer_add。从名字我想起了关键一点:当前流程只是用来“处理”电话事件而已,并不是自己生成一个电话事件啊,电话事件应该是由此流程外的对象生成的(比如有来电了,又如要打电话了),用中断来进行事件队列的事件添加。

 

到此为止,我们已经确认了rild的主要监听功能就是在ril_event_loop中:

其中在ril_event_loop的for (;;)循环中,我们看到了if (-1 == calcNextTimeout(&tv)),这里就是在尝试处理电话事件啦^_^。

////////////////////////////////////////////////////////////

Android 的
call setting 是用来设定与 simcard 相关的一些内容的应用程序,如网络,PIN等等,算是AP层。这里就选择其中一个项从源代码读下去直到底层,看看大概的结构和流程。

    在 Android 主菜单中选择 setting->call setting->additional call setting->caller ID,会弹出来一个对话框来选择,这个项是用来设定在用电话本拨打电话的时候是否显示对方的电话号码。这里就以这个设定为例来一步步读下去。
AP层:
    call setting 的代码和资源都是放在/packages/apps/Phone 的目录下。其实 Android 的 setting AP 相关的资源都是放在/packages/apps/setting 下的。但是看 \packages\apps\Settings\res\xml\settings.xml 中:

  1.     <PreferenceScreen android:key="call_settings"
  2.          android:title="@string/call_settings_title"
  3.     android:summary="@string/call_settings_summary">
  4.     <intent android:action="android.intent.action.MAIN"
  5.          android:targetPackage="com.android.phone"        
  6.                  android:targetClass="com.android.phone.CallFeaturesSetting" />
  7.      </PreferenceScreen>



从这里就可以知道,android 的call setting 的包指向了 phone,并且知道了入口是 CallFeaturesSetting 类。
    在/packages/apps/Phone/res/call_featrue_setting.xml 中有call setting 的界面布局:

    
        

  1. <PreferenceScreen android:key="button_more_expand_key"
  2.          android:title="@string/labelMore" android:persistent="false">
  3.           ...
  4.         <ListPreference android:key="button_clir_key" ... />



    这个button_clir_key就是对应的 caller ID 的那个按钮,从这里可以看出是一个ListPreference,点击会出现一个列表框。里面出现的内容布局都在这里定义。相关的xml档都在/packages/apps/Phone/res 下。
    接着就是AP的代码了,在/packages/apps/Phone/src 下。前面说了入口是 CallFeaturesSetting:

抱歉!评论已关闭.