Android 5.1 Phone MT(来电)流程分析(Framework层)

写在前面的话

本文主要分析Android 接电话的流程,研究的代码是Android 5.1的,现在我们只关注framework层,以CDMA为例,GSM同理。
关于应用层的流程,请看《Android 5.1 Phone MT(来电)流程分析(应用层)》。



(如果图片看不清的话,可以右键选择在新标签中打开图片,或者把图片另存到自己电脑再查看。)


http://blog.csdn.net/linyongan


一、显示来电的界面

步骤1和2: RIL.java的processUnsolicited()方法
接电话的流程是由底层传送到应用层的。首先RIL.java接收到RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED消息,我们进入RIL.java里查找RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED的消息的处理逻辑,在 RIL.java 文件里有两个方法processUnsolicited()和responseToString()进行该消息的处理。我们重点关注 processUnsolicited ()方法,该方法会对底层传过来的数据进行收集和整理,然后再完成对应response的逻辑处理和消息通知

private void processUnsolicited (Parcel p) {
    ...
    try {switch(response) {
    ...
    case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED: 
    ret =  responseVoid(p); break;
    ...
    }
    switch(response) {
    ...
    case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED:
         if (RILJ_LOGD) 
         unsljLog(response);//打印log日志
         //发出通知(RegistrantList消息处理机制)
         mCallStateRegistrants.notifyRegistrants(new 
         AsyncResult(null, null, null));
    ...
    }
}

知识点解析:谁会接受到RIL.java发出的Call状态变化的通知呢?
要找出mCallStateRegistrants的调用者(在Source Insight这个编译器中,选中mCallStateRegistrants,然后按快捷键Ctrl+/),找到BaseCommands.java的registerForCallStateChanged()方法,接着继续找它的调用者,最后我们来到 CdmaCallTracker.java

public CdmaCallTracker(CDMAPhone phone) {
      ...
      mCi.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null);
      ...
}

发觉是CdmaCallTracker.java向RIL注册了一个EVENT_CALL_STATE_CHANGE类型的Handler消息。


步骤3: 因此,我们在 CdmaCallTracker.java 的handleMessage()方法里可以找到响应EVENT_CALL_STATE_CHANGE消息类型的处理逻辑,如下:

 public void
     handleMessage (Message msg) {
     ...
     case EVENT_CALL_STATE_CHANGE:
          //调用父类CallTracker查询Call List方法
          pollCallsWhenSafe();
     break;
     ...
}

pollCallsWhenSafe()方法是在它的父类CallTracker.java中实现的。

步骤4和5:下面我们来到 CallTracker.java 的pollCallsWhenSafe()方法里。

protected void pollCallsWhenSafe() {
        ...
        if (checkNoOperationsPending()) {
        //注意mLastRelevantPoll对象的消息类型,后面会用到
            mLastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);
            mCi.getCurrentCalls(mLastRelevantPoll);
        }
}

在这里通过obtainMessage()创建了一个消息类型为EVENT_POLL_CALLS_RESULT的Message,并且作为参数传递到RIL.java的getCurrentCalls()方法里。

步骤6: RIL.java的getCurrentCalls()方法
mCi是RIL.java的实例对象,这也就回到了 RIL.java 的getCurrentCalls()方法里,它将RIL_REQUEST_GET_CURRENT_CALLS 消息封装成RILRequest 类型并发送。

    public void getCurrentCalls (Message result) {
        //注意rr对象的消息类型,后面会用到
        RILRequest rr = RILRequest.obtain(
        RIL_REQUEST_GET_CURRENT_CALLS, result);
        //打印log日志
        if (RILJ_LOGD) 
        riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
        send(rr);
    }

步骤7和8: RIL.java的processSolicited()方法
RIL向底层发送了查询Call List的请求,底层处理完成之后,就会把处理的结果返回给RIL,RIL.java 有三处接收处理RIL_REQUEST_GET_CURRENT_CALLS消息,真正的逻辑处理在 processSolicited ()方法里

private RILRequest processSolicited (Parcel p) {
        ...
        case RIL_REQUEST_GET_CURRENT_CALLS: 
        ret =  responseCallList(p); break;
        ...
        //打印log日志
        if (RILJ_LOGD) riljLog(rr.serialString() + "< " + 
        requestToString(rr.mRequest)
                    + " " + retToString(rr.mRequest, ret));
        if (rr.mResult != null) {
            AsyncResult.forMessage(rr.mResult, null, tr);
            rr.mResult.sendToTarget();//发出handler消息通知
}

responseCallList()方法会对数据进行收集整理,返回Object类型的ret对象。注意:此时Call的状态为 INCOMING

步骤9: CdmaCallTracker.java中的handleMessage()方法
rr.mResult.sendToTarget()发出handler消息通知后,会在 CdmaCallTracker.java 中的handleMessage()方法中响应。并且它的消息类型是EVENT_POLL_CALLS_RESULT(在本文的第2个小标题的末尾提到)。这里根据Message获取传递的Object数据对象,再调用handlePollCalls处理数据

public void handleMessage (Message msg) {
        ...
        switch (msg.what) {
            case EVENT_POLL_CALLS_RESULT:{
                //打印log日志
                Rlog.d(LOG_TAG, "Event EVENT_POLL_CALLS_RESULT Received");
                ar = (AsyncResult)msg.obj;

                if(msg == mLastRelevantPoll) {
                    if(DBG_POLL) log(
                            "handle EVENT_POLL_CALL_RESULT: set needsPoll=F");
                    mNeedsPoll = false;
                    mLastRelevantPoll = null;
                    handlePollCalls((AsyncResult)msg.obj);
                }
            }
       break;
       ...
}

步骤10: handlePollCalls()方法根据RIL发出的Call List对象,判断Call的状态并发出通知,这里发出的是新来电通知Phone.notifyNewRingingConnection

protected void
    handlePollCalls(AsyncResult ar){
    ...
    if (newRinging != null) {
    mPhone.notifyNewRingingConnection(newRinging);
    ...
}

步骤11: CDMAPhone.java的notifyNewRingingConnection()方法

void notifyNewRingingConnection(Connection c) {
        /* we'd love it if this was package-scoped*/
        super.notifyNewRingingConnectionP(c);
    }

这里调用了父类PhoneBase.java 的方法。

**步骤12:**PhoneBase.java的notifyNewRingingConnectionP()方法

    /**
     * Notify registrants of a new ringing Connection.
     * Subclasses of Phone probably want to replace this with a
     * version scoped to their packages
     */
    protected void notifyNewRingingConnectionP(Connection cn) {
        if (!mIsVoiceCapable)
            return;
        AsyncResult ar = new AsyncResult(null, cn, null);
        mNewRingingConnectionRegistrants.notifyRegistrants(ar);
    }

继续发出来电通知。
在PstnIncomingCallNotifier.java的registerForNotifications()方法里看到

    /**
     * Register for notifications from the base phone.
     * TODO: We should only need to interact with the phoneproxy directly. However,
     * since the phoneproxy only interacts directly with CallManager we either listen to callmanager
     * or we have to poke into the proxy like this.  Neither is desirable. It would be better if
     * this class and callManager could register generically with the phone proxy instead and get
     * radio techonology changes directly.  Or better yet, just register for the notifications
     * directly with phone proxy and never worry about the technology changes. This requires a
     * change in opt/telephony code.
     */
    private void registerForNotifications() {
        Phone newPhone = mPhoneProxy.getActivePhone();
        if (newPhone != mPhoneBase) {
            unregisterForNotifications();

            if (newPhone != null) {
                Log.i(this, "Registering: %s", newPhone);
                mPhoneBase = newPhone;
                mPhoneBase.registerForNewRingingConnection(
                        mHandler, EVENT_NEW_RINGING_CONNECTION, null);
                mPhoneBase.registerForCallWaiting(
                        mHandler, EVENT_CDMA_CALL_WAITING, null);
                mPhoneBase.registerForSuppServiceNotification(
                        mHandler, EVENT_SUPP_SERVICE_NOTIFY, null);
                mPhoneBase.registerForUnknownConnection(mHandler, EVENT_UNKNOWN_CONNECTION,
                        null);
            }
        }
    }

是在这里注册监听了EVENT_NEW_RINGING_CONNECTION,因此PhoneBase.java发出的来电通知会被PstnIncomingCallNotifier.java处理(在Android5.0之前是由CallManager.java来处理)。

步骤13: PstnIncomingCallNotifier.java里mHandler的handleMessage()方法。PstnIncomingCallNotifier.java是在packages\services\telephony\src\com\android\services\telephony目录下的,这里已经来到了应用层,本文暂且分析到这里;在应用层还有很长的流程,详情请看《Android 5.1 Phone MT(来电)流程分析(应用层)》。


二、响铃

步骤14和15: 底层上报RIL_UNSOL_CALL_RING消息,由RIL.java的processUnsolicited()来处理

private void processUnsolicited (Parcel p) {
    ...
    try {switch(response) {
    ...
    case RIL_UNSOL_CALL_RING: 
    ret =  responseVoid(p); break;
    ...
    }
    switch(response) {
    ...
    case RIL_UNSOL_CALL_RING:
         if (RILJ_LOGD) 
         unsljLog(response);//打印log日志
         //发出通知
         if (mRingRegistrant != null) {
         mRingRegistrant.notifyRegistrant(
                         new AsyncResult (null, ret, null));
         }
    ...
    }
}

在PhoneBase.java的构造方法中看到

mCi.setOnCallRing(this, EVENT_CALL_RING, null);

所以RIL.java发出响铃的通知会通知到PhoneBase.java。

步骤16: PhoneBase.java的的handleMessage()方法

    @Override
    public void handleMessage(Message msg) {
      ...
      switch(msg.what) {
            case EVENT_CALL_RING:
                Rlog.d(LOG_TAG, "Event EVENT_CALL_RING Received state=" + getState());
                ar = (AsyncResult)msg.obj;
                if (ar.exception == null) {
                    PhoneConstants.State state = getState();
                    if ((!mDoesRilSendMultipleCallRing)
                            && ((state == PhoneConstants.State.RINGING) ||
                                    (state == PhoneConstants.State.IDLE))) {
                        mCallRingContinueToken += 1;
                        sendIncomingCallRingNotification(mCallRingContinueToken);
                    } else {
                        notifyIncomingRing();
                    }
                }
     break;
     ...
 }

此时如果没有报异常,而且Call的状态是RINGING,则进入sendIncomingCallRingNotification()方法里。

步骤17和18: PhoneBase.java的的sendIncomingCallRingNotification()方法

    /**
     * Send the incoming call Ring notification if conditions are right.
     */
    private void sendIncomingCallRingNotification(int token) {
        if (mIsVoiceCapable && !mDoesRilSendMultipleCallRing &&
                (token == mCallRingContinueToken)) {
            Rlog.d(LOG_TAG, "Sending notifyIncomingRing");
            notifyIncomingRing();
            sendMessageDelayed(
                    obtainMessage(EVENT_CALL_RING_CONTINUE, token, 0), mCallRingDelay);
        } else {
            Rlog.d(LOG_TAG, "Ignoring ring notification request,"
                    + " mDoesRilSendMultipleCallRing=" + mDoesRilSendMultipleCallRing
                    + " token=" + token
                    + " mCallRingContinueToken=" + mCallRingContinueToken
                    + " mIsVoiceCapable=" + mIsVoiceCapable);
        }
    }

在这里可以看到,除了调用notifyIncomingRing()方法发出来电响铃通知,还调用sendMessageDelayed()发送一个消息类型为EVENT_CALL_RING_CONTINUE的Message。

步骤19: PhoneBase.java的的handleMessage()方法

    @Override
    public void handleMessage(Message msg) {
      ...
      switch(msg.what) {
      case EVENT_CALL_RING_CONTINUE:
          Rlog.d(LOG_TAG, "Event EVENT_CALL_RING_CONTINUE Received stat=" + getState());
          if (getState() == PhoneConstants.State.RINGING) {
              sendIncomingCallRingNotification(msg.arg1);
          }
      break;
   }

步骤20: 如果Call的状态是RINGING,就重复调用sendIncomingCallRingNotification()方法,重复步骤17~19的流程,直到Call的状态变成OFFHOOK,则响铃这段流程就结束。


三、用户接听电话

步骤21:接听电话的流程是由UI界面一直传递到Framework层,在应用层的流程中,最后是由TelephonyConnection.java传递给Framework层,它调用了CDMAPhone.java的acceptCall()方法

    @Override
    public void
    acceptCall(int videoState) throws CallStateException {
        ImsPhone imsPhone = mImsPhone;
        if ( imsPhone != null && imsPhone.getRingingCall().isRinging() ) {
            imsPhone.acceptCall(videoState);
        } else {
            mCT.acceptCall();
        }
    }

mCT就是CdmaCallTracker。

步骤22和23: CdmaCallTracker.java的的acceptCall()方法

    void acceptCall() throws CallStateException {
        if (mRingingCall.getState() == CdmaCall.State.INCOMING) {
            Rlog.i("phone", "acceptCall: incoming...");
            // Always unmute when answering a new call
            setMute(false);
            mCi.acceptCall(obtainCompleteMessage());
        } else if (mRingingCall.getState() == CdmaCall.State.WAITING) {
            CdmaConnection cwConn = (CdmaConnection)(mRingingCall.getLatestConnection());

            // Since there is no network response for supplimentary
            // service for CDMA, we assume call waiting is answered.
            // ringing Call state change to idle is in CdmaCall.detach
            // triggered by updateParent.
            cwConn.updateParent(mRingingCall, mForegroundCall);
            cwConn.onConnectedInOrOut();
            updatePhoneState();
            switchWaitingOrHoldingAndActive();
        } else {
            throw new CallStateException("phone not ringing");
        }
    }

    /**
     * Obtain a message to use for signalling "invoke getCurrentCalls() when
     * this operation and all other pending operations are complete
     */
    private Message
    obtainCompleteMessage() {
        return obtainCompleteMessage(EVENT_OPERATION_COMPLETE);
    }

通过obtainCompleteMessage()方法创建一个消息类型为EVENT_OPERATION_COMPLETE的Message,再传递给RIL.java的acceptCall()方法。

步骤24: RIL.java的的acceptCall()方法

    @Override
    public void
    acceptCall (Message result) {
        RILRequest rr
                = RILRequest.obtain(RIL_REQUEST_ANSWER, result);

        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));

        send(rr);
    }

RILJ向底层发送了RIL_REQUEST_ANSWER请求。
之后的流程相信大家都很熟悉了。
步骤25: 底层回应了RILJ的RIL_REQUEST_ANSWER请求,接着通知CDMACallTracker来处理。
步骤26~30: CDMACallTracker处理之后,调用RIL.java的getCurrentCalls()请求查询Call的状态列表。
步骤31: 底层返回Call的状态列表,接着通知CDMACallTracker来处理。注意:此时Call的状态为 ACTIVE
步骤32~36: CDMACallTracker发出Call状态已改变的通知,向应用层传递,在应用层也有很长的流程,本文就不详细说了,详情请看《Android 5.1 Phone MT(来电)流程分析(应用层)》。
步骤37~39: 重复!!!底层又上报RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED消息,CDMACallTracker接收到之后,调用RIL.java的getCurrentCalls()请求查询Call的状态列表;底层返回Call的状态列表,接着通知CDMACallTracker来处理;CDMACallTracker发出Call状态已改变的通知,向应用层传递。


最后贴出了来电流程的log片段

10-13 14:07:55.724 D/RILJ    ( 3102): [UNSL]< UNSOL_RESPONSE_CALL_STATE_CHANGED [SUB0]
10-13 14:07:55.725 D/RILJ    ( 3102): [2401]> GET_CURRENT_CALLS [SUB0]
10-13 14:07:55.811 D/RILJ    ( 3102): [2401]< GET_CURRENT_CALLS 
 [id=1,INCOMING,toa=129,norm,mt,0,voc,noevp,,cli=1,,1]  [SUB0]
10-13 14:07:55.823 D/RILJ    ( 3102): [UNSL]< UNSOL_CALL_RING [C@184b4a77 [SUB0]
10-13 14:08:21.799 D/RILJ    ( 3102): [2417]> SET_MUTE false [SUB0]
10-13 14:08:21.807 D/RILJ    ( 3102): [2418]> ANSWER [SUB0]
10-13 14:08:21.814 D/RILJ    ( 3102): [2417]< SET_MUTE  [SUB0]
10-13 14:08:22.170 D/RILJ    ( 3102): [2418]< ANSWER  [SUB0]
10-13 14:08:22.185 D/RILJ    ( 3102): [UNSL]< UNSOL_RESPONSE_CALL_STATE_CHANGED [SUB0]
10-13 14:08:22.187 D/RILJ    ( 3102): [2420]> GET_CURRENT_CALLS [SUB0]
10-13 14:08:22.216 D/RILJ    ( 3102): [2419]< GET_CURRENT_CALLS  
[id=1,ACTIVE,toa=129,norm,mt,0,voc,noevp,,cli=1,,1]  [SUB0]
10-13 14:08:22.248 D/RILJ    ( 3102): [2420]< GET_CURRENT_CALLS 
 [id=1,ACTIVE,toa=129,norm,mt,0,voc,noevp,,cli=1,,1]  [SUB0]
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值