来电过程, 是由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状态改变
@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:
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();
}
- 调用processIndication向底层发送确认收到消息
- 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
搜索到有:
- BaseCommands
- GsmCdmaCallTracker
- CommandsInterface
其中BascCommands,CommandsInterface都是接口
mCalIStateReg istrants. notifyRegistrant 发出通知后,仅一个 地方可响应此消息通知,即GsmCdmaCallTracker 类的handleMessage 方法,本质上是个Handler处理类
跟进GsmCdmaCallTracker的handleMessage方法,可以看到其在初始化的地方注册了CallStateChanged消息的监听,注册的时候传入了自身的handler,notify的时候使用该handler发送消息,所以我们可以在handleMessage中响应并处理EVENT_CALL_STATE_CHANGE消息。
@Override
public void handleMessage(Message msg) {
AsyncResult ar;
switch (msg.what) {
...
case EVENT_CALL_STATE_CHANGE:
pollCallsWhenSafe();
...
pollCallsWhenSafe 调用父类CallTracker 方法
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 中
@Override
public 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 方法,如下:
其继承自一个底层的服务
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 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();
}
}
继续回到GsmCdmaCallTracker的handleMessage中,之前发送请求的时候有发送EVENT_POLL_CALLS_RESULT,这里我们继续回到该事件处理的地方来分析
@Override
public void handleMessage(Message msg) {
AsyncResult ar;
switch (msg.what) {
case EVENT_POLL_CALLS_RESULT:
Rlog.d(LOG_TAG, "Event EVENT_POLL_CALLS_RESULT Received");
if (msg == mLastRelevantPoll) {
if (DBG_POLL) log(
"handle EVENT_POLL_CALL_RESULT: set needsPoll=F");
mNeedsPoll = false;
mLastRelevantPoll = null;
handlePollCalls((AsyncResult)msg.obj);
}
break;
继续追踪handlePollCalls
@Override
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的方法,往上追溯。
继续查看响铃消息通知到何处,全局搜索(registerForNewRingingConnection),找到
PstnIncommingCallNotifier.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() {
@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传递消息到了应用层了
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 matches
try {
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层
108 private final ITelecomService.Stub mBinderImpl = new ITelecomService.Stub() {
109 @Override
1083 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,
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 }
--------------------------------------------------------------------------
下方与拨号相同
进入到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);
}
}
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() {
@Override
public 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() {
@Override
public 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) {
}
}
@Override
public 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()方法。
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 会触发
@Override
public 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 的 onSuccess
handleSuccessfulConnection();
} catch (RemoteException e) {
Log.w(this, "onServiceConnected: %s died.");
if (mServiceDeathRecipient != null) {
mServiceDeathRecipient.binderDied();
}
}
}
}
} finally {
Log.endSession();
}
}
整个绑定过程,只做2件事,
一是给远程服务提供访问自己的接口,
二是利用远程接口创建一个通话链接。
这2件事都是跨进程进行的。远程服务访问自己的接口是 ConnectionServiceWrapper.Adapter
, 是一个Binder。
由内部类 Adapter 继承于 IConnectionServiceAdapter.Stub,可以看出会进行跨进程访问
public class ConnectionServiceWrapper extends ServiceBinder implements
ConnectionServiceFocusManager.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);
//判断是来电还是去电创造不同的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();
}
}
此处先分析: onCreateIncomingConnection
运行完成后分析:mAdapter.handleCreateConnectionComplete
其中:
public Connection onCreateIncomingConnection(
PhoneAccountHandle connectionManagerPhoneAccount,
ConnectionRequest request) {
return null;
}
当判断是来电时会通过 onCreateIncomingConnection 创建连接,直接跟进去发现是空实现,那么该方法的实现应该在该类的子类中,跟进到其子类TelephonyConnectionService中
public class TelephonyConnectionService extends ConnectionService {
/**
* Service for making GSM and CDMA connections.
*/
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);
...
}
跳转到 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 connection
returnConnection.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
private final class Adapter extends IConnectionServiceAdapter.Stub {
@Override
public 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 uniformly
Call 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 connection
if (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
调用的是这个类里面的方法
private CreateConnectionResponse mCallResponse;
@Override
public 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 call
mService.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 {
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中
可以看出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() {
@Override
public 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创建并执行 performFiltering
new IncomingCallFilter(mContext, this, incomingCall, mLock,
mTimeoutsAdapter, filters).performFiltering();
}
IncomingCallFilter创建并执行 performFiltering
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()));
}
如果没有超时则在异步查询结束后,会通过回调方法将CallFilterResult传回onCallFilteringComplete.
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());
}
}
}
然后, 回到CallsManager中进行onCallFilteringComplete处理
@Override
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));
}
}
}
跟踪到 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);
其中:
private void onCallEnteringRinging() {
641 if (mRingingCalls.size() == 1) {
642 mCallAudioModeStateMachine.sendMessageWithArgs(
643 CallAudioModeStateMachine.NEW_RINGING_CALL,
644 makeArgsForModeStateMachine());
645 }
646 }
查看 InCallController 的 onCallAdded 方法
@Override
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
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
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);
}
}
在 InCallService 中handleMessage处理MSG_SET_IN_CALL_ADAPTER消息的时候就注册了监听,这里继续跟进到InCallService中的实现去
private Phone.Listener mPhoneListener = new Phone.Listener() {
/** ${inheritDoc} */
@Override
public void onAudioStateChanged(Phone phone, AudioState audioState) {
InCallService.this.onAudioStateChanged(audioState);
}
。。。。。//
/** ${inheritDoc} */
@Override
public void onCallAdded(Phone phone, Call call) {
InCallService.this.onCallAdded(call);
}
这其实是个空实现,具体实现是在子类中,继续跟进到子类 InCallServiceImpl 中分析
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;
@Override
public void onCallAudioStateChanged(CallAudioState audioState) {
Trace.beginSection("InCallServiceImpl.onCallAudioStateChanged");
AudioModeProvider.getInstance().onAudioStateChanged(audioState);
Trace.endSection();
}
///-----------
@Override
public void onCallAdded(Call call) {
Trace.beginSection("InCallServiceImpl.onCallAdded");
InCallPresenter.getInstance().onCallAdded(call);
Trace.endSection();
}
跟踪到这里可以看到其所在目录是Dialer下的inCallUI了,这就到dialer层了,如果查看Diler的清单文件可以发现其有android.telecom.InCallService声明
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);
}
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();
}
InCallPresenter 监听来电状态
可以看出 InCallPresenter 实现了 CallList.Listener 的接口,所以可以监听来电的状态
public class InCallPresenter implements CallList.Listener, AudioModeProvider.AudioModeListener {
跟踪到 onCallListChange 方法
@Override
public 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 world
LogUtil.i(
"InCallPresenter.onCallListChange",
"Phone switching state: " + oldState + " -> " + newState);
inCallState = newState;
// Foreground call changed
DialerCall 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 state
for (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