美文网首页
电话笔记 | 电话来电流程分析

电话笔记 | 电话来电流程分析

作者: 力卉编程 | 来源:发表于2020-01-02 21:29 被阅读0次

    一、总体流程

    Android的Phone设计的相当复杂,只有了解了Phone的设计框架才能把握电话的拨号或来电流程,这里介绍一下电话的来电流程。

    电话流程图:


    电话流程

    Framework层的RIL中的RILReceiver线程从rild服务进程中读取modem发送上来的来电消息等信息,通过消息注册-响应机制来通知上层处理,上图清晰地显示了各层之间的消息处理关系,CallManager连接Framework层和应用层的Phone,

    CallManager处理GSMPhone注册的消息事件,并且触发CallManager注册的消息事件,而CallNotifier处理CallManager消息,这样就将RIL层的消息一级一级传送的应用层的Phone了。

    二、RIL层事件注册过程

    2.1 构建对应的Phone对象

    在PhoneFactory的makeDefaultPhone函数中,首先构造一个DefaultPhoneNotifier对象和RIL对象,然后从数据库中读取网络模式,根据网络模式得到对应的电话类型,从而构造对应的Phone对象,并为该Phone对象创建一个PhoneProxy代理对象。对于GSM网络,会构造一个GSMPhone对象

    //frameworks\base\telephony\java\com\android\internal\telephony\PhoneFactory.java
    public static void makeDefaultPhone(Context context) {
        synchronized(Phone.class) {
            if (!sMadeDefaults) {
                sLooper = Looper.myLooper();
                sContext = context;
                if (sLooper == null) {
                    throw new RuntimeException("PhoneFactory.makeDefaultPhone must be called from Looper thread");
                }
                int retryCount = 0;
                for(;;) {
                    boolean hasException = false;
                    retryCount ++;
                    try {
                        new LocalServerSocket("com.android.internal.telephony");
                    } catch (java.io.IOException ex) {
                        hasException = true;
                    }
                    if ( !hasException ) {
                        break;
                    } else if (retryCount > SOCKET_OPEN_MAX_RETRY) {
                        throw new RuntimeException("PhoneFactory probably already running");
                    } else {
                        try {
                            Thread.sleep(SOCKET_OPEN_RETRY_MILLIS);
                        } catch (InterruptedException er) {
                        }
                    }
                }
                sPhoneNotifier = new DefaultPhoneNotifier();
                // Get preferred network mode
                int preferredNetworkMode = RILConstants.PREFERRED_NETWORK_MODE;
                if (TelephonyManager.getLteOnCdmaModeStatic() == PhoneConstants.LTE_ON_CDMA_TRUE) {
                    preferredNetworkMode = Phone.NT_MODE_GLOBAL;
                }
                //从数据库中读取网络模式
                int networkMode = Settings.Global.getInt(context.getContentResolver(),
                        Settings.Global.PREFERRED_NETWORK_MODE, preferredNetworkMode);
                Log.i(LOG_TAG, "Network Mode set to " + Integer.toString(networkMode));
     
                int cdmaSubscription;        
                int lteOnCdma = TelephonyManager.getLteOnCdmaModeStatic();
                switch (lteOnCdma) {
                    case PhoneConstants.LTE_ON_CDMA_FALSE:
                        cdmaSubscription = CdmaSubscriptionSourceManager.SUBSCRIPTION_FROM_NV;
                        Log.i(LOG_TAG, "lteOnCdma is 0 use SUBSCRIPTION_FROM_NV");
                        break;
                    case PhoneConstants.LTE_ON_CDMA_TRUE:
                        cdmaSubscription = CdmaSubscriptionSourceManager.SUBSCRIPTION_FROM_RUIM;
                        Log.i(LOG_TAG, "lteOnCdma is 1 use SUBSCRIPTION_FROM_RUIM");
                        break;
                    case PhoneConstants.LTE_ON_CDMA_UNKNOWN:
                    default:
                        //Get cdmaSubscription mode from Settings.System
                        cdmaSubscription = Settings.Global.getInt(context.getContentResolver(),
                                Settings.Global.PREFERRED_CDMA_SUBSCRIPTION,
                                preferredCdmaSubscription);
                        Log.i(LOG_TAG, "lteOnCdma not set, using PREFERRED_CDMA_SUBSCRIPTION");
                        break;
                }
                Log.i(LOG_TAG, "Cdma Subscription set to " + cdmaSubscription);
                //reads the system properties and makes commandsinterface
                sCommandsInterface = new RIL(context, networkMode, cdmaSubscription);
                // Instantiate UiccController so that all other classes can just call getInstance()
                UiccController.make(context, sCommandsInterface);  
                //根据网络模式得到电话类型
                int phoneType = TelephonyManager.getPhoneType(networkMode);
                //根据电话类型创建对应类型的Phone对象,并且使用创建的Phone对象来构造PhoneProxy代理对象
                if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
                    Log.i(LOG_TAG, "Creating GSMPhone");
                    sProxyPhone = new PhoneProxy(new GSMPhone(context,sCommandsInterface, sPhoneNotifier));
                } else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
                    switch (TelephonyManager.getLteOnCdmaModeStatic()) {
                        case PhoneConstants.LTE_ON_CDMA_TRUE:
                            Log.i(LOG_TAG, "Creating CDMALTEPhone");
                            sProxyPhone = new PhoneProxy(new CDMALTEPhone(context,sCommandsInterface, sPhoneNotifier));
                            break;
                        case PhoneConstants.LTE_ON_CDMA_FALSE:
                        default:
                            Log.i(LOG_TAG, "Creating CDMAPhone");
                            sProxyPhone = new PhoneProxy(new CDMAPhone(context,sCommandsInterface, sPhoneNotifier));
                            break;
                    }
                }
                sMadeDefaults = true;
            }
        }
    }
    
    2.2 构建对象GSMPhone

    在构造GSMPhone对象时,首先使用父类的成员变量CommandsInterfac mCM设置电话类型,由于RIL类实现了CommandsInterfac接口,因此mCM引用RIL对象。在构造GSMPhone对象时通过参数传入并设置父类PhoneBase的成员变量mCM。

    //frameworks\base\telephony\java\com\android\internal\telephony\gsm\ GSMPhone.java 
    public GSMPhone (Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode) {
        super(notifier, context, ci, unitTestMode);
        mCM.setPhoneType(Phone.PHONE_TYPE_GSM);
        mIccCard.set(MsUiccController.getInstance(this).getIccCard());
        mIccRecords = mIccCard.get().getIccRecords();
        mCT = new GsmCallTracker(this);
        mSST = new GsmServiceStateTracker (this);
        mSMS = new GsmSMSDispatcher(this, mSmsStorageMonitor, mSmsUsageMonitor);
        if (!unitTestMode) {
            mSimPhoneBookIntManager = new SimPhoneBookInterfaceManager(this);
            mSimSmsIntManager = new SimSmsInterfaceManager(this, mSMS);
            mSubInfo = new PhoneSubInfo(this);
        }
        mCM.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
        registerForSimRecordEvents();
        mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
        mCM.registerForOn(this, EVENT_RADIO_ON, null);
        mCM.setOnUSSD(this, EVENT_USSD, null);
        mCM.setOnSuppServiceNotification(this, EVENT_SSN, null);
        mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK, null);
     
        mHandlerThread = new HandlerThread("GSMPhone_AsyncThread");
        mHandlerThread.start();
        mAsyncThread = new AsyncThread(mHandlerThread.getLooper());
        if (false) {
            try {
                //debugSocket = new LocalServerSocket("com.android.internal.telephony.debug");
                debugSocket = new ServerSocket();
                debugSocket.setReuseAddress(true);
                debugSocket.bind (new InetSocketAddress("127.0.0.1", 6666));
     
                debugPortThread
                    = new Thread(
                        new Runnable() {
                            public void run() {
                                for(;;) {
                                    try {
                                        Socket sock;
                                        sock = debugSocket.accept();
                                        Log.i(LOG_TAG, "New connection; resetting radio");
                                        mCM.resetRadio(null);
                                        sock.close();
                                    } catch (IOException ex) {
                                        Log.w(LOG_TAG,
                                            "Exception accepting socket", ex);
                                    }
                                }
                            }
                        },
                        "GSMPhone debug");
     
                debugPortThread.start();
     
            } catch (IOException ex) {
                Log.w(LOG_TAG, "Failure to open com.android.internal.telephony.debug socket", ex);
            }
        }
        //Change the system property
        SystemProperties.set(TelephonyProperties.CURRENT_ACTIVE_PHONE,
                new Integer(Phone.PHONE_TYPE_GSM).toString());
    }
    
    2.3 父类PhoneBase

    构造GSMPhone对象同时也会创建一个GsmCallTracker对象,GSMCallTracker实现了电话的拨打(Dial)、接听/拒绝(accept/reject)、挂断(hangup)、保持(hold)、切换以及电话会议等功能,它还负责查询Modem当前有多少路通话,维护电话状态等功能。GSMCallTracker中包含了GsmConnection、RegistrantList、 GSMCall和Phone.State等类的对象实例。在GSMCallTracker构造函数中向RIL类实例注册了RegistrantList,当通话状态及射频Radio状态变化时,就会通知GSMCallTracker。

    //frameworks\base\telephony\java\com\android\internal\telephony\ PhoneBase.java
    protected PhoneBase(PhoneNotifier notifier, Context context, CommandsInterface ci,
            boolean unitTestMode) {
        this.mNotifier = notifier;
        this.mContext = context;
        mLooper = Looper.myLooper();
        mCM = ci;
        setPropertiesByCarrier();
        setUnitTestMode(unitTestMode);
        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
        mDnsCheckDisabled = sp.getBoolean(DNS_SERVER_CHECK_DISABLED_KEY, false);
        mCM.setOnCallRing(this, EVENT_CALL_RING, null);
        mIsVoiceCapable = mContext.getResources().getBoolean(com.android.internal.R.bool.config_voice_capable);
        mDoesRilSendMultipleCallRing = SystemProperties.getBoolean(
                TelephonyProperties.PROPERTY_RIL_SENDS_MULTIPLE_CALL_RING, true);
        Log.d(LOG_TAG, "mDoesRilSendMultipleCallRing=" + mDoesRilSendMultipleCallRing);
        mCallRingDelay = SystemProperties.getInt(
                TelephonyProperties.PROPERTY_CALL_RING_DELAY, 3000);
        Log.d(LOG_TAG, "mCallRingDelay=" + mCallRingDelay);
        // Initialize device storage and outgoing SMS usage monitors for SMSDispatchers.
        mSmsStorageMonitor = new SmsStorageMonitor(this);
        mSmsUsageMonitor = new SmsUsageMonitor(context);
    }
    
    2.4 电话Tracker

    cm引用RIL对象,在这里注册了电话状态改变事件,视频电话状态改变事件,无线开关事件等。由于RIL实现了CommandsInterface接口,并继承于BaseCommands抽象类,registerForCallStateChanged函数实现在RIL的父类BaseCommands中

    这里为RIL注册了一些消息事件,并指定GsmCallTracker来处理这些消息。

    //frameworks\base\telephony\java\com\android\internal\telephony\gsm\ GsmCallTracker.java 
    GsmCallTracker (GSMPhone phone) {
        this.phone = phone;
        cm = phone.mCM;
        cm.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null);
        cm.registerForVideoCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null);
        cm.registerForOn(this, EVENT_RADIO_AVAILABLE, null);
        cm.registerForNotAvailable(this, EVENT_RADIO_NOT_AVAILABLE, null);
        sendEmptyMessage(EVENT_INITIALIZE);
    }
    
    2.5 注册监听状态函数

    该函数通过Handler及对应的事件消息来构造一个Registrant对象,并将其注册到mCallStateRegistrants对象中,mCallStateRegistrants为RegistrantList类型变量,定义在RIL的父类BaseCommands中,RegistrantList类是用于保存注册的处理指定消息的所有Handler,RegistrantList类首先将某个消息及处理该消息的Handler封装成Registrant对象,并将该对象保存到成员变量registrants动态数组中。

    //frameworks\base\telephony\java\com\android\internal\telephony\BaseCommands.java
    public void registerForCallStateChanged(Handler h, int what, Object obj) {
        Registrant r = new Registrant (h, what, obj);
        mCallStateRegistrants.add(r);
    }
    
    2.6 电话流程状态

    对于电话状态改变事件,注册的Handle对象为GsmCallTracker,因此在电话状态改变事件到来时,GsmCallTracker将处理EVENT_CALL_STATE_CHANGE消息事件。

    GsmCallTracker有三个成员变量:

    • GsmCall ringingCall = new GsmCall(this) 前台Call,其中对应的Connection是ACTIVE,DIALING,ALERTING状态的,即激活状态
    • GsmCall foregroundCall = new GsmCall(this) 后台Call,其中对应的Connection是HOLDING状态的,即保持状态
    • GsmCall backgroundCall = new GsmCall(this) 来电Call,其中对应的Connection是INCOMING,WAITING状态的,即来电状态

    三、电话流程函数跟踪

    3.1 构建全局对象及注册事件

    在Phone进程启动的时,PhoneApp的onCreate函数首先被调用,PhoneApp会构造各种全局对象,同时也会注册一些事件。

    mCM = CallManager.getInstance();
    mCM.registerPhone(phone);
    //function here
    public boolean registerPhone(Phone phone) {
        Phone basePhone = getPhoneBase(phone);
        if (basePhone != null && !mPhones.contains(basePhone)) {
            if (DBG) {
                Log.d(LOG_TAG, "registerPhone(" +
                        phone.getPhoneName() + " " + phone + ")");
            }
            if (mPhones.isEmpty()) {
                mDefaultPhone = basePhone;
            }
            mPhones.add(basePhone);
            mRingingCalls.add(basePhone.getRingingCall());
            mBackgroundCalls.add(basePhone.getBackgroundCall());
            mForegroundCalls.add(basePhone.getForegroundCall());
            registerForPhoneStates(basePhone);
            return true;
        }
        return false;
    }
    private void registerForPhoneStates(Phone phone) {
        // for common events supported by all phones
        phone.registerForPreciseCallStateChanged(mHandler, EVENT_PRECISE_CALL_STATE_CHANGED, null);
        phone.registerForDisconnect(mHandler, EVENT_DISCONNECT, null);
        phone.registerForNewRingingConnection(mHandler, EVENT_NEW_RINGING_CONNECTION, null);
        phone.registerForUnknownConnection(mHandler, EVENT_UNKNOWN_CONNECTION, null);
        phone.registerForIncomingRing(mHandler, EVENT_INCOMING_RING, null);
        phone.registerForRingbackTone(mHandler, EVENT_RINGBACK_TONE, null);
        phone.registerForInCallVoicePrivacyOn(mHandler, EVENT_IN_CALL_VOICE_PRIVACY_ON, null);
        phone.registerForInCallVoicePrivacyOff(mHandler, EVENT_IN_CALL_VOICE_PRIVACY_OFF, null);
        phone.registerForDisplayInfo(mHandler, EVENT_DISPLAY_INFO, null);
        phone.registerForSignalInfo(mHandler, EVENT_SIGNAL_INFO, null);
        phone.registerForResendIncallMute(mHandler, EVENT_RESEND_INCALL_MUTE, null);
        phone.registerForMmiInitiate(mHandler, EVENT_MMI_INITIATE, null);
        phone.registerForMmiComplete(mHandler, EVENT_MMI_COMPLETE, null);
        phone.registerForSuppServiceFailed(mHandler, EVENT_SUPP_SERVICE_FAILED, null);
        phone.registerForServiceStateChanged(mHandler, EVENT_SERVICE_STATE_CHANGED, null);
     
        // for events supported only by GSM and CDMA phone
        if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_GSM ||
                phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
            phone.setOnPostDialCharacter(mHandler, EVENT_POST_DIAL_CHARACTER, null);
        }
     
        // for events supported only by CDMA phone
        if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA ){
            phone.registerForCdmaOtaStatusChange(mHandler, EVENT_CDMA_OTA_STATUS_CHANGE, null);
            phone.registerForSubscriptionInfoReady(mHandler, EVENT_SUBSCRIPTION_INFO_READY, null);
            phone.registerForCallWaiting(mHandler, EVENT_CALL_WAITING, null);
            phone.registerForEcmTimerReset(mHandler, EVENT_ECM_TIMER_RESET, null);
        }
    }
    
    3.2 CallManager层事件注册过程

    在启动PhoneApp时,同样也会创建一个CallNotifier对象
    notifier = CallNotifier.init(this, phone, ringer, mBtHandsfree, new CallLogAsync());

    这构造CallNotifier对象过程中,为CallManager层注册了一些消息事件,并指定CallNotifier来处理这些消息

    private void registerForNotifications() {
        mCM.registerForNewRingingConnection(this, PHONE_NEW_RINGING_CONNECTION, null);
        mCM.registerForPreciseCallStateChanged(this, PHONE_STATE_CHANGED, null);
        mCM.registerForDisconnect(this, PHONE_DISCONNECT, null);
        mCM.registerForUnknownConnection(this, PHONE_UNKNOWN_CONNECTION_APPEARED, null);
        mCM.registerForIncomingRing(this, PHONE_INCOMING_RING, null);
        mCM.registerForCdmaOtaStatusChange(this, EVENT_OTA_PROVISION_CHANGE, null);
        mCM.registerForCallWaiting(this, PHONE_CDMA_CALL_WAITING, null);
        mCM.registerForDisplayInfo(this, PHONE_STATE_DISPLAYINFO, null);
        mCM.registerForSignalInfo(this, PHONE_STATE_SIGNALINFO, null);
        mCM.registerForInCallVoicePrivacyOn(this, PHONE_ENHANCED_VP_ON, null);
        mCM.registerForInCallVoicePrivacyOff(this, PHONE_ENHANCED_VP_OFF, null);
        mCM.registerForRingbackTone(this, PHONE_RINGBACK_TONE, null);
        mCM.registerForResendIncallMute(this, PHONE_RESEND_MUTE, null);
    }
    
    3.3 状态变化的介绍:
    • 当有PHONE_NEW_RINGING_CONNECTION类型消息到来时,意味着一个RINGING或WAITING的连接(connection)出现,此时handleMessage函数调用onNewRingingConnection来处理。后者先检查Settings里的设置是否可以接听电话;然后进 行响铃(见InCallTonePlayer)和显示InCallScreen的UI,见PhoneUtils.showIncomingCallUi()和PhoneApp.displayCallScreen()两个函数。通话过程中的铃音提示由线程类InCallTonePlayer完成。
    • 当有PHONE_INCOMING_RING类型的消息到来时,意味着RIL层受到Ring,此处播放铃音。它使用的是Ringer.ring()函数,它会创建一个线程去播放铃音,见Ringer.makeLooper函数。
    • 当有PHONE_STATE_CHANGED消息时,表明Phone的状态发生了改变,比如响铃后接通了电话,此时处理函数是onPhoneStateChanged,比如再次确认停止铃音、更新状态栏列的状态通知等。
    • 当有PHONE_DISCONNECT消息时,表明电话连接已挂断或RingCall断掉。其处理函数是onDisconnect。它清理现场诸如音频通道恢复、来电响铃的停止确认、对InCallScreen的UI清理、若有未接电话须在状态栏显示等。
    3.4 电话状态改变事件处理

    我们已经知道在RIL中分别创建了两个线程,一个用于往rild套接字中写入数据,一个用于从该套接字中读取rild服务进程发送上来的数据。对于来电事件,RILReceiver会读取到rild发送过来的来电信息。


    RIL

    以下这段代码是RILReceiver线程不断循环读取来自rild的AT Response,
    调用processResponse进行处理,根据返回结果中不同的Request号,
    调用到相应的responseXXX函数簇,获取AT执行结果。

    //frameworks\base\telephony\java\com\android\internal\telephony\RIL.java
    try {
        InputStream is = mSocket.getInputStream();
        for (;;) {
            Parcel p;
            //从rild套接字中读取消息
            length = readRilMessage(is, buffer);
            if (length < 0) {
                // End-of-stream reached
                break;
            }
            //将读取到的数据序列化到Parcel对象中
            p = Parcel.obtain();
            p.unmarshall(buffer, 0, length);
            p.setDataPosition(0);
            //数据处理
            processResponse(p);
            p.recycle();
        }
    } catch (java.io.IOException ex) {
        Log.i(LOG_TAG, "'" + SOCKET_NAME_RIL + "' socket closed", ex);
    } catch (Throwable tr) {
        Log.e(LOG_TAG, "Uncaught exception read length=" + length +
            "Exception:" + tr.toString());
    }
    
    
    private void processResponse (Parcel p) {
        int type;
     
        type = p.readInt();
     
        if (type == RESPONSE_UNSOLICITED) {
            processUnsolicited (p);
        } else if (type == RESPONSE_SOLICITED) {
            processSolicited (p);
        }
        releaseWakeLockIfDone();
    }
    

    在Android之rild进程启动源码分析介绍了,rild服务进程会接收到两种类型的消息,一种是Ap向Bp发送请求,Bp给Ap发送回复消息,一种是Bp主动给Ap发送事件,对于请求响应事件,调用processSolicited函数来处理,而对于BP主动发起的事件则调用processUnsolicited函数来处理。来电属于BP主动发起的请求事件,因此processUnsolicited函数将处理来电请求

    protected void processUnsolicited (Parcel p) {
        int response;
        Object ret;
        response = p.readInt();
        try {
            switch(response) {
                case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED: ret =  responseVoid(p); break;         
                default:
                    throw new RuntimeException("Unrecognized unsol response: " + response);
            }
        } catch (Throwable tr) {
            Log.e(LOG_TAG, "Exception processing unsol response: " + response +
                "Exception:" + tr.toString());
            return;
        }
        switch(response) {
            case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED:
                if (RILJ_LOGD) unsljLog(response);
                mCallStateRegistrants.notifyRegistrants(new AsyncResult(null, null, null));
            break;
        }
    }
    

    mCallStateRegistrants为RegistrantList类型变量,前面已经介绍了消息注册过程,这里调用RegistrantList的notifyRegistrants函数来通知所有注册过该消息的Handler处理该消息。

    //frameworks\base\core\java\android\os\RegistrantList.java
    public void  notifyRegistrants(){
        internalNotifyRegistrants(null, null);
    }
     
    private synchronized void  internalNotifyRegistrants (Object result, Throwable exception){
       for (int i = 0, s = registrants.size(); i < s ; i++) {
            Registrant  r = (Registrant) registrants.get(i);
            r.internalNotifyRegistrant(result, exception);
       }
    }
    

    这里循环遍历成员变量registrants中保存的所有Registrant对象,前面介绍到,在注册某个Handler处理指定消息时,首先将其封装为Registrant对象,这里取出该消息对应的所有Registrant对象,并调用该对象的internalNotifyRegistrant函数来触发注册的Handler处理该消息。

    //frameworks\base\core\java\android\os\Registrant.java
    
    void internalNotifyRegistrant (Object result, Throwable exception){
        Handler h = getHandler();
        if (h == null) {
            clear();
        } else {
            Message msg = Message.obtain();
            msg.what = what;
            msg.obj = new AsyncResult(userObj, result, exception);
            h.sendMessage(msg);
        }
    }
    

    该函数其是就是向注册的Handler中发送消息,消息为注册的消息类型。由于在构造GsmCallTracker对象时,已经在BaseCommands中注册了EVENT_CALL_STATE_CHANGE消息的处理Handler为GsmCallTracker对象本身,
    cm.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null);

    因此mCallStateRegistrants.notifyRegistrants(new AsyncResult(null, null, null))将向GsmCallTracker对象发送EVENT_CALL_STATE_CHANGE的消息

    //frameworks\base\telephony\java\com\android\internal\telephony\CallTracker.java
    public void handleMessage (Message msg) {
         AsyncResult ar;
         switch (msg.what) {
           case EVENT_CALL_STATE_CHANGE:
                pollCallsWhenSafe();
              break;
         }
    }
    

    函数最终调用pollCallsWhenSafe来处理EVENT_CALL_STATE_CHANGE消息,pollCallsWhenSafe用于查询当前的通话状态。

    protected void pollCallsWhenSafe() {
        needsPoll = true;
        if (checkNoOperationsPending()) {
            lastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);
            cm.getCurrentCalls(lastRelevantPoll);
        }
    }
    

    函数checkNoOperationsPending就是判断变量pendingOperations是否等于0,如果等于0,则调用CommandsInterface的getCurrentCalls函数来发送一个EVENT_POLL_CALLS_RESULT消息,该函数实现在RIL.java中。
    AT命令CLCC查询结果对应于Connection类中的成员变量,一 路电话对应一个对象。

    //frameworks\base\telephony\java\com\android\internal\telephony\RIL.java
    public void getCurrentCalls (Message result) {
        RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_CURRENT_CALLS, result);
        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
        send(rr);
    }
    

    未完~~

    文 | 力卉编程

    相关文章

      网友评论

          本文标题:电话笔记 | 电话来电流程分析

          本文链接:https://www.haomeiwen.com/subject/xjxaoctx.html