来电过程, 是由com.android.phone进程发起的,因为 com.android.phone 进程中 Telephony 直接与Moderm层交互, com.android.phone 进程收到来来电消息后,发送消息给 system 进程, system 进程(Telecom作为中介)开始和com.android.phone 进程建立链接, 并通知 UI 进程 (com.android.dialer) 更新。大体上和拨号过程类似。

来电流程时序图:

对于MO Call来说,一般是由用户自己操作来发起的主动动作,可以根据UI上的button来跟踪流程。但是对于MTcall来说,一般是被动的接收modem的消息,不太好从UI的层面来跟踪流程,所以大概的总结下MT流程。

首先,查来电消息的处理。在来电时,首先是由modem向上上报来电的消息,上层来处理。第一条消息是:RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,消息报上来后,到RadioIndication.java来处理(在Android O后,UNSOL消息在RadioIndication处理,SOL消息在RadioResponse里处理。替代了之前的processUnsolicited & processSolicited方法)。这条消息就是modem 告知上层:当前Call的状态发送变化了。但是上层并不知道真正的变化是什么,所以Tele回去询问当前Call到底是属于什么状态,发出请求:RIL_REQUEST_GET_CURRENT_CALLS。当Modem得到这些请求后,会将这些信息返回给Tele.

从RIL层开始往上追溯,RIL接收底层来电消息。来电的消息属于主动上报的UnSolicited消息,其对应的事件ID是CALL_STATE_CHANGE,我们进入RIL.java开始查找。

UNSOL_RESPONSE_CALL STATE CHANGED状态改变

  • frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java

  @UnsupportedAppUsage
5692      void unsljLog(int response) {
5693          riljLog("[UNSL]< " + responseToString(response));
5694      }@UnsupportedAppUsage
5561      static String responseToString(int request) {
5562          switch(request) {
5563              case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED:
5564                  return "UNSOL_RESPONSE_RADIO_STATE_CHANGED";
5565              case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED:
5566                  return "UNSOL_RESPONSE_CALL_STATE_CHANGED";
5567              case RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED:
  1. frameworks/opt/telephony/src/java/com/android/internal/telephony/RadioIndication.java

RadioIndication 类有17 个方法调用RIL 对象的unsljLog 方法打印消息,处理此
RIL 消息的代码逻辑详情如下:

    public void callStateChanged(int indicationType) {mRil.processIndication(indicationType);if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED);mRil.mCallStateRegistrants.notifyRegistrants();}
  1. 调用processIndication向底层发送确认收到消息
  2. notifyRegistrant发出通知

RIL层在接收到底层的消息后,发起了notify通知。----------- 观测者模式

其中:

public class RadioIndication extends IRadioIndication.Stub {

而 mCallStateRegistrants 在:

RIL继承于父类 BaseCommands ,实现了 mCallStateRegistrants

public class RIL extends BaseCommands implements CommandsInterface 
protected RegistrantList mCallStateRegistrants = new RegistrantList();

此处是: registerForCallStateChanged

搜索到有:

  1. BaseCommands
  2. GsmCdmaCallTracker
  3. CommandsInterface

其中BascCommands,CommandsInterface都是接口

mCalIStateReg istrants. notifyRegistrant 发出通知后,仅一个 地方可响应此消息通知,即GsmCdmaCallTracker 类的handleMessage 方法,本质上是个Handler处理类

  • frameworks/opt/telephony/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java

跟进GsmCdmaCallTracker的handleMessage方法,可以看到其在初始化的地方注册了CallStateChanged消息的监听,注册的时候传入了自身的handler,notify的时候使用该handler发送消息,所以我们可以在handleMessage中响应并处理EVENT_CALL_STATE_CHANGE消息。

     @Overridepublic void handleMessage(Message msg) {AsyncResult ar;switch (msg.what) {...case EVENT_CALL_STATE_CHANGE:pollCallsWhenSafe();...

pollCallsWhenSafe 调用父类CallTracker 方法

  • frameworks/opt/telephony/src/java/com/android/internal/telephony/CallTracker.java

   protected void pollCallsWhenSafe() {mNeedsPoll = true;mLastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);mCi.getCurrentCalls(mLastRelevantPoll);}}

发现其又调用了mCi.getCurrentCalls去查询当前的Call情况,此方法会调用到RIL中对应的方法去(Phone创建的时候对mCi进行初始化使得具有RIL通信能力,其mCi即调用RIL.java)

又回到了 RIL 中

  • frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java

    @Overridepublic void getCurrentCalls(Message result) {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);}}}

在发送请求后,等待modem返回结果给RIL层,继续跟踪返回消息的接收(省去  与 RIL 层的交互)

在RIL.java中查找底层消息反馈的处理方法,发现有两个方法processRespose和processResponseDone,向上追溯发现其是在RadioResponse.java中的

responseCurrentCalls方法 调用了 processResponseDone 方法,如下:
  • frameworks/opt/telephony/src/java/com/android/internal/telephony/RadioResponse.java

其继承自一个底层的服务

public class RadioResponse extends IRadioResponse.Stub

CurrentCall的消息继续在responseCurrentCalls方法追踪。

    public void getCurrentCallsResponse(RadioResponseInfo responseInfo,ArrayList<android.hardware.radio.V1_0.Call> calls) {responseCurrentCalls(responseInfo, calls);}

继续追踪调用的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 CLCCdc.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 145dc.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();}}

继续回到GsmCdmaCallTracker的handleMessage中,之前发送请求的时候有发送EVENT_POLL_CALLS_RESULT,这里我们继续回到该事件处理的地方来分析

  • frameworks/opt/telephony/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java

    @Overridepublic 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;

继续追踪handlePollCalls

    @Overrideprotected 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 sparseif (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" reasonArrayList<GsmCdmaConnection> locallyDisconnectedConnections = new ArrayList<>();for (int i = mDroppedDuringPoll.size() - 1; i >= 0 ; i--) {GsmCdmaConnection conn = mDroppedDuringPoll.get(i);//CDMAboolean wasDisconnected = false;//来电处理,本地挂断或者未接,本地挂断的话直接设置挂断的原因为LOCAL或INVALID_NUMBERif (conn.isIncoming() && conn.getConnectTime() == 0) {// Missed or rejected callint 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的方法,往上追溯。

继续查看响铃消息通知到何处,全局搜索(registerForNewRingingConnection),找到

PstnIncommingCallNotifier.java

  • 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.*/

用来 监听来电消息

    private final Handler mHandler = new Handler() {@Overridepublic 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传递消息到了应用层了

 private void handleNewRingingConnection(AsyncResult asyncResult) {Log.d(this, "handleNewRingingConnection");Connection connection = (Connection) asyncResult.result;if (connection != null) {Call call = connection.getCall();// Check if we have a pending number verification request.if (connection.getAddress() != null) {if (NumberVerificationManager.getInstance().checkIncomingCall(connection.getAddress())) {// Disconnect the call if it matchestry {connection.hangup();} catch (CallStateException e) {Log.e(this, e, "Error hanging up potential number verification call");}return;}}// Final verification of the ringing state before sending the intent to Telecom.if (call != null && call.getState().isRinging()) {sendIncomingCallIntent(connection);}}}
    private void sendIncomingCallIntent(Connection connection) {------PhoneAccountHandle handle = findCorrectPhoneAccountHandle();if (handle == null) {try {connection.hangup();} catch (CallStateException e) {// connection already disconnected. Do nothing}} else {TelecomManager.from(mPhone.getContext()).addNewIncomingCall(handle, extras);}}

//获取telecomm服务,通过aidl接口调用 telecomService 的addNewIncomingCall方法

 //获取telecomm服务public static TelecomManager from(Context context) {return (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE);}

进入到TelecomService层

  • packages/services/Telecomm/src/com/android/server/telecom/TelecomServiceImpl.java

108      private final ITelecomService.Stub mBinderImpl = new ITelecomService.Stub() {
109          @Override1083          public void addNewIncomingCall(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
1084              try {
1085                  Log.startSession("TSI.aNIC");
1086                  synchronized (mLock) {
1087                      Log.i(this, "Adding new incoming call with phoneAccountHandle %s",
1088                              phoneAccountHandle);
1089                      。。。。。。。。。
。。。。。。。。。
1116                          long token = Binder.clearCallingIdentity();
1117                          try {
1118                              Intent intent = new Intent(TelecomManager.ACTION_INCOMING_CALL);
1119                              intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
1120                                      phoneAccountHandle);
1121                              intent.putExtra(CallIntentProcessor.KEY_IS_INCOMING_CALL, true);
1122                              if (extras != null) {
1123                                  extras.setDefusable(true);
1124                                  intent.putExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS, extras);
1125                              }
1126                              mCallIntentProcessorAdapter.processIncomingCallIntent(
1127                                      mCallsManager, intent);
1128                          } finally {
1129                              Binder.restoreCallingIdentity(token);
1130                          }
1131                      } else {
1132                          Log.w(this, "Null phoneAccountHandle. Ignoring request to add new" +
1133                                  " incoming call");
1134                      }
1135                  }
1136              } finally {
1137                  Log.endSession();
1138              }
1139          }

继续跟进mCallIntentProcessorAdapter.processIncomingCallIntent,

  • packages/services/Telecomm/src/com/android/server/telecom/CallIntentProcessor.java

287      static void processIncomingCallIntent(CallsManager callsManager, Intent intent) {
288          PhoneAccountHandle phoneAccountHandle = intent.getParcelableExtra(
289                  TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE);
290
291          if (phoneAccountHandle == null) {
292              Log.w(CallIntentProcessor.class,
293                      "Rejecting incoming call due to null phone account");
294              return;
295          }
296          if (phoneAccountHandle.getComponentName() == null) {
297              Log.w(CallIntentProcessor.class,
298                      "Rejecting incoming call due to null component name");
299              return;
300          }
301
302          Bundle clientExtras = null;
303          if (intent.hasExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS)) {
304              clientExtras = intent.getBundleExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS);
305          }
306          if (clientExtras == null) {
307              clientExtras = new Bundle();
308          }
309
310          Log.d(CallIntentProcessor.class,
311                  "Processing incoming call from connection service [%s]",
312                  phoneAccountHandle.getComponentName());
313          callsManager.processIncomingCallIntent(phoneAccountHandle, clientExtras);
314      }

--------------------------------------------------------------------------

下方与拨号相同

  • packages/services/Telecomm/src/com/android/server/telecom/CallsManager.java

进入到CallsManager中继续跟进

    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);}}

  • packages/services/Telecomm/src/com/android/server/telecom/Call.java

    void startCreateConnection(PhoneAccountRegistrar phoneAccountRegistrar) {if (mCreateConnectionProcessor != null) {Log.w(this, "mCreateConnectionProcessor in startCreateConnection is not null. This is" +" due to a race between NewOutgoingCallIntentBroadcaster and " +"phoneAccountSelected, but is harmlessly resolved by ignoring the second " +"invocation.");return;}mCreateConnectionProcessor = new CreateConnectionProcessor(this, mRepository, this,phoneAccountRegistrar, mContext);mCreateConnectionProcessor.process();}

继续跟踪process 方法

packages/services/Telecomm/src/com/android/server/telecom/CreateConnectionProcessor.java

    public void process() {Log.v(this, "process");clearTimeout();mAttemptRecords = new ArrayList<>();if (mCall.getTargetPhoneAccount() != null) {mAttemptRecords.add(new CallAttemptRecord(mCall.getTargetPhoneAccount(), mCall.getTargetPhoneAccount()));}if (!mCall.isSelfManaged()) {adjustAttemptsForConnectionManager();adjustAttemptsForEmergency(mCall.getTargetPhoneAccount());}mAttemptRecordIterator = mAttemptRecords.iterator();attemptNextPhoneAccount();}

其中 attemptNextPhoneAccount 方法

    private void attemptNextPhoneAccount() {Log.v(this, "attemptNextPhoneAccount");CallAttemptRecord attempt = null;if (mCallResponse != null && attempt != null) {Log.i(this, "Trying attempt %s", attempt);PhoneAccountHandle phoneAccount = attempt.connectionManagerPhoneAccount;mService = mRepository.getService(phoneAccount.getComponentName(),phoneAccount.getUserHandle());if (mService == null) {Log.i(this, "Found no connection service for attempt %s", attempt);attemptNextPhoneAccount();} else {mConnectionAttempt++;mCall.setConnectionManagerPhoneAccount(attempt.connectionManagerPhoneAccount);mCall.setTargetPhoneAccount(attempt.targetPhoneAccount);mCall.setConnectionService(mService);setTimeoutIfNeeded(mService, attempt);if (mCall.isIncoming()) {mService.createConnection(mCall, CreateConnectionProcessor.this);} else {// Start to create the connection for outgoing call after the ConnectionService// of the call has gained the focus.mCall.getConnectionServiceFocusManager().requestFocus(mCall,new CallsManager.RequestCallback(new CallsManager.PendingAction() {@Overridepublic void performAction() {Log.d(this, "perform create connection");mService.createConnection(mCall,CreateConnectionProcessor.this);}}));}}} else {Log.v(this, "attemptNextPhoneAccount, no more accounts, failing");DisconnectCause disconnectCause = mLastErrorDisconnectCause != null ?mLastErrorDisconnectCause : new DisconnectCause(DisconnectCause.ERROR);notifyCallConnectionFailure(disconnectCause);}}

核心代码:

private ConnectionServiceWrapper mService;   if (mCall.isIncoming()) {mService.createConnection(mCall, CreateConnectionProcessor.this);}
void createConnection(final Call call, final CreateConnectionResponse response) {// 链接创建成功后 onSuccess 会被调用BindCallback callback = new BindCallback() {@Overridepublic void onSuccess() {try {/// M: For VoLTE @{boolean isConferenceDial = call.isConferenceDial();// 会议通话if (isConferenceDial) {logOutgoing("createConference(%s) via %s.", call, getComponentName());mServiceInterface.createConference(call.getConnectionManagerPhoneAccount(),callId,new ConnectionRequest(call.getTargetPhoneAccount(),call.getHandle(),extras,call.getVideoState()),call.getConferenceParticipants(),call.isIncoming());// 非会议(拨打电话会走这里)} else {// 通过远程接口创建链接mServiceInterface.createConnection(call.getConnectionManagerPhoneAccount(),callId,new ConnectionRequest(call.getTargetPhoneAccount(),call.getHandle(),extras,call.getVideoState()),call.isIncoming(),call.isUnknown());}/// @}} catch (RemoteException e) {}}@Overridepublic void onFailure() {}};mBinder.bind(callback, call);
}

mBinder是Binder2对象,Binder2是ConnectionServiceWrapper的父类ServiceBinder内部类,所以此处调用的是的ServiceBinder的内部类的Binder2类的bind()方法,先new一个ServiceConnection对象,然后绑定一个远程服务端服务。如果绑定成功的话,在ServiceBinder的内部类ServiceBinderConnection的onServiceConnected()方法就被调用。
在这里做了两件事:

  1).通过setBinder()方法,回调ConnectionServiceWrapper的setServiceInterface()方法,通过mServiceInterface = IConnectionService.Stub.asInterface(binder);
这行代码获取一个远程服务端的对象mServiceInterface 。
  2)、再通过调用handleSuccessfulConnection()方法回调callback 的onSuccess()方法,也就又回到ConnectionServiceWrapper的createConnection()方法里。调用ConnectionService.java里mBinder的createConnection()方法然后通过message传递调用createConnection()方法。

  • packages/services/Telecomm/src/com/android/server/telecom/ServiceBinder.java

mBider 的bind 方法

void bind(BindCallback callback, Call call) {if (mServiceConnection == null) {Intent serviceIntent = new Intent(mServiceAction).setComponent(mComponentName);ServiceConnection connection = new ServiceBinderConnection(call);// 进行绑定if (mUserHandle != null) {isBound = mContext.bindServiceAsUser(serviceIntent, connection, bindingFlags,mUserHandle);} else {isBound = mContext.bindService(serviceIntent, connection, bindingFlags);}if (!isBound) {handleFailedConnection();return;}} else {}}

绑定成功后,ServiceBinderConnection 的 onServiceConnected 会触发

        @Overridepublic void onServiceConnected(ComponentName componentName, IBinder binder) {try {if (binder != null) {mServiceDeathRecipient = new ServiceDeathRecipient(componentName);try {binder.linkToDeath(mServiceDeathRecipient, 0);mServiceConnection = this;
// 会触发 ConnectionServiceWrapper.setServiceInterface  ==>
ConnectionServiceWrapper.addConnectionServiceAdapter
通过mServiceInterface,给绑定的服务,提供一个访问自己的接口setBinder(binder);// 触发bind(BindCallback callback, Call call) 中 callback 的 onSuccesshandleSuccessfulConnection();} catch (RemoteException e) {Log.w(this, "onServiceConnected: %s died.");if (mServiceDeathRecipient != null) {mServiceDeathRecipient.binderDied();}}}}} finally {Log.endSession();}}

整个绑定过程,只做2件事,

一是给远程服务提供访问自己的接口,

二是利用远程接口创建一个通话链接。

这2件事都是跨进程进行的。远程服务访问自己的接口是 ConnectionServiceWrapper.Adapter , 是一个Binder。

  • packages/services/Telecomm/src/com/android/server/telecom/ConnectionServiceWrapper.java

由内部类 Adapter 继承于 IConnectionServiceAdapter.Stub,可以看出会进行跨进程访问

public class ConnectionServiceWrapper extends ServiceBinder implementsConnectionServiceFocusManager.ConnectionServiceFocus {private final class Adapter extends IConnectionServiceAdapter.Stub {

调用ConnectionService.java里mBinder的createConnection()方法然后通过message传递调用createConnection()方法。

    private void handleSuccessfulConnection() {// Make a copy so that we don't have a deadlock inside one of the callbacks.Set<BindCallback> callbacksCopy = new ArraySet<>();synchronized (mCallbacks) {callbacksCopy.addAll(mCallbacks);mCallbacks.clear();}for (BindCallback callback : callbacksCopy) {callback.onSuccess();}}

通过调用handleSuccessfulConnection()方法回调callback 的onSuccess()方法,也就又回到ConnectionServiceWrapper的createConnection()方法里。

1094      public void createConnection(final Call call, final CreateConnectionResponse response) {
1095          Log.d(this, "createConnection(%s) via %s.", call, getComponentName());
1096          BindCallback callback = new BindCallback() {
1097              @Override
1098              public void onSuccess() {
1099                  String callId = mCallIdMapper.getCallId(call);
1100                  mPendingResponses.put(callId, response);
1101
///---------//1146
1150          // 核心代码
1151                  try {
1152                      mServiceInterface.createConnection(
1153                              call.getConnectionManagerPhoneAccount(),
1154                              callId,
1155                              connectionRequest,
1156                              call.shouldAttachToExistingConnection(),
1157                              call.isUnknown(),
1158                              Log.getExternalSession());
1159
1160                  } catch (RemoteException e) {
1161                      Log.e(this, e, "Failure to createConnection -- %s", getComponentName());
1162                      mPendingResponses.remove(callId).handleCreateConnectionFailure(
1163                              new DisconnectCause(DisconnectCause.ERROR, e.toString()));
1164                  }
1165              }
1166
1167              @Override
1168              public void onFailure() {
1169                  Log.e(this, new Exception(), "Failure to call %s", getComponentName());
1170                  response.handleCreateConnectionFailure(new DisconnectCause(DisconnectCause.ERROR));
1171              }
1172          };
1173
1174          mBinder.bind(callback, call);
1175      }
private IConnectionService mServiceInterface;

线中间的处理过程 和 拨号 流程一样 

----------------------------------------------------------------- 

createConnection()方法通过判断是来电还是去电分别创建不同的connection,

    /*** 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} */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);//判断是来电还是去电创造不同的connectionConnection 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();}}

此处先分析: onCreateIncomingConnection

运行完成后分析:mAdapter.handleCreateConnectionComplete

其中:

    public Connection onCreateIncomingConnection(PhoneAccountHandle connectionManagerPhoneAccount,ConnectionRequest request) {return null;}

当判断是来电时会通过 onCreateIncomingConnection 创建连接,直接跟进去发现是空实现,那么该方法的实现应该在该类的子类中,跟进到其子类TelephonyConnectionService中

  • packages/services/Telephony/src/com/android/services/telephony/TelephonyConnectionService.java

public class TelephonyConnectionService extends ConnectionService {
/*** Service for making GSM and CDMA connections.*/
public class TelephonyConnectionService extends ConnectionService @Overridepublic 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);...}

跳转到 createConnectionFor 方法中

    private 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();if (phoneType == TelephonyManager.PHONE_TYPE_GSM) {returnConnection = new GsmConnection(originalConnection, telecomCallId, isOutgoing);} else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) {boolean allowsMute = allowsMute(phone);returnConnection = new CdmaConnection(originalConnection, mEmergencyTonePlayer,allowsMute, isOutgoing, telecomCallId);}if (returnConnection != null) {// Listen to Telephony specific callbacks from the connectionreturnConnection.addTelephonyConnectionListener(mTelephonyConnectionListener);returnConnection.setVideoPauseSupported(TelecomAccountRegistry.getInstance(this).isVideoPauseSupported(phoneAccountHandle));returnConnection.setManageImsConferenceCallSupported(TelecomAccountRegistry.getInstance(this).isManageImsConferenceCallSupported(phoneAccountHandle));returnConnection.setShowPreciseFailedCause(TelecomAccountRegistry.getInstance(this).isShowPreciseFailedCause(phoneAccountHandle));}return returnConnection;}

继续 分析  mAdapter.handleCreateConnectionComplete

这里通过AIDL进行通信,搜索 IConnectionServiceAdapter.Stub,跟进到 ConnectionServiceWrapper

  • frameworks/base/telecomm/java/android/telecom/ConnectionServiceAdapter.java

    private final class Adapter extends IConnectionServiceAdapter.Stub {@Overridepublic void handleCreateConnectionComplete(String callId, ConnectionRequest request,ParcelableConnection connection, Session.Info sessionInfo) {Log.startSession(sessionInfo, LogUtils.Sessions.CSW_HANDLE_CREATE_CONNECTION_COMPLETE);long token = Binder.clearCallingIdentity();try {synchronized (mLock) {logIncoming("handleCreateConnectionComplete %s", callId);ConnectionServiceWrapper.this.handleCreateConnectionComplete(callId, request, connection);

继续跟进handleCreateConnectionComplete

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 uniformlyCall foundCall = mCallIdMapper.getCall(callId);if (foundCall != null) {// The post-dial digits are created when the call is first created.  Normally// the ConnectionService is responsible for stripping them from the address, but// since a failed connection will not have done this, we could end up with duplicate// post-dial digits.foundCall.clearPostDialDigits();}removeCall(callId, connection.getDisconnectCause());} else {// Successful connectionif (mPendingResponses.containsKey(callId)) {mPendingResponses.remove(callId).handleCreateConnectionSuccess(mCallIdMapper, connection);}}}

mPendingResponses是hashMap容器,每次在 createConnection 的时候会将对象加入该容器,如果此时connection还未断开的,会移除此connection,调用hanleCreateConnectionSuccess方法。
往上追溯CreateConnectionResponse,是一个接口,跟踪到mService.createConnection(mCall, this);

public class CreateConnectionProcessor implements CreateConnectionResponse {

CreateConnectionProcessor.java会把自身传入,发现该类也实现了 CreateConnectionResponse ,所以这里的 handleCreateConnectionSuccess
调用的是这个类里面的方法

  • packages/services/Telecomm/src/com/android/server/telecom/CreateConnectionProcessor.java

private CreateConnectionResponse mCallResponse;@Overridepublic void handleCreateConnectionSuccess(CallIdMapper idMapper,ParcelableConnection connection) {if (mCallResponse == null) {// Nobody is listening for this connection attempt any longer; ask the responsible// ConnectionService to tear down any resources associated with the callmService.abort(mCall);} else {// Success -- share the good news and remember that we are no longer interested// in hearing about any more attempts
// 核心代码mCallResponse.handleCreateConnectionSuccess(idMapper, connection);mCallResponse = null;// If there's a timeout running then don't clear it. The timeout can be triggered// after the call has successfully been created but before it has become active.}}

还是 CreateConnectionResponse 接口

实现的是 Call 对象 ,Call 也实现了该接口

public class Call implements CreateConnectionResponse, EventManager.Loggable,
84          ConnectionServiceFocusManager.CallFocus {
  • packages/services/Telecomm/src/com/android/server/telecom/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:for (Listener l : mListeners) {
// 此处触发了回调l.onSuccessfulIncomingCall(this);}break;
。。。。。

这里根据来电类型,触发回调,监听者会收到通知

,之前在CallManager中执行 processIncomingCallIntent 方法创建Call的时候就添加了监听,所以最后会回调到CallsManager中

  • packages/services/Telecomm/src/com/android/server/telecom/CallsManager.java

可以看出CallsManager的管理作用,创建Calls并添加监听,在完成Call的相关初始化后进行进一步处理,其实就是传递消息到别的的地方去。

    public void onSuccessfulIncomingCall(Call incomingCall) {Log.d(this, "onSuccessfulIncomingCall");PhoneAccount phoneAccount = mPhoneAccountRegistrar.getPhoneAccountUnchecked(incomingCall.getTargetPhoneAccount());Bundle extras =phoneAccount == null || phoneAccount.getExtras() == null? new Bundle(): phoneAccount.getExtras();if (incomingCall.hasProperty(Connection.PROPERTY_EMERGENCY_CALLBACK_MODE) ||incomingCall.isSelfManaged() ||extras.getBoolean(PhoneAccount.EXTRA_SKIP_CALL_FILTERING)) {Log.i(this, "Skipping call filtering for %s (ecm=%b, selfMgd=%b, skipExtra=%b)",incomingCall.getId(),incomingCall.hasProperty(Connection.PROPERTY_EMERGENCY_CALLBACK_MODE),incomingCall.isSelfManaged(),extras.getBoolean(PhoneAccount.EXTRA_SKIP_CALL_FILTERING));onCallFilteringComplete(incomingCall, new CallFilteringResult(true, false, true, true));incomingCall.setIsUsingCallFiltering(false);return;}incomingCall.setIsUsingCallFiltering(true);
//迭代器模式List<IncomingCallFilter.CallFilter> filters = new ArrayList<>();filters.add(new DirectToVoicemailCallFilter(mCallerInfoLookupHelper));filters.add(new AsyncBlockCheckFilter(mContext, new BlockCheckerAdapter(),mCallerInfoLookupHelper, null));filters.add(new CallScreeningServiceController(mContext, this, mPhoneAccountRegistrar,new ParcelableCallUtils.Converter(), mLock,new TelecomServiceImpl.SettingsSecureAdapterImpl(), mCallerInfoLookupHelper,new CallScreeningServiceHelper.AppLabelProxy() {@Overridepublic CharSequence getAppLabel(String packageName) {PackageManager pm = mContext.getPackageManager();try {ApplicationInfo info = pm.getApplicationInfo(packageName, 0);return pm.getApplicationLabel(info);} catch (PackageManager.NameNotFoundException nnfe) {Log.w(this, "Could not determine package name.");}return null;}}));
//IncomingCallFilter创建并执行 performFilteringnew IncomingCallFilter(mContext, this, incomingCall, mLock,mTimeoutsAdapter, filters).performFiltering();}

IncomingCallFilter创建并执行 performFiltering

  • packages/services/Telecomm/src/com/android/server/telecom/callfiltering/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@Overridepublic 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()));}

如果没有超时则在异步查询结束后,会通过回调方法将CallFilterResult传回onCallFilteringComplete.

    public void onCallFilteringComplete(Call call, CallFilteringResult result) {synchronized (mTelecomLock) { // synchronizing to prevent race on mResultmNumPendingFilters--;mResult = result.combine(mResult);if (mNumPendingFilters == 0) {// synchronized on mTelecomLock to enter into Telecom.mHandler.post(new Runnable("ICF.oCFC", mTelecomLock) {@Overridepublic void loggedRun() {if (mIsPending) {Log.addEvent(mCall, LogUtils.Events.FILTERING_COMPLETED, mResult);mListener.onCallFilteringComplete(mCall, mResult);mIsPending = false;}}}.prepare());}}}

然后, 回到CallsManager中进行onCallFilteringComplete处理

  • packages/services/Telecomm/src/com/android/server/telecom/CallsManager.java

    @Overridepublic void onCallFilteringComplete(Call incomingCall, CallFilteringResult result) {...if (incomingCall.getState() != CallState.DISCONNECTED &&incomingCall.getState() != CallState.DISCONNECTING &&incomingCall.getState() != CallState.ACTIVE) {//设置Call状态为RingsetCallState(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 {//添加CalladdCall(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));}}}

跟踪到 addCall 方法

3207      @VisibleForTesting
3208      public void addCall(Call call) {
3209          Trace.beginSection("addCall");
3210          Log.v(this, "addCall(%s)", call);
3211          call.addListener(this);
3212          mCalls.add(call);
3213
3214          // Specifies the time telecom finished routing the call. This is used by the dialer for
3215          // analytics.
3216          Bundle extras = call.getIntentExtras();
3217          extras.putLong(TelecomManager.EXTRA_CALL_TELECOM_ROUTING_END_TIME_MILLIS,
3218                  SystemClock.elapsedRealtime());
3219
3220          updateCanAddCall();
3221          // onCallAdded for calls which immediately take the foreground (like the first call).
3222          for (CallsManagerListener listener : mListeners) {
3223              if (LogUtils.SYSTRACE_DEBUG) {
3224                  Trace.beginSection(listener.getClass().toString() + " addCall");
3225              }
3226              listener.onCallAdded(call);
3227              if (LogUtils.SYSTRACE_DEBUG) {
3228                  Trace.endSection();
3229              }
3230          }
3231          Trace.endSection();
3232      }

//通知监听Call添加的观察者

listener.onCallAdded(call);

添加的观察者,和拨号一样,主要是 CllAudilManager (负责响铃)和  InCallController

        mListeners.add(mInCallWakeLockController);mListeners.add(statusBarNotifier);mListeners.add(mCallLogManager);mListeners.add(mPhoneStateBroadcaster);mListeners.add(mInCallController);mListeners.add(mCallAudioManager);mListeners.add(mCallRecordingTonePlayer);mListeners.add(missedCallNotifier);mListeners.add(mHeadsetMediaButton);mListeners.add(mProximitySensorManager);

其中:

  • packages/services/Telecomm/src/com/android/server/telecom/CallAudioManager.java

private void onCallEnteringRinging() {
641          if (mRingingCalls.size() == 1) {
642              mCallAudioModeStateMachine.sendMessageWithArgs(
643                      CallAudioModeStateMachine.NEW_RINGING_CALL,
644                      makeArgsForModeStateMachine());
645          }
646      }
  • packages/services/Telecomm/src/com/android/server/telecom/InCallController.java

查看 InCallController 的 onCallAdded 方法

    @Overridepublic 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());//添加CalladdCall(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 serviceboolean 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

  • frameworks/base/telecomm/java/android/telecom/InCallService.java

291      /** Manages the binder calls so that the implementor does not need to deal with it. */
292      private final class InCallServiceBinder extends IInCallService.Stub {
293          @Override
294          public void setInCallAdapter(IInCallAdapter inCallAdapter) {
295              mHandler.obtainMessage(MSG_SET_IN_CALL_ADAPTER, inCallAdapter).sendToTarget();
296          }
297
298          @Override
299          public void addCall(ParcelableCall call) {
300              mHandler.obtainMessage(MSG_ADD_CALL, call).sendToTarget();
301          }

继续跟进MSG_ADD_CALL消息的处理

205      /** Default Handler used to consolidate binder method calls onto a single thread. */
206      private final Handler mHandler = new Handler(Looper.getMainLooper()) {
207          @Override
208          public void handleMessage(Message msg) {
209              if (mPhone == null && msg.what != MSG_SET_IN_CALL_ADAPTER) {
210                  return;
211              }
212
213              switch (msg.what) {
214                  case MSG_SET_IN_CALL_ADAPTER:
215                      String callingPackage = getApplicationContext().getOpPackageName();
216                      mPhone = new Phone(new InCallAdapter((IInCallAdapter) msg.obj), callingPackage,
217                              getApplicationContext().getApplicationInfo().targetSdkVersion);
218                      mPhone.addListener(mPhoneListener);
219                      onPhoneCreated(mPhone);
220                      break;
221                  case MSG_ADD_CALL:
222                      mPhone.internalAddCall((ParcelableCall) msg.obj);
223                      break;

继续跟进internalAddCall

  • frameworks/base/telecomm/java/android/telecom/Phone.java

    final void internalAddCall(ParcelableCall parcelableCall) {//创建CallCall 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的监听者的onCallAddedfireCallAdded(call);}private void fireCallAdded(Call call) {for (Listener listener : mListeners) {listener.onCallAdded(this, call);}}    

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

  • frameworks/base/telecomm/java/android/telecom/InCallService.java

    private Phone.Listener mPhoneListener = new Phone.Listener() {/** ${inheritDoc} */@Overridepublic void onAudioStateChanged(Phone phone, AudioState audioState) {InCallService.this.onAudioStateChanged(audioState);}
。。。。。///** ${inheritDoc} */@Overridepublic void onCallAdded(Phone phone, Call call) {InCallService.this.onCallAdded(call);}

这其实是个空实现,具体实现是在子类中,继续跟进到子类 InCallServiceImpl  中分析

  • packages/apps/Dialer/java/com/android/incallui/InCallServiceImpl.java

Dialer  层

public class InCallServiceImpl extends InCallService {private ReturnToCallController returnToCallController;private CallList.Listener feedbackListener;// We only expect there to be one speakEasyCallManager to be instantiated at a time.// We did not use a singleton SpeakEasyCallManager to avoid holding on to state beyond the// lifecycle of this service, because the singleton is associated with the state of the// Application, not this service.private SpeakEasyCallManager speakEasyCallManager;@Overridepublic void onCallAudioStateChanged(CallAudioState audioState) {Trace.beginSection("InCallServiceImpl.onCallAudioStateChanged");AudioModeProvider.getInstance().onAudioStateChanged(audioState);Trace.endSection();}///-----------@Overridepublic void onCallAdded(Call call) {Trace.beginSection("InCallServiceImpl.onCallAdded");InCallPresenter.getInstance().onCallAdded(call);Trace.endSection();}

跟踪到这里可以看到其所在目录是Dialer下的inCallUI了,这就到dialer层了,如果查看Diler的清单文件可以发现其有android.telecom.InCallService声明

  • packages/apps/Dialer/java/com/android/incallui/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的维护列表)调用onCallAddedmCallList.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);}
  • packages/apps/Dialer/java/com/android/incallui/call/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();}...
}

跟踪 onIncoming 方法

  /** Called when a single call has changed. */private void onIncoming(DialerCall call) {Trace.beginSection("CallList.onIncoming");if (updateCallInMap(call)) {LogUtil.i("CallList.onIncoming", String.valueOf(call));}for (Listener listener : listeners) {listener.onIncomingCall(call);}Trace.endSection();}
  • packages/apps/Dialer/java/com/android/incallui/InCallPresenter.java

InCallPresenter 监听来电状态

可以看出 InCallPresenter 实现了 CallList.Listener 的接口,所以可以监听来电的状态

public class InCallPresenter implements CallList.Listener, AudioModeProvider.AudioModeListener {

跟踪到 onCallListChange 方法

  @Overridepublic void onCallListChange(CallList callList) {Trace.beginSection("InCallPresenter.onCallListChange");if (inCallActivity != null && inCallActivity.isInCallScreenAnimating()) {awaitingCallListUpdate = true;Trace.endSection();return;}if (callList == null) {Trace.endSection();return;}awaitingCallListUpdate = false;InCallState newState = getPotentialStateFromCallList(callList);InCallState oldState = inCallState;LogUtil.d("InCallPresenter.onCallListChange","onCallListChange oldState= " + oldState + " newState=" + newState);// If the user placed a call and was asked to choose the account, but then pressed "Home", the// incall activity for that call will still exist (even if it's not visible). In the case of// an incoming call in that situation, just disconnect that "waiting for account" call and// dismiss the dialog. The same activity will be reused to handle the new incoming call. See// a bug for more details.DialerCall waitingForAccountCall;if (newState == InCallState.INCOMING&& (waitingForAccountCall = callList.getWaitingForAccountCall()) != null) {waitingForAccountCall.disconnect();// The InCallActivity might be destroyed or not started yet at this point.if (isActivityStarted()) {inCallActivity.dismissPendingDialogs();}}// 核心代码newState = startOrFinishUi(newState);LogUtil.d("InCallPresenter.onCallListChange", "onCallListChange newState changed to " + newState);// Set the new state before announcing it to the worldLogUtil.i("InCallPresenter.onCallListChange","Phone switching state: " + oldState + " -> " + newState);inCallState = newState;// Foreground call changedDialerCall primary = null;if (newState == InCallState.INCOMING) {primary = callList.getIncomingCall();} else if (newState == InCallState.PENDING_OUTGOING || newState == InCallState.OUTGOING) {primary = callList.getOutgoingCall();if (primary == null) {primary = callList.getPendingOutgoingCall();}} else if (newState == InCallState.INCALL) {primary = getCallToDisplay(callList, null, false);}if (primary != null) {onForegroundCallChanged(primary);}// notify listeners of new statefor (InCallStateListener listener : listeners) {LogUtil.d("InCallPresenter.onCallListChange","Notify " + listener + " of state " + inCallState.toString());listener.onStateChange(oldState, inCallState, callList);}if (isActivityStarted()) {final boolean hasCall =callList.getActiveOrBackgroundCall() != null || callList.getOutgoingCall() != null;inCallActivity.dismissKeyguard(hasCall);}Trace.endSection();}

继续跟踪 startOrFinishUi 方法

private InCallState startOrFinishUi(InCallState newState) {if ((showCallUi || showAccountPicker) && !shouldStartInBubbleMode()) {LogUtil.i("InCallPresenter.startOrFinishUi", "Start in call UI");
// 展示来电界面showInCall(false /* showDialpad */, !showAccountPicker /* newOutgoingCall */);} else if (newState == InCallState.INCOMING) {LogUtil.i("InCallPresenter.startOrFinishUi", "Start Full Screen in call UI");try {PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);PowerHALManager powerHALManager = new PowerHALManager(context, new Handler());PowerHALManager.PowerHintScene sceneIncall = powerHALManager.createPowerHintScene("InCall: InCallPresenter", PowerHintVendorSprd.POWER_HINT_VENDOR_RADIO_CALL, null);if (sceneIncall != null && !pm.isScreenOn()) {Log.i(this, "power Hint POWER_HINT_VENDOR_RADIO_CALL");sceneIncall.acquire(1000);}} catch (java.lang.NoClassDefFoundError e) {LogUtil.e("InCallPresenter.startOrFinishUi", "Exception:" + e.getMessage());} catch (java.util.NoSuchElementException e) {LogUtil.e("InCallPresenter.startOrFinishUi", "Exception:" + e.getMessage());} catch (Exception e) {LogUtil.e("InCallPresenter.startOrFinishUi", "Exception:" + e.getMessage());}} else if (newState == InCallState.NO_CALLS) {// The new state is the no calls state.  Tear everything down.inCallState = newState;attemptFinishActivity();attemptCleanup();}

跟踪 showInCall 方法

  public void showInCall(boolean showDialpad, boolean newOutgoingCall) {LogUtil.i("InCallPresenter.showInCall", "Showing InCallActivity");context.startActivity(InCallActivity.getIntent(context, showDialpad, newOutgoingCall, false /* forFullScreen */));}

至此,显示来电界面。

MO 是从Dialer 发起,MT是从Modem发起。所以两个流程最大的差别也就是如何开始创建Call & connection。当准备开始创建和创建完成后,MO & MT在流程上几乎是没有差异的,都是一些Call & connection的控制,然后通过UI显示出来。

总的来电各层之间的流程:

RIL→TelephonyFramework →TeleponyService→ TeleComService→

TeleComFramework→ TeleComService→TeleComFramework-->InCallUI

安卓10 来电流程梳理相关推荐

  1. 安卓10拨号流程梳理

    电话应用框架 Android电话模块是一个典型的分层结构设计,如下: 电话框架分为4个层次,分别为:应用层.框架层(framework层,简称fw).RIL(Radio Interface Layer ...

  2. 安卓10来电流程详细总结

    来电过程, 是由com.android.phone进程发起的,因为 com.android.phone 进程中 Telephony 直接与Moderm层交互, com.android.phone 进程 ...

  3. 安卓10拨号流程详细总结

    电话应用框架 Android电话模块是一个典型的分层结构设计,如下: 电话框架分为4个层次,分别为:应用层.框架层(framework层,简称fw).RIL(Radio Interface Layer ...

  4. 安卓手机来电亮屏流程分析

    来电亮屏流程分析 本文档是针对手机来电时候自主点亮屏幕这一流程的分析,很自然的就将其分为2个阶段,第一个是来电,第二个是点亮屏幕. 来电的流程: 来电消息是从RIL层接收到的,然后才开始传递上来. A ...

  5. android 刷系统,安卓10的刷机教程,教你刷好Killer的精简包

    本帖最后由 大熊花 于 2020-6-13 22:03 编辑 安卓10真香-- 之前我还退回到安卓9的公测33,心想为了玩游戏流畅,结果发现还是安卓10更好一点. 下午把东西准备齐了刷了killer的 ...

  6. 开发安卓app游戏_「安卓APP开发流程」安卓APP如何开发的?

    21世纪,智能手机走进了人们的生活,现在的智能手机的操作系统基本分为两种,一种是IOS系统(苹果系统).安卓系统,其中,安卓系统是开源的,所以很多品牌商会讲安卓包装成自己的系统,但核心还是一样的,都是 ...

  7. android10rom包,安卓10的刷机教程,教你刷好Killer的精简包

    本帖最后由 大熊花 于 2020-6-13 22:03 编辑 安卓10真香-- 之前我还退回到安卓9的公测33,心想为了玩游戏流畅,结果发现还是安卓10更好一点. 下午把东西准备齐了刷了killer的 ...

  8. Android10支持volte,Nemo_LG V35 安卓10.0解锁Volte(联通、电信、移动)教程_Nemo社区_LinkNemo_关于分享和探索的好地方...

    什么是volte? 早期的4g,只支持上网而不支持通话,这也就意味着当在通话的时候,网络会从4g会回落到3g或者2g上. 而后续随着技术的迭代,推出了volte,就是为了解决4g下通话的问题. LG ...

  9. 安卓app开发方案_「安卓APP开发流程」安卓APP如何开发的?

    21世纪,智能手机走进了人们的生活,现在的智能手机的操作系统基本分为两种,一种是IOS系统(苹果系统).安卓系统,其中,安卓系统是开源的,所以很多品牌商会讲安卓包装成自己的系统,但核心还是一样的,都是 ...

最新文章

  1. tensorflow在训练和验证时监视不同的summary的操作
  2. 20190216 vagrant up 失败问题
  3. windows 禁用ipv6服务_在 Windows 7 中禁用IPv6协议/IPv6隧道
  4. phpstudy mysql5.1_linux下mysql5.1 和 5.7安装教程详解
  5. LNMP与CA认证的童话故事
  6. caffe学习路的起点
  7. 抽奖砍价之类以均值为基础的波动算法 demo版本
  8. 洛谷P3386 【模板】二分图匹配
  9. 【NOIP初赛】【Luogu1787】普及组2013(洛谷初赛题提交水AC方法了解一下)
  10. d3.js(v5.7)的node与数据匹配(自动匹配扩展函数)
  11. C++ 常量引用用法
  12. 【洛谷P3804】统计每个子串出现的次数和长度(后缀自动机模版+拓扑序计数)
  13. font-awesome在Vue项目中的使用(npm使用)
  14. 解析腾讯企业邮箱到自己域名,设置mail的cname
  15. 计算机多媒体化简笔画,计算器简笔画教程
  16. 微信小程序文件下载并保存
  17. python自动做表格_用Python做自动化的表格处理(批量智能替换) - Python趣用之法2...
  18. tcp连接失败触发的异常
  19. QT+ffmpeg+SDL2播放视频流
  20. 系统备份(ghost工具)

热门文章

  1. SQL leetcode刷题答案(一)
  2. CodeForces 1216CodeForces 1221 A~D
  3. 使用@PersistenceContext获取EntityManager报NullPointerException异常
  4. 2020程序员高质量网站集锦(时间有限,网站贵精不贵多,质量最重要)
  5. C# Int16,Int32和Int64的区别
  6. 使用python+Selenium动态爬取《率土之滨》藏宝阁账号信息
  7. 【附源码】计算机毕业设计JAVA东理咨询交流论坛
  8. Object.assign的原理及其实现方式
  9. IEC61850开发流程
  10. Adobe Illustrator CC 制作排版