写在前面的话
本文主要分析Android 接电话的流程,研究的代码是Android 5.1的,现在我们只关注framework层,以CDMA为例,GSM同理。
关于应用层的流程,请看《Android 5.1 Phone MT(来电)流程分析(应用层)》。
(如果图片看不清的话,可以右键选择在新标签中打开图片,或者把图片另存到自己电脑再查看。)
本文来自 http://blog.csdn.net/linyongan ,转载请务必注明出处。
一、显示来电的界面
步骤1和2: RIL.java的processUnsolicited()方法
接电话的流程是由底层传送到应用层的。首先RIL.java接收到RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED
消息,我们进入RIL.java里查找RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED
的消息的处理逻辑,在
RIL.java
文件里有两个方法processUnsolicited()和responseToString()进行该消息的处理。我们重点关注
processUnsolicited
()方法,该方法会对底层传过来的数据进行收集和整理,然后再完成对应response的逻辑处理和消息通知
private void processUnsolicited (Parcel p) {
...
try {switch(response) {
...
case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED:
ret = responseVoid(p); break;
...
}
switch(response) {
...
case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED:
if (RILJ_LOGD)
unsljLog(response);//打印log日志
//发出通知(RegistrantList消息处理机制)
mCallStateRegistrants.notifyRegistrants(new
AsyncResult(null, null, null));
...
}
}
知识点解析:谁会接受到RIL.java发出的Call状态变化的通知呢?
要找出mCallStateRegistrants
的调用者(在Source Insight这个编译器中,选中mCallStateRegistrants,然后按快捷键Ctrl+/
),找到BaseCommands.java的registerForCallStateChanged()方法,接着继续找它的调用者,最后我们来到
CdmaCallTracker.java的构造方法里
public CdmaCallTracker(CDMAPhone phone) {
...
mCi.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null);
...
}
发觉是CdmaCallTracker.java向RIL注册了一个EVENT_CALL_STATE_CHANGE
类型的Handler消息。
步骤3: 因此,我们在
CdmaCallTracker.java
的handleMessage()方法里可以找到响应EVENT_CALL_STATE_CHANGE
消息类型的处理逻辑,如下:
public void
handleMessage (Message msg) {
...
case EVENT_CALL_STATE_CHANGE:
//调用父类CallTracker查询Call List方法
pollCallsWhenSafe();
break;
...
}
pollCallsWhenSafe()方法是在它的父类CallTracker.java中实现的。
步骤4和5:下面我们来到 CallTracker.java 的pollCallsWhenSafe()方法里。
protected void pollCallsWhenSafe() {
...
if (checkNoOperationsPending()) {
//注意mLastRelevantPoll对象的消息类型,后面会用到
mLastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);
mCi.getCurrentCalls(mLastRelevantPoll);
}
}
在这里通过obtainMessage()创建了一个消息类型为EVENT_POLL_CALLS_RESULT
的Message,并且作为参数传递到RIL.java的getCurrentCalls()方法里。
步骤6: RIL.java的getCurrentCalls()方法
mCi是RIL.java的实例对象,这也就回到了
RIL.java
的getCurrentCalls()方法里,它将RIL_REQUEST_GET_CURRENT_CALLS
消息封装成RILRequest 类型并发送。
public void getCurrentCalls (Message result) {
//注意rr对象的消息类型,后面会用到
RILRequest rr = RILRequest.obtain(
RIL_REQUEST_GET_CURRENT_CALLS, result);
//打印log日志
if (RILJ_LOGD)
riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
send(rr);
}
步骤7和8: RIL.java的processSolicited()方法
RIL向底层发送了查询Call List的请求,底层处理完成之后,就会把处理的结果返回给RIL,RIL.java 有三处接收处理RIL_REQUEST_GET_CURRENT_CALLS
消息,真正的逻辑处理在
processSolicited
()方法里
private RILRequest processSolicited (Parcel p) {
...
case RIL_REQUEST_GET_CURRENT_CALLS:
ret = responseCallList(p); break;
...
//打印log日志
if (RILJ_LOGD) riljLog(rr.serialString() + "< " +
requestToString(rr.mRequest)
+ " " + retToString(rr.mRequest, ret));
if (rr.mResult != null) {
AsyncResult.forMessage(rr.mResult, null, tr);
rr.mResult.sendToTarget();//发出handler消息通知
}
responseCallList()方法会对数据进行收集整理,返回Object类型的ret对象。注意:此时Call的状态为 INCOMING 。
步骤9: CdmaCallTracker.java中的handleMessage()方法
rr.mResult.sendToTarget()发出handler消息通知后,会在
CdmaCallTracker.java
中的handleMessage()方法中响应。并且它的消息类型是EVENT_POLL_CALLS_RESULT
(在本文的第2个小标题的末尾提到)。这里根据Message获取传递的Object数据对象,再调用handlePollCalls处理数据
public void handleMessage (Message msg) {
...
switch (msg.what) {
case EVENT_POLL_CALLS_RESULT:{
//打印log日志
Rlog.d(LOG_TAG, "Event EVENT_POLL_CALLS_RESULT Received");
ar = (AsyncResult)msg.obj;
if(msg == mLastRelevantPoll) {
if(DBG_POLL) log(
"handle EVENT_POLL_CALL_RESULT: set needsPoll=F");
mNeedsPoll = false;
mLastRelevantPoll = null;
handlePollCalls((AsyncResult)msg.obj);
}
}
break;
...
}
步骤10: handlePollCalls()方法根据RIL发出的Call List对象,判断Call的状态并发出通知,这里发出的是新来电通知Phone.notifyNewRingingConnection
protected void
handlePollCalls(AsyncResult ar){
...
if (newRinging != null) {
mPhone.notifyNewRingingConnection(newRinging);
...
}
步骤11: CDMAPhone.java的notifyNewRingingConnection()方法
void notifyNewRingingConnection(Connection c) {
/* we'd love it if this was package-scoped*/
super.notifyNewRingingConnectionP(c);
}
这里调用了父类PhoneBase.java 的方法。
**步骤12:**PhoneBase.java的notifyNewRingingConnectionP()方法
/**
* Notify registrants of a new ringing Connection.
* Subclasses of Phone probably want to replace this with a
* version scoped to their packages
*/
protected void notifyNewRingingConnectionP(Connection cn) {
if (!mIsVoiceCapable)
return;
AsyncResult ar = new AsyncResult(null, cn, null);
mNewRingingConnectionRegistrants.notifyRegistrants(ar);
}
继续发出来电通知。
在PstnIncomingCallNotifier.java的registerForNotifications()方法里看到
/**
* Register for notifications from the base phone.
* TODO: We should only need to interact with the phoneproxy directly. However,
* since the phoneproxy only interacts directly with CallManager we either listen to callmanager
* or we have to poke into the proxy like this. Neither is desirable. It would be better if
* this class and callManager could register generically with the phone proxy instead and get
* radio techonology changes directly. Or better yet, just register for the notifications
* directly with phone proxy and never worry about the technology changes. This requires a
* change in opt/telephony code.
*/
private void registerForNotifications() {
Phone newPhone = mPhoneProxy.getActivePhone();
if (newPhone != mPhoneBase) {
unregisterForNotifications();
if (newPhone != null) {
Log.i(this, "Registering: %s", newPhone);
mPhoneBase = newPhone;
mPhoneBase.registerForNewRingingConnection(
mHandler, EVENT_NEW_RINGING_CONNECTION, null);
mPhoneBase.registerForCallWaiting(
mHandler, EVENT_CDMA_CALL_WAITING, null);
mPhoneBase.registerForSuppServiceNotification(
mHandler, EVENT_SUPP_SERVICE_NOTIFY, null);
mPhoneBase.registerForUnknownConnection(mHandler, EVENT_UNKNOWN_CONNECTION,
null);
}
}
}
是在这里注册监听了EVENT_NEW_RINGING_CONNECTION
,因此PhoneBase.java发出的来电通知会被PstnIncomingCallNotifier.java处理(在Android5.0之前是由CallManager.java来处理)。
步骤13: PstnIncomingCallNotifier.java里mHandler的handleMessage()方法。PstnIncomingCallNotifier.java是在packages\services\telephony\src\com\android\services\telephony目录下的,这里已经来到了应用层,本文暂且分析到这里;在应用层还有很长的流程,详情请看《Android 5.1 Phone MT(来电)流程分析(应用层)》。
二、响铃
步骤14和15: 底层上报RIL_UNSOL_CALL_RING
消息,由RIL.java的processUnsolicited()来处理
private void processUnsolicited (Parcel p) {
...
try {switch(response) {
...
case RIL_UNSOL_CALL_RING:
ret = responseVoid(p); break;
...
}
switch(response) {
...
case RIL_UNSOL_CALL_RING:
if (RILJ_LOGD)
unsljLog(response);//打印log日志
//发出通知
if (mRingRegistrant != null) {
mRingRegistrant.notifyRegistrant(
new AsyncResult (null, ret, null));
}
...
}
}
在PhoneBase.java的构造方法中看到
mCi.setOnCallRing(this, EVENT_CALL_RING, null);
所以RIL.java发出响铃的通知会通知到PhoneBase.java。
步骤16: PhoneBase.java的的handleMessage()方法
@Override
public void handleMessage(Message msg) {
...
switch(msg.what) {
case EVENT_CALL_RING:
Rlog.d(LOG_TAG, "Event EVENT_CALL_RING Received state=" + getState());
ar = (AsyncResult)msg.obj;
if (ar.exception == null) {
PhoneConstants.State state = getState();
if ((!mDoesRilSendMultipleCallRing)
&& ((state == PhoneConstants.State.RINGING) ||
(state == PhoneConstants.State.IDLE))) {
mCallRingContinueToken += 1;
sendIncomingCallRingNotification(mCallRingContinueToken);
} else {
notifyIncomingRing();
}
}
break;
...
}
此时如果没有报异常,而且Call的状态是RINGING,则进入sendIncomingCallRingNotification()方法里。
步骤17和18: PhoneBase.java的的sendIncomingCallRingNotification()方法
/**
* Send the incoming call Ring notification if conditions are right.
*/
private void sendIncomingCallRingNotification(int token) {
if (mIsVoiceCapable && !mDoesRilSendMultipleCallRing &&
(token == mCallRingContinueToken)) {
Rlog.d(LOG_TAG, "Sending notifyIncomingRing");
notifyIncomingRing();
sendMessageDelayed(
obtainMessage(EVENT_CALL_RING_CONTINUE, token, 0), mCallRingDelay);
} else {
Rlog.d(LOG_TAG, "Ignoring ring notification request,"
+ " mDoesRilSendMultipleCallRing=" + mDoesRilSendMultipleCallRing
+ " token=" + token
+ " mCallRingContinueToken=" + mCallRingContinueToken
+ " mIsVoiceCapable=" + mIsVoiceCapable);
}
}
在这里可以看到,除了调用notifyIncomingRing()方法发出来电响铃通知,还调用sendMessageDelayed()发送一个消息类型为EVENT_CALL_RING_CONTINUE
的Message。
步骤19: PhoneBase.java的的handleMessage()方法
@Override
public void handleMessage(Message msg) {
...
switch(msg.what) {
case EVENT_CALL_RING_CONTINUE:
Rlog.d(LOG_TAG, "Event EVENT_CALL_RING_CONTINUE Received stat=" + getState());
if (getState() == PhoneConstants.State.RINGING) {
sendIncomingCallRingNotification(msg.arg1);
}
break;
}
步骤20: 如果Call的状态是RINGING,就重复调用sendIncomingCallRingNotification()方法,重复步骤17~19的流程,直到Call的状态变成OFFHOOK,则响铃这段流程就结束。
三、用户接听电话
步骤21:接听电话的流程是由UI界面一直传递到Framework层,在应用层的流程中,最后是由TelephonyConnection.java传递给Framework层,它调用了CDMAPhone.java的acceptCall()方法
@Override
public void
acceptCall(int videoState) throws CallStateException {
ImsPhone imsPhone = mImsPhone;
if ( imsPhone != null && imsPhone.getRingingCall().isRinging() ) {
imsPhone.acceptCall(videoState);
} else {
mCT.acceptCall();
}
}
mCT就是CdmaCallTracker。
步骤22和23: CdmaCallTracker.java的的acceptCall()方法
void acceptCall() throws CallStateException {
if (mRingingCall.getState() == CdmaCall.State.INCOMING) {
Rlog.i("phone", "acceptCall: incoming...");
// Always unmute when answering a new call
setMute(false);
mCi.acceptCall(obtainCompleteMessage());
} else if (mRingingCall.getState() == CdmaCall.State.WAITING) {
CdmaConnection cwConn = (CdmaConnection)(mRingingCall.getLatestConnection());
// Since there is no network response for supplimentary
// service for CDMA, we assume call waiting is answered.
// ringing Call state change to idle is in CdmaCall.detach
// triggered by updateParent.
cwConn.updateParent(mRingingCall, mForegroundCall);
cwConn.onConnectedInOrOut();
updatePhoneState();
switchWaitingOrHoldingAndActive();
} else {
throw new CallStateException("phone not ringing");
}
}
/**
* Obtain a message to use for signalling "invoke getCurrentCalls() when
* this operation and all other pending operations are complete
*/
private Message
obtainCompleteMessage() {
return obtainCompleteMessage(EVENT_OPERATION_COMPLETE);
}
通过obtainCompleteMessage()方法创建一个消息类型为EVENT_OPERATION_COMPLETE
的Message,再传递给RIL.java的acceptCall()方法。
步骤24: RIL.java的的acceptCall()方法
@Override
public void
acceptCall (Message result) {
RILRequest rr
= RILRequest.obtain(RIL_REQUEST_ANSWER, result);
if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
send(rr);
}
RILJ向底层发送了RIL_REQUEST_ANSWER
请求。
之后的流程相信大家都很熟悉了。
步骤25: 底层回应了RILJ的RIL_REQUEST_ANSWER
请求,接着通知CDMACallTracker来处理。
步骤26~30: CDMACallTracker处理之后,调用RIL.java的getCurrentCalls()请求查询Call的状态列表。
步骤31: 底层返回Call的状态列表,接着通知CDMACallTracker来处理。注意:此时Call的状态为
ACTIVE
。
步骤32~36: CDMACallTracker发出Call状态已改变的通知,向应用层传递,在应用层也有很长的流程,本文就不详细说了,详情请看《Android 5.1 Phone MT(来电)流程分析(应用层)》。
步骤37~39: 重复!!!底层又上报RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED
消息,CDMACallTracker接收到之后,调用RIL.java的getCurrentCalls()请求查询Call的状态列表;底层返回Call的状态列表,接着通知CDMACallTracker来处理;CDMACallTracker发出Call状态已改变的通知,向应用层传递。
最后贴出了来电流程的log片段
10-13 14:07:55.724 D/RILJ ( 3102): [UNSL]< UNSOL_RESPONSE_CALL_STATE_CHANGED [SUB0]
10-13 14:07:55.725 D/RILJ ( 3102): [2401]> GET_CURRENT_CALLS [SUB0]
10-13 14:07:55.811 D/RILJ ( 3102): [2401]< GET_CURRENT_CALLS
[id=1,INCOMING,toa=129,norm,mt,0,voc,noevp,,cli=1,,1] [SUB0]
10-13 14:07:55.823 D/RILJ ( 3102): [UNSL]< UNSOL_CALL_RING [C@184b4a77 [SUB0]
10-13 14:08:21.799 D/RILJ ( 3102): [2417]> SET_MUTE false [SUB0]
10-13 14:08:21.807 D/RILJ ( 3102): [2418]> ANSWER [SUB0]
10-13 14:08:21.814 D/RILJ ( 3102): [2417]< SET_MUTE [SUB0]
10-13 14:08:22.170 D/RILJ ( 3102): [2418]< ANSWER [SUB0]
10-13 14:08:22.185 D/RILJ ( 3102): [UNSL]< UNSOL_RESPONSE_CALL_STATE_CHANGED [SUB0]
10-13 14:08:22.187 D/RILJ ( 3102): [2420]> GET_CURRENT_CALLS [SUB0]
10-13 14:08:22.216 D/RILJ ( 3102): [2419]< GET_CURRENT_CALLS
[id=1,ACTIVE,toa=129,norm,mt,0,voc,noevp,,cli=1,,1] [SUB0]
10-13 14:08:22.248 D/RILJ ( 3102): [2420]< GET_CURRENT_CALLS
[id=1,ACTIVE,toa=129,norm,mt,0,voc,noevp,,cli=1,,1] [SUB0]