Android call process and other case sorting (3)--MT

Posted by balkar on Sun, 19 May 2019 02:39:04 +0200

For MO Call, it is usually an active action initiated by the user himself, and the process can be tracked according to the button on the UI. However, for MTcall, it is generally passive to receive modem messages, and it is not very easy to track the process from the UI level, so the MT process is roughly summarized.

First, check the processing of incoming message. When calling, the first step is to report the message of the call from modem, which is handled by the upper layer. The first message is: RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED. When the message is reported, it is processed in RadioIndication.java (after Android O, UNSOL message is processed in RadioIndication, SOL message is processed in RadioResponse). It replaces the previous process Unsolicited & process Solicited method. This message is modem informing the upper layer that the status of the current Call has changed. But the upper layer didn't know what the real change was, so Tele went back and asked what the current Call was in and made a request: RIL_REQUEST_GET_CURRENT_CALLS. When Modem receives these requests, it returns the information to Tele.

The specific code is as follows:

Step1. Receives the call status change message reported by Modem.

http://androidxref.com/8.1.0_r33/xref/frameworks/opt/telephony/src/java/com/android/internal/telephony/RadioIndication.java

    // When you get the message, you notify the listener of the message.
    public void callStateChanged(int indicationType) {
        mRil.processIndication(indicationType);

        if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED);

        mRil.mCallStateRegistrants.notifyRegistrants();
    }

Step2. Processing call s status changes reported from Modem. The code shows that GsmCdmaCallTracker.java has registered the listener:

http://androidxref.com/8.1.0_r33/xref/frameworks/opt/telephony/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java

    // When initialized, listen for EVENT_CALL_STATE_CHANGE messages
    public GsmCdmaCallTracker (GsmCdmaPhone phone) {
        ......
        mCi.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null);
        ......
    }

    // handle processing
    @Override
    public void handleMessage(Message msg) {
        AsyncResult ar;
        switch (msg.what) {
            ......
            case EVENT_CALL_STATE_CHANGE:
                // This method is not overridden in GsmCdmaCallTracker, so look at this method in the parent class
                pollCallsWhenSafe();
            break;
            ......
        }
    }


Step3. After processing, request Call information from Modem.

http://androidxref.com/8.1.0_r33/xref/frameworks/opt/telephony/src/java/com/android/internal/telephony/CallTracker.java

    protected void pollCallsWhenSafe() {
        mNeedsPoll = true;

        if (checkNoOperationsPending()) {
            mLastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);
            // Initiate requests to Modem through RIL
            mCi.getCurrentCalls(mLastRelevantPoll);
        }
    }

Step4. When Modem has finished processing, it returns the response.

http://androidxref.com/8.1.0_r33/xref/frameworks/opt/telephony/src/java/com/android/internal/telephony/RadioResponse.java

    /**
     * @param responseInfo Response info struct containing response type, serial no. 
     *        and error
     * @param calls Current call list
     */
    public void getCurrentCallsResponse(RadioResponseInfo responseInfo,
                                        ArrayList<android.hardware.radio.V1_0.Call> calls) {
        responseCurrentCalls(responseInfo, calls);
    }


    /**
     * Processing the message and returning it to the requester   
     */
    private void responseCurrentCalls(RadioResponseInfo responseInfo,
                                      ArrayList<android.hardware.radio.V1_0.Call> calls) {
        RILRequest rr = mRil.processResponse(responseInfo);

        if (rr != null) {
            ......

            /**
             * Processing the message body, we find that the message returned through the bottom creates the dcCalls object, which is the current Call status letter.
             * After judging the dc status, notify if necessary, and pass if there are no exceptions
             * sendMessageResponse Method to send a message. This part, like N, returns the return value to the original request.
             *It is up to the requester to decide how to deal with it.
            */
            if (responseInfo.error == RadioError.NONE) {
                sendMessageResponse(rr.mResult, dcCalls);
            }
            mRil.processResponseDone(rr, responseInfo, dcCalls);
        }
    }

Step5: Processing response. As you can see at Step3, CallTracker initiates a request, so the reponse returned by RIL returns to CallTracker. Check that the message in CallTracker does not process EVENT_POLL_CALLS_RESULT, and check that the message is processed in the subclass GsmCdmaCallTracker.java:

http://androidxref.com/8.1.0_r33/xref/frameworks/opt/telephony/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java#EVENT_POLL_CALLS_RESULT

    //****** Overridden from Handler

    @Override
    public void handleMessage(Message msg) {
        AsyncResult ar;

        switch (msg.what) {
            case EVENT_POLL_CALLS_RESULT:
                Rlog.d(LOG_TAG, "Event EVENT_POLL_CALLS_RESULT Received");

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

    // ***** Overwritten from CallTracker

    @Override
    protected synchronized void handlePollCalls(AsyncResult ar) {
        List polledCalls;
        ...
        if (newRinging != null) {
            //Notify new Ringing
            mPhone.notifyNewRingingConnection(newRinging);
        }
        ...
    }

Step6: Check the notification of the ringing bell. Find this notification, and ultimately Pstn Incoming CallNotifier handles it.

http://androidxref.com/8.1.0_r33/xref/packages/services/Telephony/src/com/android/services/telephony/PstnIncomingCallNotifier.java

    /**
     * Used to listen to events from {@link #mPhone}.
     */
    private final Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch(msg.what) {
                case EVENT_NEW_RINGING_CONNECTION:
                    handleNewRingingConnection((AsyncResult) msg.obj);
                    break;
                 ...
            }
        }
    };

    /**
     * Verifies the incoming call and triggers sending the incoming-call intent to 
     * Telecom.
     * @param asyncResult The result object from the new ringing event.
     */
    private void handleNewRingingConnection(AsyncResult asyncResult) {
            ...    
            if (call != null && call.getState().isRinging()) {
                sendIncomingCallIntent(connection);
            }
    }


    /**
     * Sends the incoming call intent to telecom.
     */
    private void sendIncomingCallIntent(Connection connection) {
        ...
        TelecomManager.from(mPhone.getContext()).addNewIncomingCall(handle, extras);
    }

At this point, the RIL message has been processed, and then the intent. response reported by Modem is sent to the upper level. The general method is as follows:

  1. RadioIndication.java#callStateChanged
  2. -->GsmCdmaCallTracker.java#mCi.registerForCallStateChanged# EVENT_CALL_STATE_CHANGE
  3. -->GsmCdmaCallTracker.java#pollCallsWhenSafe()
  4. --> Ril.java # getCurrentCalls # RIL_REQUEST_GET_CURRENT_CALLS
  5.  --> RadioResponse.java # getCurrentCallsResponse # responseCurrentCalls # sendMessageResponse
  6.  --> GsmCdmaCallTracker.java # EVENT_POLL_CALLS_RESULT #  handlePollCall
  7.  --> GsmCdmaPhone.java # notifyNewRingingConnection
  8. --> Phone.java#notifyNewRingingConnectionP
  9. -->PstnIncomingCallNotifier.java#handleNewRingingConnection#sendIncomingCallIntent

Step7: Processing in Packages / Service, intent delivery. In Step6, the addNewIncomingCall method of telecomService is invoked by getting Telecomm's service. Then addNewIncomingCall is invoked by aidl interface. Look at the specific implementation:

http://androidxref.com/8.1.0_r33/xref/packages/services/Telecomm/src/com/android/server/telecom/TelecomServiceImpl.java#addNewIncomingCall

        /**
         * @see android.telecom.TelecomManager#addNewIncomingCall
         */
        @Override
        public void addNewIncomingCall(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
          ......
                            Intent intent = new Intent(TelecomManager.ACTION_INCOMING_CALL);
                            intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
                                    phoneAccountHandle);
                            intent.putExtra(CallIntentProcessor.KEY_IS_INCOMING_CALL, true);
                            if (extras != null) {
                                extras.setDefusable(true);
                                intent.putExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS, extras);
                            }
                            mCallIntentProcessorAdapter.processIncomingCallIntent(
                                    mCallsManager, intent);
          ......              
        }

Continue to follow up the code:

http://androidxref.com/8.1.0_r33/xref/packages/services/Telecomm/src/com/android/server/telecom/CallIntentProcessor.java


    static void processIncomingCallIntent(CallsManager callsManager, Intent intent) {
        PhoneAccountHandle phoneAccountHandle = intent.getParcelableExtra(
                TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE);
        ...
        callsManager.processIncomingCallIntent(phoneAccountHandle, clientExtras);
    }

    /**
     * Starts the process to attach the call to a connection service.
     *
     * @param phoneAccountHandle The phone account which contains the component name of the
     *        connection service to use for this call.
     * @param extras The optional extras Bundle passed with the intent used for the incoming call.
     */
    void processIncomingCallIntent(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
         
        ...
        if (!isHandoverAllowed || (call.isSelfManaged() && !isIncomingCallPermitted(call,
                call.getTargetPhoneAccount()))) {
            notifyCreateConnectionFailed(phoneAccountHandle, call);
        } else {
            //Start creating Connection with this call
            call.startCreateConnection(mPhoneAccountRegistrar);
        }
    }

The direction of this code is as follows:

  1. TelecomManager.java # addNewIncomingCall 
  2. --> TelecomServiceImpl.java # addNewIncomingCall
  3. --> CallIntentProcessor.java # processIncomingCallIntent
  4. --> CallsManager.java #  processIncomingCallIntent 

Step8: Start creating connections. The process here is the same as the previous MO process, which creates a Call and then calls startCreateConnection to create a connection. Without too many logical calls, the approximate code goes as follows:

  1. Call.java # startCreateConnection 
  2. --> CreateConnectionProcessor.java # process() # attemptNextPhoneAccount()
  3. --> ConnectionServiceWrapper.java # createConnection
  4. --> ConnectionService.java # createConnection #MSG_CREATE_CONNECTION
  5. --> ConnectionServiceAdapter.java # handleCreateConnectionComplete
  6. --> ConnectionServiceWrapper.java # handleCreateConnectionComplete
  7. --> Call.java #  handleCreateConnectionSuccess

Setp9: Processing Call. The process here is not too logical, and is similar to MO:

  1. CallsManager.java # onSuccessfulIncomingCall
  2. --> IncomingCallFilter.java # performFiltering # onCallFilteringComplete
  3. --> CallsManager.java #  onCallFilteringComplete # addCall
  4. --> InCallController.java # onCallAdded

Setp10: Display UI interface, consistent with MO

  1. InCallService.java # MSG_ADD_CALL # 
  2. --> Phone.java # internalAddCall # fireCallAdded
  3. --> InCallService.java # onCallAdded
  4. --> InCallServiceImpl.java # onCallAdded
  5. --> InCallPresenter.java # onCallAdded
  6. --> CallList.java # onCallAdded
  7. --> CallList.java # onDialerCallUpdate 
  8. --> CallList.java # notifyGenericListeners 
  9. --> InCallPresenter.java # onCallListChange  
  10. --> InCallPresenter.java # startOrFinishUi 
  11. --> InCallPresenter.java # showInCall

The biggest difference between MO and MT is MT & MO initiation. MO is initiated from Dialer and MT is initiated from Modem. So the biggest difference between the two processes is how to start creating Call & connection. When it's ready to start creating and finished, MO & MT has almost no difference in process. It's all controlled by Call & Connection, which is displayed through UI. The main process analysis of this article is mainly focused on the reporting and processing of Modem messages.

 

Topics: Java Android