对于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.
具体的代码如下:
Step1.接收Modem上报的call状态变化的消息。
http://androidxref.com/8.1.0_r33/xref/frameworks/opt/telephony/src/java/com/android/internal/telephony/RadioIndication.java
// 得到消息后,就去通知监听这个消息的对象
public void callStateChanged(int indicationType) {
mRil.processIndication(indicationType);
if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED);
mRil.mCallStateRegistrants.notifyRegistrants();
}
Step2.处理从Modem上报的call状态变化的消息。代码里可以看出GsmCdmaCallTracker.java有注册该监听:
http://androidxref.com/8.1.0_r33/xref/frameworks/opt/telephony/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java
// 初始化时,监听EVENT_CALL_STATE_CHANGE消息
public GsmCdmaCallTracker (GsmCdmaPhone phone) {
......
mCi.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null);
......
}
// handle 处理
@Override
public void handleMessage(Message msg) {
AsyncResult ar;
switch (msg.what) {
......
case EVENT_CALL_STATE_CHANGE:
// 该方法并没有在GsmCdmaCallTracker重写,所以要在父类中查看该方法
pollCallsWhenSafe();
break;
......
}
}
Step3. 处理完后,向Modem请求Call的信息。
http://androidxref.com/8.1.0_r33/xref/frameworks/opt/telephony/src/java/com/android/internal/telephony/CallTracker.java
protected void pollCallsWhenSafe() {
mNeedsPoll = true;
if (checkNoOperationsPending()) {
mLastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);
// 通过RIL向Modem发起请求
mCi.getCurrentCalls(mLastRelevantPoll);
}
}
Step4. 当Modem处理完毕后,就返回这个response.
http://androidxref.com/8.1.0_r33/xref/frameworks/opt/telephony/src/java/com/android/internal/telephony/RadioResponse.java
/**
* @param responseInfo Response info struct containing response type, serial no.
* and error
* @param calls Current call list
*/
public void getCurrentCallsResponse(RadioResponseInfo responseInfo,
ArrayList calls) {
responseCurrentCalls(responseInfo, calls);
}
/**
* 处理这个消息,然后返回给请求者
*/
private void responseCurrentCalls(RadioResponseInfo responseInfo,
ArrayList calls) {
RILRequest rr = mRil.processResponse(responseInfo);
if (rr != null) {
......
/**
* 处理消息体,发现其通过底层返回的消息创建了dcCalls对象,也就是当前的Call状态信
* 息,对dc状态进行判断后如果有需要就notify通知,如果没有异常则通过
* sendMessageResponse方法发送消息。这部分就和N的一样了,将返回值返回给当初的请求
*者,由请求者去决定如何处理。
*/
if (responseInfo.error == RadioError.NONE) {
sendMessageResponse(rr.mResult, dcCalls);
}
mRil.processResponseDone(rr, responseInfo, dcCalls);
}
}
Step5: 处理response。在Step3时候可以看到,CallTracker发起了请求,所以RIL返回的reponse就返回到CallTracker.查看了CallTracker里并没有处理EVENT_POLL_CALLS_RESULT的消息,查看了子类GsmCdmaCallTracker.java中有处理该消息:
http://androidxref.com/8.1.0_r33/xref/frameworks/opt/telephony/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java#EVENT_POLL_CALLS_RESULT
//****** Overridden from Handler
@Override
public void handleMessage(Message msg) {
AsyncResult ar;
switch (msg.what) {
case EVENT_POLL_CALLS_RESULT:
Rlog.d(LOG_TAG, "Event EVENT_POLL_CALLS_RESULT Received");
if (msg == mLastRelevantPoll) {
if (DBG_POLL) log(
"handle EVENT_POLL_CALL_RESULT: set needsPoll=F");
mNeedsPoll = false;
mLastRelevantPoll = null;
handlePollCalls((AsyncResult)msg.obj);
}
break;
...
}
}
// ***** Overwritten from CallTracker
@Override
protected synchronized void handlePollCalls(AsyncResult ar) {
List polledCalls;
...
if (newRinging != null) {
//通知newRinging
mPhone.notifyNewRingingConnection(newRinging);
}
...
}
Step6: 查看响铃的通知。查找这个通知,最终是PstnIncomingCallNotifier来处理这个通知。
http://androidxref.com/8.1.0_r33/xref/packages/services/Telephony/src/com/android/services/telephony/PstnIncomingCallNotifier.java
/**
* Used to listen to events from {@link #mPhone}.
*/
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch(msg.what) {
case EVENT_NEW_RINGING_CONNECTION:
handleNewRingingConnection((AsyncResult) msg.obj);
break;
...
}
}
};
/**
* Verifies the incoming call and triggers sending the incoming-call intent to
* Telecom.
* @param asyncResult The result object from the new ringing event.
*/
private void handleNewRingingConnection(AsyncResult asyncResult) {
...
if (call != null && call.getState().isRinging()) {
sendIncomingCallIntent(connection);
}
}
/**
* Sends the incoming call intent to telecom.
*/
private void sendIncomingCallIntent(Connection connection) {
...
TelecomManager.from(mPhone.getContext()).addNewIncomingCall(handle, extras);
}
至此,已经将RIL消息处理完毕,然后发出这个intent.将Modem上报的response向上层传递。大概的方法传递如下:
Step7: Packages/service里的处理,intent的传递。 在Step6中,通过获取Telecomm的service.然后去调用addNewIncomingCall,通过aidl接口调用 telecomService 的addNewIncomingCall方法。查看具体实现的地方:
http://androidxref.com/8.1.0_r33/xref/packages/services/Telecomm/src/com/android/server/telecom/TelecomServiceImpl.java#addNewIncomingCall
/**
* @see android.telecom.TelecomManager#addNewIncomingCall
*/
@Override
public void addNewIncomingCall(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
......
Intent intent = new Intent(TelecomManager.ACTION_INCOMING_CALL);
intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
phoneAccountHandle);
intent.putExtra(CallIntentProcessor.KEY_IS_INCOMING_CALL, true);
if (extras != null) {
extras.setDefusable(true);
intent.putExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS, extras);
}
mCallIntentProcessorAdapter.processIncomingCallIntent(
mCallsManager, intent);
......
}
继续跟进代码:
http://androidxref.com/8.1.0_r33/xref/packages/services/Telecomm/src/com/android/server/telecom/CallIntentProcessor.java
static void processIncomingCallIntent(CallsManager callsManager, Intent intent) {
PhoneAccountHandle phoneAccountHandle = intent.getParcelableExtra(
TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE);
...
callsManager.processIncomingCallIntent(phoneAccountHandle, clientExtras);
}
/**
* Starts the process to attach the call to a connection service.
*
* @param phoneAccountHandle The phone account which contains the component name of the
* connection service to use for this call.
* @param extras The optional extras Bundle passed with the intent used for the incoming call.
*/
void processIncomingCallIntent(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
...
if (!isHandoverAllowed || (call.isSelfManaged() && !isIncomingCallPermitted(call,
call.getTargetPhoneAccount()))) {
notifyCreateConnectionFailed(phoneAccountHandle, call);
} else {
//通过这个call 来开始创建Connection
call.startCreateConnection(mPhoneAccountRegistrar);
}
}
这块的代码走向大概如下:
Step8:开始创建connection。这里和之前MO的流程是一样的,创建了一个Call然后调用startCreateConnection去创建connection。没有太多的逻辑调用,大概的代码走向如下:
Setp9: 对Call进行处理。这里的流程也没有太大的逻辑,且与MO相似:
Setp10:显示UI界面,与MO一致
MO与MT最大的差异就是MT & MO发起。MO 是从Dialer 发起,MT是从Modem发起。所以两个流程最大的差别也就是如何开始创建Call & connection。当准备开始创建和创建完成后,MO & MT在流程上几乎是没有差异的,都是一些Call & connection的控制,然后通过UI显示出来。该篇主要的流程分析主要就放在Modem消息的上报以及处理。