小议UNSOL_RESPONSE_CALL_STATE_CHANGED与GET_CURRENT_CALLS

  在之前的讨论中我们曾经看到,GsmCallTracker所维护的每一路GsmConnection都需要从modem侧及时更新当前通话状态。那么,这个CLCC是如何从framework侧发送的呢?


  在ril.java中有方法getCurrentCalls(Messageresult),该方法即是将GET_CURRENT_CALLS的消息打包以socket方式发到cp侧,再转换为AT+CLCC指令发送到网络端的。


  再往上看,会发现在GsmCallTracker中有方法operationComplete(),是它调用了getCureentCalls方法。有趣的是,这个方法中还有个实例变量pendingOperations用来计数,具体是做什么用的,后面会说到。

 

  统计了一下,调用这个operationComplete()方法的,都是在framework侧收到这些消息的时候:

EVENT_OPERATION_COMPLETE

EVENT_SWITCH_RESULT

EVENT_CONFERENCE_RESULT

EVENT_SEPARATE_RESULT

EVENT_ECT_RESULT

EVENT_GET_LAST_CALL_FAIL_CAUSE

 

  对于前五种消息,相信经常折腾framework侧Call业务的童鞋都不会陌生。像dial,reject,acceptCall,以及切换前后台通话,合并通话等等业务操作,都会将这几个对应的消息用obtain系列的方法包成Message参数发下去,等待指令操作完之后再带着消息回传上来,以此解决异步消息应答消息不同步的问题。而消息EVENT_GET_LAST_CALL_FAIL_CAUSE,则是专门处理上述列出的各项业务异常的情况,在该种情况下,framework层也认为本次业务已经处理完成了。

 

  简单地说,这个operationComplete()方法就像字面上所写的那样,标志着一次业务操作的结束,而实例变量pendingOperations就是专门用来计量当前待处理的业务数目的。可以看到,在obtain相关的方法中,该变量自加1,而framework收到底层上报上来的对应的完成消息,并调用operationComplete()方法时,这个变量又自减1了。

 

  这种类似于PV操作的机制是专门用来保护异步消息处理的流程正常化。如果一次业务譬如说dial,由于网络侧timeout的缘故,迟迟收不到ATD执行完毕的消息回执,那么显然这个pendingOperations就不可能被清为零。

 

  这是非常糟糕的事情。因为我们知道,网络侧会根据当前的通话流程(拨号、振铃、接通等等)不断主动上报消息UNSOL_RESPONSE_CALL_STATE_CHANGED,告知framework底层状态已经有了变化,请查询更新当前通话状态。

小议UNSOL_RESPONSE_CALL_STATE_CHANGED与GET_CURRENT_CALLS_第1张图片

    

  如何更新当前的通话状态?显然需要通过GET_CURRENT_CALLS这样的动作去查询。当UNSOL_RESPONSE_CALL_STATE_CHANGED消息主动上报后,GsmCallTracker的handleMessage就会执行之前已经注册好的消息EVENT_CALL_STATE_CHANGE对应的方法——pollCallsWhenSafe()。在这个方法中,我们又会注册消息EVENT_POLL_CALLS_RESULT,并调用getCurrentCalls方法,从而发送AT+CLCC指令,更新当前通话状态,完成一次通话状态的获取过程。

 

     但是这个流程顺利完成的前提是pendingOperations已经清为零。

    protected void pollCallsWhenSafe() {

        needsPoll = true;

        if (checkNoOperationsPending()) {

            lastRelevantPoll =obtainMessage(EVENT_POLL_CALLS_RESULT);

            cm.getCurrentCalls(lastRelevantPoll);

        }

    }

    private boolean
    checkNoOperationsPending() {
        if (DBG_POLL) log("checkNoOperationsPending: pendingOperations=" +
                pendingOperations);
        return pendingOperations == 0;
    }

     换句话说,只有当上一次业务操作执行完成之后,接下来AT+CLCC指令才会被正常发送。这期间,即使网络侧已经有了变化,发送了主动上报的消息UNSOL_RESPONSE_CALL_STATE_CHANGED也没有用。这个机制有效地保护了各个处理流程之间逻辑上的正常,但是在某种异常条件下,比如说由于网络延迟引起了消息回执迟迟不能收到,导致framework无法进一步更新通话状态。这里是否应该设置某种保护机制,我得好好考虑一下。


你可能感兴趣的:(网络,socket)