MT Call来电流程分析

来电时底层会上报消息到RIL层,在Android8.0上目前已经做了修改,不再使用Socket进行通信,而是使用ril_service服务进行通信,O的系统上引入了HIDL机制,telephony的framework层引用底层的服务就用到了此机制,这也导致了RIL层的调整.
1.我们从RIL层开始往上追溯,RIL接收底层来电消息,来电的消息属于主动上报的UnSolicited消息,其对应的事件ID是CALL_STATE_CHANGE,我们进入RIL.java开始查找。在Android 7.0上的入口是processUnsolicited方法。
该方法的操作主要操作有以下两点
    (1)向底层发送确认消息
    (2)继续通知上层
我们在O版本上只看到了processIndication方法,
frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java
public void processIndication(int indicationType) {
if (indicationType == RadioIndicationType.UNSOLICITED_ACK_EXP) {
              sendAck();
if (RILJ_LOGD) riljLog("Unsol response received; Sending ack to ril.cpp");
         } else {
// ack is not expected to be sent back. Nothing is required to be done here.
         }
      }
可以看到该方法是向底层发送确认消息的方法,也就是7.0中processUnsolicited方法的一个操作,可以看到8.0中已经没有processUnsolicited方法,那么RIL是如何接收底层消息的呢?搜索调用此方法的地方。
发现RadioIndication.java有调用此方法。
这里我们看到之前7.0上的processUnsolicited方法对于callState处理的方法移除到这里了。
frameworks/opt/telephony/src/java/com/android/internal/telephony/
RadioIndication.java
    public void callStateChanged(int indicationType) {
        mRil.processIndication(indicationType);
        if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED);
        mRil.mCallStateRegistrants.notifyRegistrants();
    }
这里的操作和之前一样
    调用processIndication向底层发送确认收到消息
     notifyRegistrant发出通知
注意RadioIndication类
public class RadioIndication extends IRadioIndication.Stub
我们继续看看其继承的IRadioIndication.Stub,全局搜索RadioIndication可以发现其在IRadio.hal中定义了此接口,关于HIDL用法就不再展开,后续有空再补充HIDL的知识。注意RadioIndication类,发现其定义了大量类似callStateChanged的方法,再对比7.0上的processUnsolicited方法,发现本是通过一个方法统一管理的底层回复现在交由RadioIndication类处理,其callStateChanged对应与之前processUnsolicited方法中的switch-case的callStateChanged一项,其他的以此类推。RIL通信的7.0和8.0差别变化比较大的一个地方。接下来继续分析RIL接收到底层消息后,发起的通知传向何处。

2.RIL层在接收到底层的消息后,发起了notify通知,关于regist-notify机制其实就是观察者模式,全局搜索registerForCallStateChanged。发现有三个地方注册了此接口。
    BaseCommands
    GsmCdmaCallTracker
    CommandsInterface
其中BascCommands,CommandsInterface都是接口,具体作用可以参见Phone讲解,这里继续跟进GsmCdmaCallTracker。可以看到其继承自CallTracker,本质上是个Handler处理类,所以其关键方法在于handleMessage处理。
3.跟进GsmCdmaCallTracker的handleMessage方法
我们可以看到其在初始化的地方注册了CallStateChanged消息的监听,注册的时候传入了自身的handler,
frameworks/opt/telephony/src/java/com/mediatek/internal/telephony/GsmCdmaCallTracker.java
    public GsmCdmaCallTracker (GsmCdmaPhone phone) {
         this.mPhone = phone;
         mCi = phone.mCi;
        mCi.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null);
mCi.registerForOn(this, EVENT_RADIO_AVAILABLE, null);
mCi.registerForNotAvailable(this, EVENT_RADIO_NOT_AVAILABLE, null);
// Register receiver for ECM exit
IntentFilter filter = new IntentFilter();      filter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
mPhone.getContext().registerReceiver(mEcmExitReceiver, filter);
       updatePhoneType(true);
    }
notify的时候使用该handler发送消息,所以我们可以在handleMessage中响应并处理EVENT_CALL_STATE_CHANGE消息。

    public void handleMessage(Message msg) {
        AsyncResult ar;
        switch (msg.what) {
            ...
             case EVENT_CALL_STATE_CHANGE:
                  pollCallsWhenSafe();
4.继续跟踪pollCallsWhenSafe方法
    frameworks/opt/telephony/src/java/com/android/internal/telephony/CallTracker.java
protected void pollCallsWhenSafe() {
    mNeedsPoll = true;
    if (checkNoOperationsPending()) {
         mLastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);
         mCi.getCurrentCalls(mLastRelevantPoll);
        }
    }
发现其又调用了mCi.getCurrentCalls去查询当前的Call情况,此方法会调用到RIL中对应的方法去(Phone创建的时候对mCi进行初始化使得具有RIL通信能力,其mCi即调用RIL.java)
5.继续跟进RIL中的getCurrentCalls方法
public void getCurrentCalls(Message result) {
        //区别与7.0的代码,获取一个Radio代理进行通信
IRadio radioProxy = getRadioProxy(result);
if (radioProxy != null) {
      //创建一个请求消息
RILRequest rr = obtainRequest(RIL_REQUEST_GET_CURRENT_CALLS, result,
       mRILDefaultWorkSource);
 if (RILJ_LOGD) {
            riljLog(rr.serialString() + "> requestToString(rr.mRequest));
     }
       try {//向底层发起请求
                radioProxy.getCurrentCalls(rr.mSerial);
           } catch (RemoteException | RuntimeException e) {
               handleRadioProxyExceptionForRR(rr, "getCurrentCalls", e);
            }
        }
    }
6.在发送请求后,等待modem返回结果给RIL层,继续跟踪返回消息的接收
在Android N上RIL请求的返回是在processSolicited方法中处理
其主要操作如下:
    向底层发送一个确认消息
    调用ril_commands.h中定义的回复方法进行处理
那么Android O是如何处理的呢?
在RIL.java中查找底层消息反馈的处理方法,发现有两个方法processRespose和processResponseDone,向上追溯发现其是在RadioResponse.java中的调用此方法。
继续分析RadioResponse类
public class RadioResponse extends IRadioResponse.Stub
发现其继承自一个底层的服务,观察其中各个处理方法发现其中是各中上层请求的返回处理方法。可见N上的processSolicited的消息回复被抽取到这个地方来了。
那么其CurrentCall的消息继续在responseCurrentCalls方法追踪。
frameworks/opt/telephony/src/java/com/android/internal/telephony/RadioResponse.java
  public void getCurrentCallsResponse(RadioResponseInfo responseInfo,
             ArrayList<android.hardware.radio.V1_0.Call> calls) {
        responseCurrentCalls(responseInfo, calls);
    }
7.继续追踪调用的responseCurrentCalls方法
     private void responseCurrentCalls(RadioResponseInfo responseInfo,                                      ArrayList<android.hardware.radio.V1_0.Call> calls) {
  RILRequest rr = mRil.processResponse(responseInfo);
  if (rr != null) {
     int num = calls.size();
     ArrayList<DriverCall> dcCalls = new ArrayList<DriverCall>(num);
            DriverCall dc;
         for (int i = 0; i < num; i++) {
                dc = new DriverCall();
// TODO: change name of function stateFromCLCC() in DriverCall.java to name
// clarifying what is CLCC
                dc.state = DriverCall.stateFromCLCC((int) (calls.get(i).state));
                dc.index = calls.get(i).index;
                dc.TOA = calls.get(i).toa;
                dc.isMpty = calls.get(i).isMpty;
                dc.isMT = calls.get(i).isMT;
                dc.als = calls.get(i).als;
                dc.isVoice = calls.get(i).isVoice;
                dc.isVoicePrivacy = calls.get(i).isVoicePrivacy;
                dc.number = calls.get(i).number;
                dc.numberPresentation =
DriverCall.presentationFromCLIP( (int) (calls.get(i).numberPresentation));
                dc.name = calls.get(i).name;
                dc.namePresentation =
DriverCall.presentationFromCLIP((int) (calls.get(i).namePresentation));
                if (calls.get(i).uusInfo.size() == 1) {
                    dc.uusInfo = new UUSInfo();
           dc.uusInfo.setType(calls.get(i).uusInfo.get(0).uusType);
           dc.uusInfo.setDcs(calls.get(i).uusInfo.get(0).uusDcs);
  if (!TextUtils.isEmpty(calls.get(i).uusInfo.get(0).uusData)) {
byte[] userData = calls.get(i).uusInfo.get(0).uusData.getBytes();
                        dc.uusInfo.setUserData(userData);
                    } else {
mRil.riljLog("responseCurrentCalls: uusInfo data is null or empty");
                    }
mRil.riljLogv(String.format("Incoming UUS : type=%d, dcs=%d, length=%d",
                            dc.uusInfo.getType(), dc.uusInfo.getDcs(),
                            dc.uusInfo.getUserData().length));
mRil.riljLogv("Incoming UUS : data (hex): "+ IccUtils.bytesToHexString(dc.uusInfo.getUserData()));
                } else {
                    mRil.riljLogv("Incoming UUS : NOT present!");
                }
// Make sure there's a leading + on addresses with a TOA of 145
dc.number = PhoneNumberUtils.stringFromStringAndTOA(dc.number, dc.TOA);
                dcCalls.add(dc);
if (dc.isVoicePrivacy) {
      mRil.mVoicePrivacyOnRegistrants.notifyRegistrants();
       mRil.riljLog("InCall VoicePrivacy is enabled");
      } else {
           mRil.mVoicePrivacyOffRegistrants.notifyRegistrants();
           mRil.riljLog("InCall VoicePrivacy is disabled");
                }
            }
            Collections.sort(dcCalls);
if ((num == 0) && mRil.mTestingEmergencyCall.getAndSet(false)) {
      if (mRil.mEmergencyCallbackModeRegistrant != null) {
 mRil.riljLog("responseCurrentCalls: call ended, testing emergency call,"
                            + " notify ECM Registrants");
          mRil.mEmergencyCallbackModeRegistrant.notifyRegistrant();
                }
            }
            //发送返回消息
            if (responseInfo.error == RadioError.NONE) {
                sendMessageResponse(rr.mResult, dcCalls);
            }
            mRil.processResponseDone(rr, responseInfo, dcCalls);
        }
    }
 发现其通过底层返回的消息创建了dcCalls对象,也就是当前的Call状态信息,对dc状态进行判断后如果有需要就notify通知,如果没有异常则通过sendMessageResponse方法发送消息
     public static void sendMessageResponse(Message msg, Object ret) {
        if (msg != null) {
            AsyncResult.forMessage(msg, ret, null);
            msg.sendToTarget();
        }
    }
这部分就和N的一样了,将返回值返回给当初的请求者,由请求者去决定如何处理

8.继续回到GsmCdmaCallTracker的handleMessage中,之前发送请求的时候有发送EVENT_POLL_CALLS_RESULT,这里我们继续回到该事件处理的地方来分析
     GsmCdmaCallTracker.java  
  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;
9.继续追踪handlePollCalls
protected synchronized void handlePollCalls(AsyncResult ar) {
 //解析返回的结果
for (int i = 0, curDC = 0, dcSize = polledCalls.size()
                ; i < mConnections.length; i++) {
            GsmCdmaConnection conn = mConnections[i];
            DriverCall dc = null;
            // polledCall list is sparse
            if (curDC < dcSize) {
                dc = (DriverCall) polledCalls.get(curDC);
                if (dc.index == i+1) {
                    curDC++;
                } else {
                    dc = null;
                }
            }
            ...
            if (conn == null && dc != null) {
            ...状态的处理及识别
        //响铃消息通知
     if (newRinging != null) {
            mPhone.notifyNewRingingConnection(newRinging);
       }
        // clear the "local hangup" and "missed/rejected call"
        // cases from the "dropped during poll" list
        // These cases need no "last call fail" reason
        ArrayList<GsmCdmaConnection> locallyDisconnectedConnections = new ArrayList<>();
        for (int i = mDroppedDuringPoll.size() - 1; i >= 0 ; i--) {
            GsmCdmaConnection conn = mDroppedDuringPoll.get(i);
            //CDMA
            boolean wasDisconnected = false;
 //来电处理,本地挂断或者未接,本地挂断的话直接设置挂断的原因为LOCAL或INVALID_NUMBER
            if (conn.isIncoming() && conn.getConnectTime() == 0) {
                // Missed or rejected call
                int cause;
                if (conn.mCause == DisconnectCause.LOCAL) {
                    cause = DisconnectCause.INCOMING_REJECTED;
                } else {
                    cause = DisconnectCause.INCOMING_MISSED;
                }
                if (Phone.DEBUG_PHONE) {
                    log("missed/rejected call, conn.cause=" + conn.mCause);
                    log("setting cause to " + cause);
                }
                mDroppedDuringPoll.remove(i);
                hasAnyCallDisconnected |= conn.onDisconnect(cause);
                wasDisconnected = true;
                locallyDisconnectedConnections.add(conn);
            } else if (conn.mCause == DisconnectCause.LOCAL
                    || conn.mCause == DisconnectCause.INVALID_NUMBER) {
                mDroppedDuringPoll.remove(i);
                hasAnyCallDisconnected |= conn.onDisconnect(conn.mCause);
                wasDisconnected = true;
                locallyDisconnectedConnections.add(conn);
            }
            if (!isPhoneTypeGsm() && wasDisconnected && unknownConnectionAppeared
                    && conn == newUnknownConnectionCdma) {
                unknownConnectionAppeared = false;
                newUnknownConnectionCdma = null;
            }
        }
        if (locallyDisconnectedConnections.size() > 0) {
            mMetrics.writeRilCallList(mPhone.getPhoneId(), locallyDisconnectedConnections);
        }
 /* Disconnect any pending Handover connections */
        //通话断开的一些处理操作
        ...
if (newRinging != null || hasNonHangupStateChanged || hasAnyCallDisconnected) {
            internalClearDisconnected();
        }
        //更新phone状态
        if (VDBG) log("handlePollCalls calling updatePhoneState()");
        updatePhoneState();
        ...
    }
可以看到其先对底层反馈的消息进行解析,获取其通话状态,判断如果是来电则发出notifyNewRingingConnection响铃消息通知,然后进行一些通话断开连接的操作及更新phone状态。继续跟进notifyNewRingingConnection响铃消息,该消息调用的是phone的方法,往上追溯。
    /frameworks/opt/telephony/src/java/com/android/internal/telephony/sip/
/frameworks/opt/telephony/src/java/com/android/internal/telephony/imsphone/
/frameworks/opt/telephony/src/java/com/android/internal/telephony/
frameworks/opt/telephony/src/java/com/android/internal/telephony/Phone.java
public void notifyNewRingingConnectionP(Connection cn) {
        if (!mIsVoiceCapable)
            return;
        AsyncResult ar = new AsyncResult(null, cn, null);
        mNewRingingConnectionRegistrants.notifyRegistrants(ar);
    }
10.继续查看响铃消息通知到何处,全局搜索(registerForNewRingingConnection),发现其监听的主要是以下几个地方
    PstnIncommingCallNotifier.java
    PhoneMock.java
    CallManager.java
    Phone.java
GsmCdmaCallTracker调用的其实是phone的notify方法,所以可以排除PhoneMock.java和Phone.java所以主要继续跟踪的就是CallManager 和 PstnIncommingCallNotifier
看下CallManager的handleMessage消息处理方法
    case EVENT_NEW_RINGING_CONNECTION:
       if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_NEW_RINGING_CONNECTION)");
          Connection c = (Connection) ((AsyncResult) msg.obj).result;
              int subId = c.getCall().getPhone().getSubId();
         if (getActiveFgCallState(subId).isDialing() || hasMoreThanOneRingingCall()) {
                        try {
      Rlog.d(LOG_TAG, "silently drop incoming call: " + c.getCall());
                            c.getCall().hangup();
                        } catch (CallStateException e) {
                            Rlog.w(LOG_TAG, "new ringing connection", e);
                        }
                    } else {
  mNewRingingConnectionRegistrants.notifyRegistrants((AsyncResult)msg.obj);
                    }
                    break;
可以看到CallManager在对此消息进行判断后,确认是否需要挂断,如果不需要则进一步通知此消息。所以其实还是 PstnIncommingCallNotifier 中处理此消息。
通过注释也可发现其是监听来电消息。
/proprietary/packages/services/Telephony/src/com/android/services/telephony/PstnIncomingCallNotifier.java
/**
 * Listens to incoming-call events from the associated phone object and notifies Telecom upon each
 * occurence. One instance of these exists for each of the telephony-based call services.
 */
  @Override
        public void handleMessage(Message msg) {
            switch(msg.what) {
                case EVENT_NEW_RINGING_CONNECTION:
                    handleNewRingingConnection((AsyncResult) msg.obj);
                    break;
                case EVENT_CDMA_CALL_WAITING:
                    handleCdmaCallWaiting((AsyncResult) msg.obj);
                    break;
                case EVENT_UNKNOWN_CONNECTION:
                    handleNewUnknownConnection((AsyncResult) msg.obj);
                    break;
                default:
                    break;
            }
        }
继续调用handleNewRingingConnection方法处理调用sendIncommingCallIntent发送Intent,这里其实就已经从RIL传递消息到了应用层了,后续继续分析在应用层如何继续上报的。

    /**
     * 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) {
        Log.d(this, "handleNewRingingConnection");
        Connection connection = (Connection) asyncResult.result;
if (connection != null) {
      Call call = connection.getCall();
  // Final verification of the ringing state before sending the intent to Telecom.
      if (call != null && call.getState().isRinging()) {
if (ExtensionManager.getDigitsUtilExt().isConnectionMatched(connection,
  mPhoneAccountHandle, mPhone.getContext()) == false) {
                    return;
                }
                sendIncomingCallIntent(connection);
            }
        }
    }
11.继续跟进sendIncomingCallIntent
    /**
     * Sends the incoming call intent to telecom.
     */
PstnIncomingCallNotifier.java
   private void sendIncomingCallIntent(Connection connection) {
   Bundle extras = new Bundle();
   //extras填充一些数据
   ...
   PhoneAccountHandle handle = findCorrectPhoneAccountHandle();
   if (handle == null) {
        //挂断
  } else {
TelecomManager.from(mPhone.getContext()).addNewIncomingCall(handle, extras);
        }
    }
    //获取telecomm服务
    public static TelecomManager from(Context context) {
        return (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE);
    }

frameworks/base/telecomm/java/android/telecom/TelecomManager.java
public void addNewIncomingCall(PhoneAccountHandle phoneAccount, Bundle extras) {
   try {
     if (isServiceConnected()) {
      if (extras != null && extras.getBoolean(EXTRA_IS_HANDOVER) &&                        mContext.getApplicationContext().getApplicationInfo().targetSdkVersion >
                                 Build.VERSION_CODES.O_MR1) {
    Log.e("TAG", "addNewIncomingCall failed. Use public api " +                            "acceptHandover for API > O-MR1");
        // TODO add "return" after DUO team adds support for new handover API
      }
getTelecomService().addNewIncomingCall(
            phoneAccount, extras == null ? new Bundle() : extras);
}
} catch (RemoteException e) {
Log.e(TAG, "RemoteException adding a new incoming call: " + phoneAccount, e);
        }
    }
通过aidl接口调用 telecomService 的addNewIncomingCall方法TelecomService层
12.跟进到成员变量mBinderImpl的具体实现类
/packages/services/Telecomm/src/com/android/server/telecom/TelecomServiceImpl.java
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);
                    ...
13继续跟进mCallIntentProcessorAdapter.processIncomingCallIntent,
   /packages/services/Telecomm/src/com/android/server/telecom/CallIntentProcessor.java
 static void processIncomingCallIntent(CallsManager callsManager, Intent intent) {
        ...
        Log.d(CallIntentProcessor.class,
                "Processing incoming call from connection service [%s]",
                phoneAccountHandle.getComponentName());
        callsManager.processIncomingCallIntent(phoneAccountHandle, clientExtras);
    }
    ...
14.进入到CallsManager中继续跟进
   packages/services/Telecomm/src/com/android/server/telecom/CallsManager.java
 void processIncomingCallIntent(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
        Log.d(this, "processIncomingCallIntent");
        ...
        Call call = new Call(
                getNextCallId(),
                mContext,
                this,
                mLock,
                mConnectionServiceRepository,
                mContactsAsyncHelper,
                mCallerInfoAsyncQueryFactory,
                mPhoneNumberUtilsAdapter,
                handle,
                null /* gatewayInfo */,
                null /* connectionManagerPhoneAccount */,
                phoneAccountHandle,
                Call.CALL_DIRECTION_INCOMING /* callDirection */,
                false /* forceAttachToExistingConnection */,
                false, /* isConference */
                mClockProxy)
        ...
        call的一些状态设置
        ...
        call.initAnalytics();
        if (getForegroundCall() != null) {
            getForegroundCall().getAnalytics().setCallIsInterrupted(true);
            call.getAnalytics().setCallIsAdditional(true);
        }
        setIntentExtrasAndStartTime(call, extras);
        //添加监听
        // TODO: Move this to be a part of addCall()
        call.addListener(this);

        if (!isHandoverAllowed || (call.isSelfManaged() && !isIncomingCallPermitted(call,
                call.getTargetPhoneAccount()))) {
            notifyCreateConnectionFailed(phoneAccountHandle, call);
        } else {
            //成功上报上去建立连接
            call.startCreateConnection(mPhoneAccountRegistrar);
        }
    }
这里和之前MO的流程是一样的,创建了一个Call然后调用startCreateConnection去创建connection,有需要的可以看下去电流程二的后半部分

TelecomFramework
15.跟进到IConnectionService中Binder的实现中去
    /** @hide */
    protected IBinder mBinder = new IConnectionService.Stub() {
        @Override
        public void createConnection(
                ...
                mHandler.obtainMessage(MSG_CREATE_CONNECTION, args).sendToTarget();
            ...
16.找到handler事件处理的地方
case MSG_CREATE_CONNECTION: {
     ...
  if (!mAreAccountsInitialized) {
      Log.d(this, "Enqueueing pre-init request %s", id);
     mPreInitializationConnectionRequests.add(
                 new android.telecom.Logging.Runnable(
      SESSION_HANDLER + SESSION_CREATE_CONN + ".pICR",null /*lock*/) {
         @Override
      public void loggedRun() {
  createConnection(connectionManagerPhoneAccount,id,request,
                    isIncoming, isUnknown);
                   }
                            }.prepare());
                        } else {
   createConnection(
           connectionManagerPhoneAccount, id, request, isIncoming,
                    isUnknown);
                        }
                    }
                    ...
17.可以看到无论如何都会调用createConnection,点击跟进到ConnectionService中的此方法
    /**
     * This can be used by telecom to either create a new outgoing call or attach to an existing
     * incoming call. In either case, telecom will cycle through a set of services and call
     * createConnection util a connection service cancels the process or completes it successfully.
     */
    /** {@hide} */
frameworks/base/telecomm/java/android/telecom/ConnectionService.java
    protected void createConnection(
            final PhoneAccountHandle callManagerAccount,
            final String callId,
            final ConnectionRequest request,
            boolean isIncoming,
            boolean isUnknown) {
Log.d(this, "createConnection, callManagerAccount: %s, callId: %s, request: %s, " +"isIncoming: %b, isUnknown: %b", callManagerAccount, callId, request, isIncoming, isUnknown);
        //判断是来电还是去电创造不同的connection
        Connection connection = isUnknown ? onCreateUnknownConnection(callManagerAccount, request)
                : isIncoming ? onCreateIncomingConnection(callManagerAccount, request)
                : onCreateOutgoingConnection(callManagerAccount, request);
        ...

        Log.d(this, "createConnection, calling handleCreateConnectionSuccessful %s", callId);
        //创建成功后调用
        mAdapter.handleCreateConnectionComplete(
                callId,
                request,
                new ParcelableConnection(
                ...

        if (isIncoming && request.shouldShowIncomingCallUi() &&
                (connection.getConnectionProperties() & Connection.PROPERTY_SELF_MANAGED) ==
                        Connection.PROPERTY_SELF_MANAGED) {
            // Tell ConnectionService to show its incoming call UX.
            connection.onShowIncomingCallUi();
        }
        if (isUnknown) {
            triggerConferenceRecalculate();
        }
    }
18当判断是来电时会通过 onCreateIncomingConnection 创建连接,直接跟进去发现是空实现,那么该方法的实现应该在该类的子类中,跟进到其子类TelephonyConnectionService中

/**
 * Service for making GSM and CDMA connections.
 */
packages/services/Telephony/src/com/android/services/telephony/TelephonyConnectionService.java
public class TelephonyConnectionService extends ConnectionService
    @Override
    public Connection onCreateIncomingConnection(
            PhoneAccountHandle connectionManagerPhoneAccount,
            ConnectionRequest request) {
        ...
        Phone phone = getPhoneForAccount(accountHandle, isEmergency);
        ...
        Call call = phone.getRingingCall();
  com.android.internal.telephony.Connection originalConnection =
call.getState() == Call.State.WAITING ?
     call.getLatestConnection() : call.getEarliestConnection();
        ...
        Connection connection =
                createConnectionFor(phone, originalConnection, false /* isOutgoing */,
                        request.getAccountHandle(), request.getTelecomCallId(),
                        request.getAddress(), videoState);
        ...
    }
19 可以看到其是通过createConnectionFor创建
//返回需要的connection
    protected TelephonyConnection createConnectionFor(
            Phone phone,
            com.android.internal.telephony.Connection originalConnection,
            boolean isOutgoing,
            PhoneAccountHandle phoneAccountHandle,
            String telecomCallId,
            Uri address,
            int videoState) {
        TelephonyConnection returnConnection = null;
        int phoneType = phone.getPhoneType();
        boolean allowsMute = allowsMute(phone);
        returnConnection = new MtkGsmCdmaConnection(phoneType, originalConnection, telecomCallId, mEmergencyTonePlayer, allowsMute, isOutgoing);
        if (returnConnection != null) {
            // Listen to Telephony specific callbacks from the connection     returnConnection.addTelephonyConnectionListener(mTelephonyConnectionListener);
    returnConnection.setVideoPauseSupported(
    TelecomAccountRegistry.getInstance(this).isVideoPauseSupported(
         phoneAccountHandle));
        }
        return returnConnection;
    }
20.继续回到之前的 handleCreateConnectionComplet中跟进
ConnectionServiceAdapter.java
    public void handleCreateConnectionComplete(
            String id,
            ConnectionRequest request,
            ParcelableConnection connection) {
        for (IConnectionServiceAdapter adapter : mAdapters) {
            try {
                adapter.handleCreateConnectionComplete(id, request, connection,
                        Log.getExternalSession());
            } catch (RemoteException e) {
            }
        }
    }
21.这里通过AIDL进行通信,搜索 IConnectionServiceAdapter.Stub,
跟进到 ConnectionServiceWrapper.java
public void handleCreateConnectionComplete(String callId, ConnectionRequest request,ParcelableConnection connection, Session.Info sessionInfo) {
    ...
logIncoming("handleCreateConnectionComplete %s", callId);
ConnectionServiceWrapper.this .handleCreateConnectionComplete(callId, request, connection);
                ...
        }
    之前在拨号创建完connection并呼叫之后也会走到这个地方
22.继续跟进handleCreateConnectionComplete
  ConnectionServiceWrapper.java
  private void handleCreateConnectionComplete(
             String callId,
              ConnectionRequest request,
             ParcelableConnection connection) {
// TODO: Note we are not using parameter "request", which is a side effect of our tacit assumption that we have at most one outgoing connection attempt per ConnectionService.
// This may not continue to be the case.
if (connection.getState() == Connection.STATE_DISCONNECTED) {
// A connection that begins in the DISCONNECTED state is an indication of
// failure to connect; we handle all failures uniformly
  removeCall(callId, connection.getDisconnectCause());
          } else {
              // Successful connection
              if (mPendingResponses.containsKey(callId)) {
mPendingResponses.remove(callId)
            .handleCreateConnectionSuccess(mCallIdMapper, connection);
}
        }
     }
mPendingResponses是hashMap容器,每次在 createConnection 的时候会将对象加入该容器,如果此时connection还未断开的,会移除此connection,调用hanleCreateConnectionSuccess方法。
往上追溯createConnection跟踪到mService.createConnection(mCall, this);
CreateConnectionProcessor.java会把自身传入,发现该类也实现了 CreateConnectionResponse ,所以这里的 handleCreateConnectionSuccess
调用的是这个类里面的方法
23.继续跟进 CreateConnectionProcessor 中的此方法
CreateConnectionProcessor.java
    @Override
    public void handleCreateConnectionSuccess(
            CallIdMapper idMapper,
            ParcelableConnection connection) {
        if (mCallResponse == null) {
            mService.abort(mCall);
        } else {
 mCallResponse.handleCreateConnectionSuccess(idMapper, connection);
String number = connection == null || connection.getHandle() == null ? null : connection.getHandle().getSchemeSpecificPart();
            if (!PhoneNumberUtils.isEmergencyNumber(number)) {
                mCallResponse = null;
            }
        }
    }   

24.发现这里的 mCallResponse (mCallResponse为何是 telecomm Call 对象?),继续跟进telecomm Call中的
Call.java
public void handleCreateConnectionSuccess(
CallIdMapper idMapper, ParcelableConnection connection) {
Log.v(this, "handleCreateConnectionSuccessful %s", connection);
setTargetPhoneAccount(connection.getPhoneAccount());
setHandle(connection.getHandle(), connection.getHandlePresentation());
setCallerDisplayName(connection.getCallerDisplayName(), connection.getCallerDisplayNamePresentation());
    setConnectionCapabilities(connection.getConnectionCapabilities());
setConnectionProperties(connection.getConnectionProperties());
setIsVoipAudioMode(connection.getIsVoipAudioMode());
setSupportedAudioRoutes(connection.getSupportedAudioRoutes());
setVideoProvider(connection.getVideoProvider());
setVideoState(connection.getVideoState());
setRingbackRequested(connection.isRingbackRequested());
setStatusHints(connection.getStatusHints());
putExtras(SOURCE_CONNECTION_SERVICE, connection.getExtras());
      mConferenceableCalls.clear();
for (String id : connection.getConferenceableConnectionIds()) {
         mConferenceableCalls.add(idMapper.getCall(id));
       }
switch (mCallDirection) {
        case CALL_DIRECTION_INCOMING:
// Listeners (just CallsManager for now) will be responsible for checking whether
// the call should be blocked.
              for (Listener l : mListeners) {
                     l.onSuccessfulIncomingCall(this);
                  }
                  break;
              case CALL_DIRECTION_OUTGOING:
                for (Listener l : mListeners) {
l.onSuccessfulOutgoingCall(this,
                             getStateFromConnectionState(connection.getState()));
                }
                 break;
              case CALL_DIRECTION_UNKNOWN:
                 for (Listener l : mListeners) {
                    l.onSuccessfulUnknownCall(this, getStateFromConnectionState(connection
                             .getState()));
                 }
               break;
         }
      }
这里根据来电类型,触发回调,监听者会收到通知,之前在CallManager中执行 processIncomingCallIntent 方法创建Call的时候就添加了监听,所以最后会回调到
CallsManager中
CallsManager.java
public void onSuccessfulIncomingCall(Call incomingCall) {
Log.d(this, "onSuccessfulIncomingCall");
if (incomingCall.hasProperty(Connection.PROPERTY_EMERGENCY_CALLBACK_MODE)) {
            Log.i(this, "Skipping call filtering due to ECBM");
  onCallFilteringComplete(incomingCall, new CallFilteringResult(true, false, true, true));
  return;
       }  //迭代器模式
   List<IncomingCallFilter.CallFilter> filters = new ArrayList<>();
  filters.add(new DirectToVoicemailCallFilter(mCallerInfoLookupHelper));
  filters.add(new AsyncBlockCheckFilter(mContext, new BlockCheckerAdapter(),mCallerInfoLookupHelper));
  filters.add(new CallScreeningServiceFilter(mContext, this, mPhoneAccountRegistrar, mDefaultDialerCache, new ParcelableCallUtils.Converter(), mLock));
//IncomingCallFilter创建并执行 performFiltering
new IncomingCallFilter(mContext, this, incomingCall, mLock,
mTimeoutsAdapter, filters).performFiltering();
    }
这里我们可以看出CallsManager的管理作用,创建Calls并添加监听,在完成Call的相关初始化后进行进一步处理,其实就是传递消息到别的的地方去。
25.这里用到了迭代器模式,一个来电触发三个对象的处理,最后创建一个IncomingCallFilter并调用performFiltering.
IncomingCallFilter.java
public void performFiltering() {
        Log.addEvent(mCall, LogUtils.Events.FILTERING_INITIATED);
        for (CallFilter filter : mFilters) {
            //遍历调用,依次执行异步查询方法
            filter.startFilterLookup(mCall, this);
        }
        // synchronized to prevent a race on mResult and to enter into Telecom.
        mHandler.postDelayed(new Runnable("ICF.pFTO", mTelecomLock) { // performFiltering time-out
            @Override
            public void loggedRun() {
                if (mIsPending) {
                    //超时处理的方法
                    Log.i(IncomingCallFilter.this, "Call filtering has timed out.");
Log.addEvent(mCall, LogUtils.Events.FILTERING_TIMED_OUT);
                    //回CallsManager中的监听事件
                    mListener.onCallFilteringComplete(mCall, mResult);
                    mIsPending = false;
                }
            }
        }.prepare(), mTimeoutsAdapter.getCallScreeningTimeoutMillis(mContext.getContentResolver()));
    }
26.如果没有超时则在异步查询结束后,会通过回调方法将CallFilterResult传回onCallFilteringComplete.

IncomingCallFilter.java
public void onCallFilteringComplete(Call call, CallFilteringResult result) {
synchronized (mTelecomLock) { // synchronizing to prevent race on mResult
            mNumPendingFilters--;
//对之前三种过滤查询结果进行运算,满足条件才可以通话
 //这里不对三种过滤器具体分析,有兴趣的可以进一步分析
            mResult = result.combine(mResult);
            if (mNumPendingFilters == 0) {
                // synchronized on mTelecomLock to enter into Telecom.
                mHandler.post(new Runnable("ICF.oCFC", mTelecomLock) {
                    @Override
                    public void loggedRun() {
                        if (mIsPending) {
                            Log.addEvent(mCall, LogUtils.Events.FILTERING_COMPLETED, mResult);
                            //继续回调
                            mListener.onCallFilteringComplete(mCall, mResult);
                            mIsPending = false;
                        }
                    }
                }.prepare());
            }
        }
    }
27.回到CallsManager中进行onCallFilteringComplete处理
/packages/services/Telecomm/src/com/android/server/telecom/CallsManager.java
public void onCallFilteringComplete(Call incomingCall, CallFilteringResult result) {
       ...
  if (incomingCall.getState() != CallState.DISCONNECTED &&
       incomingCall.getState() != CallState.DISCONNECTING &&
       incomingCall.getState() != CallState.ACTIVE) {
       //设置Call状态为Ring
setCallState(incomingCall, CallState.RINGING,
 result.shouldAllowCall ? "successful incoming call" : "blocking call");
        } else {
  Log.i(this, "onCallFilteringCompleted: call already disconnected.");
            return;
        }
    if (result.shouldAllowCall) {
          if (MtkUtil.isInSingleVideoCallMode(incomingCall)) {
                ...
            }
     if (hasMaximumManagedRingingCalls(incomingCall)) {
                if (shouldSilenceInsteadOfReject(incomingCall)) {
                    incomingCall.silence();
                } else {
Log.i(this, "onCallFilteringCompleted: Call rejected! " +"Exceeds maximum number of ringing calls.");
                    rejectCallAndLog(incomingCall);
                }
            } else {
          //添加Call
                addCall(incomingCall);
            }
        } else {
      if (result.shouldReject) {
Log.i(this, "onCallFilteringCompleted: blocked call, rejecting.");
                incomingCall.reject(false, null);
            }
   if (result.shouldAddToCallLog) {
Log.i(this, "onCallScreeningCompleted: blocked call, adding to call log.");
     if (result.shouldShowNotification) {
                    Log.w(this, "onCallScreeningCompleted: blocked call, showing notification.");
                }
                //添加通话记录
mCallLogManager.logCall(incomingCall, Calls.MISSED_TYPE,
                        result.shouldShowNotification);
            } else if (result.shouldShowNotification) {
Log.i(this, "onCallScreeningCompleted: blocked call, showing notification.");
mMissedCallNotifier.showMissedCallNotification(
                        new MissedCallNotifier.CallInfo(incomingCall));
            }
        }
    }
28正常的话会将Call状态置为ring,并且添加Call,继续跟进addCall
   CallsManager.java
 private void addCall(Call call) {
        call.addListener(this);
        mCalls.add(call);
        // Specifies the time telecom finished routing the call. This is used by the dialer for
        // analytics.
        Bundle extras = call.getIntentExtras();
extras.putLong(TelecomManager.EXTRA_CALL_TELECOM_ROUTING_END_TIME_MILLIS,
                SystemClock.elapsedRealtime());
        updateCanAddCall();
        // onCallAdded for calls which immediately take the foreground (like the first call).
        for (CallsManagerListener listener : mListeners) {
            //通知监听Call添加的观察者
            listener.onCallAdded(call);
        }
        /// M: single video call mode
        if (MtkUtil.isInSingleVideoCallMode(call)) {
            for (Call c : mCalls) {
                c.refreshConnectionCapabilities();
            }
        }
    }
29.查看监听Call添加的观察者
在CallsManager构造函数初始化的时候添加了一些列观察者,还有就是通过addListener去添加的。
        mListeners.add(mInCallWakeLockController);
        mListeners.add(statusBarNotifier);
        mListeners.add(mCallLogManager);
        mListeners.add(mPhoneStateBroadcaster);
        mListeners.add(mInCallController);
        mListeners.add(mCallAudioManager);
        mListeners.add(missedCallNotifier);
        mListeners.add(mHeadsetMediaButton);
        mListeners.add(mProximitySensorManager);
        ...
        mListeners.add(new CallConnectedVibrator(mContext));
这里我们继续跟进mInCallController,
 InCallController.java
 public void onCallAdded(Call call) {
        if (!isBoundAndConnectedToServices()) {
            bindToServices(call);
        } else {
            // We are bound, and we are connected.
            adjustServiceBindingsForEmergency();
            // This is in case an emergency call is added while there is an existing call.
mEmergencyCallHelper.maybeGrantTemporaryLocationPermission(call,
                    mCallsManager.getCurrentUserHandle());
            //添加Call
            addCall(call);
List<ComponentName> componentsUpdated = new ArrayList<>();
for (Map.Entry<InCallServiceInfo, IInCallService> entry : mInCallServices.entrySet()) {
InCallServiceInfo info = entry.getKey();
if (call.isExternalCall() && !info.isExternalCallsSupported()) {
                    continue;
                }
if (call.isSelfManaged() && !info.isSelfManagedCallsSupported()) {
                    continue;
}
// Only send the RTT call if it's a UI in-call service
boolean includeRttCall = info.equals(mInCallServiceConnection.getInfo());
componentsUpdated.add(info.getComponentName());
IInCallService inCallService = entry.getValue();
ParcelableCall parcelableCall = ParcelableCallUtils.toParcelableCall(call,
                        true /* includeVideoProvider */, mCallsManager.getPhoneAccountRegistrar(),
     info.isExternalCallsSupported(), includeRttCall);
   try {
         //AIDL调用远程的addCall方法
        inCallService.addCall(parcelableCall);
       } catch (RemoteException ignored) {
                }
            }
       Log.i(this, "Call added to components: %s", componentsUpdated);
        }
    }
Telecomm Framework
30继续查找IInCallService的实现,跟进addCall方法
    /** Manages the binder calls so that the implementor does not need to deal with it. */InCallService.java
    private final class InCallServiceBinder extends IInCallService.Stub {
        @Override
        public void setInCallAdapter(IInCallAdapter inCallAdapter) {
mHandler.obtainMessage(MSG_SET_IN_CALL_ADAPTER,inCallAdapter).sendToTarget();
        }
        @Override
        public void addCall(ParcelableCall call) {
mHandler.obtainMessage(MSG_ADD_CALL, call).sendToTarget();
        }
31继续跟进MSG_ADD_CALL消息的处理
     InCallService.java
   public void handleMessage(Message msg) {
            switch (msg.what) {
                ...
                case MSG_ADD_CALL:
                    mPhone.internalAddCall((ParcelableCall) msg.obj);
                ...
32继续跟进internalAddCall
Phone.java
 final void internalAddCall(ParcelableCall parcelableCall) {
        //创建Call
Call call = new Call(this, parcelableCall.getId(), mInCallAdapter,
parcelableCall.getState(), mCallingPackage, mTargetSdkVersion);
mCallByTelecomCallId.put(parcelableCall.getId(), call);
        //添加到列表中
        mCalls.add(call);
        checkCallTree(parcelableCall);
        call.internalUpdate(parcelableCall, mCallByTelecomCallId);
        //调用phone的监听者的onCallAdded
        fireCallAdded(call);
     }

    private void fireCallAdded(Call call) {
        for (Listener listener : mListeners) {
            listener.onCallAdded(this, call);
        }
    }    

33.在 InCallService 中handleMessage处理MSG_SET_IN_CALL_ADAPTER消息的时候就注册了监听,这里继续跟进到InCallService中的实现去

private Phone.Listener mPhoneListener = new Phone.Listener()
        ...
        @Override
        public void onCallAdded(Phone phone, Call call) {
            //调用InCallService对象的onCallAdded方法
            InCallService.this.onCallAdded(call);
        }
        ...
可以看到这其实是个空实现,具体实现是在子类中,继续跟进到子类中分析
Dialer
34查找InCallService的子类
InCallServiceImpl.java
public class InCallServiceImpl extends InCallService
@Override
public void onCallAdded(Call call) {
if ((CallList.getInstance().getVideoUpgradeRequestCall() != null ||
  CallList.getInstance().getSendingVideoUpgradeRequestCall() != null ||
  /// M: When is cancel upgrade progress,we can't add another call in calllist. @{
  CallList.getInstance().getSendingCancelUpgradeRequestCall() != null)
        ///@}
  && !isEmergency(call)) {
       ...
    } else {
      InCallPresenter.getInstance().onCallAdded(call);
    }
}
跟踪到这里可以看到其所在目录是Dialer下的inCallUI了,这就到dialer层了,如果查看Diler的清单文件可以发现其有android.telecom.InCallService声明

35.InCallPresenter是InCallUI用于处理通话逻辑的核心类,继续跟进查看onCallAdded方法

  InCallPresenter.java
public void onCallAdded(final android.telecom.Call call) {
    LatencyReport latencyReport = new LatencyReport(call);
    if (shouldAttemptBlocking(call)) {
      maybeBlockCall(call, latencyReport);
    } else {
      if (call.getDetails().hasProperty(CallCompat.Details.PROPERTY_IS_EXTERNAL_CALL)) {
        mExternalCallList.onCallAdded(call);
      } else {
        latencyReport.onCallBlockingDone();
        //CallList(Call的维护列表)调用onCallAdded
        mCallList.onCallAdded(mContext, call, latencyReport);
      }
    }
    // Since a call has been added we are no longer waiting for Telecom to send us a call.
    setBoundAndWaitingForOutgoingCall(false, null);
    call.registerCallback(mCallCallback);
  }
36.继续跟进mCallList
  CallList.java
public void onCallAdded(
final Context context, final android.telecom.Call telecomCall, LatencyReport latencyReport) {
    Trace.beginSection("onCallAdded");
    ...
if (call.getState() == DialerCall.State.INCOMING
       || call.getState() == DialerCall.State.CALL_WAITING) {
          //来电调用
          onIncoming(call);
        } else {
          dialerCallListener.onDialerCallUpdate();
    }
    ...
}
最终调用其InCall的来电界面,这里就不再继续详细分析了。


 

猜你喜欢

转载自www.cnblogs.com/yz123/p/11982596.html