《Android 4.4 Kitkat Phone工作流程浅析(二)__UI结构分析》
《Android 4.4 Kitkat Phone工作流程浅析(三)__MO(去电)流程分析》
《Android 4.4 Kitkat Phone工作流程浅析(四)__RILJ工作流程简析》
《Android 4.4 Kitkat Phone工作流程浅析(五)__MT(来电)流程分析》
《Android 4.4 Kitkat Phone工作流程浅析(六)__InCallActivity显示更新流程》
本系列文章以MT/MO为主线流程,并对其中的细枝末节进行补充说明,比如来电响铃流程。在MT流程的分析中已经涵盖了流程的发起与终止,本文所描述的响铃流程始于MT流程的发起,如对MT流程不熟悉的童鞋请查看文章《Android 4.4 Kitkat Phone工作流程浅析(五)__MT(来电)流程分析》以及《Android 4.4 Kitkat Phone工作流程浅析(六)__InCallActivity显示更新流程》。
Android 4.4对于响铃流程有所改动,把响铃触发放到了TeleService中,这也符合4.4 Phone的设计风格即UI和Logic分离。当来电流程发起时,抓取radio_log进行分析后,可以看到整个来电过程状态改变如下:
handleMessage (EVENT_VOICE_CALL_INCOMING_INDICATION) //设置voice call的标志 handleMessage (EVENT_NEW_RINGING_CONNECTION) //新来电标志 handleMessage (EVENT_PRECISE_CALL_STATE_CHANGED) //状态改变 handleMessage (EVENT_INCOMING_RING) //响铃 handleMessage (EVENT_CRSS_SUPP_SERVICE_NOTIFICATION) //收到AT指令CLIP后,更新通话信息(CLIP即来电显示作用) handleMessage (EVENT_INCOMING_RING) handleMessage (EVENT_CRSS_SUPP_SERVICE_NOTIFICATION) handleMessage (EVENT_INCOMING_RING) handleMessage (EVENT_CRSS_SUPP_SERVICE_NOTIFICATION) handleMessage (EVENT_INCOMING_RING) handleMessage (EVENT_CRSS_SUPP_SERVICE_NOTIFICATION) handleMessage (EVENT_INCOMING_RING) handleMessage (EVENT_CRSS_SUPP_SERVICE_NOTIFICATION) handleMessage (EVENT_DISCONNECT) //断开连接 handleMessage (EVENT_PRECISE_CALL_STATE_CHANGED) //状态改变 handleMessage (EVENT_PRECISE_CALL_STATE_CHANGED)这些log是CallManager中打印出来的,当然我们也可以在RIL.java中去查看对应的log。
当Modem侧收到来电消息后所做的操作如下:
1. 根据来电类型设置INCOMING_INDICATION;
2. 发起NEW_RINGING_CONNECTION,新来电标志;
3. 触发CALL_STATE_CHANGED状态,状态改变促使界面更新;
4. 发起响铃通知INCOMING_RING,响铃流程由此发起;
5. 根据CLIP返回信息触发CRSS_SUPP_SERVICE_NOTIFICATION,这是由MTK加入的,其作用是根据CLIP的返回更新Call的信息;
6. 循环上面4和5步,持续响铃;
7. 断开连接DISCONNECT,本次MT流程结束(未接听);
8. 触发CALL_STATE_CHANGED状态,状态改变促使界面更新;
在MT流程发起后,会有相关的unsolicited信息反馈到RILJ中,这里主要关注响铃流程(ringing_flow),因此可以找到以下AT指令返回的log信息:
01-01 02:46:01.154 4753 4768 D use-Rlog/RLOG-AT: +CRING: VOICE 01-01 02:46:01.154 4753 4768 D use-Rlog/RLOG-AT: 01-01 02:46:01.154 4753 4768 D use-Rlog/RLOG-AT: +CLIP: "13800138000",0,"",0,"",0 01-01 02:46:01.154 4753 4768 D use-Rlog/RLOG-AT: 01-01 02:46:01.154 4753 4768 D use-Rlog/RLOG-AT: +ECPI: 1,4,0,1,1,0,"13800138000",129,"" 01-01 02:46:01.154 4753 4768 D use-Rlog/RLOG-AT: AT< +CRING: VOICE 01-01 02:46:01.154 4753 4768 D use-Rlog/RLOG-AT: RIL_URC_READER:+CRING: VOICE 01-01 02:46:01.154 4753 4768 D use-Rlog/RLOG-AT: RIL_URC_READER Enter processLine 01-01 02:46:01.154 4753 4768 D use-Rlog/RLOG-RIL: Nw URC:+CRING: VOICE 01-01 02:46:01.154 4753 4768 D use-Rlog/RLOG-RIL: receiving RING!!!!!! 01-01 02:46:01.154 4753 4768 D use-Rlog/RLOG-RIL: receiving first RING!!!!!!
整个radio_log中每隔3877ms便会打印一次+CRING: VOICE的log,通话挂断前一共有5次。根据AT返回信息可以知道,来电类型为Voice,并且是一次响铃事件。紧接着在RILJ中收到了与之对应的事件RIL_UNSOL_CALL_RING:
01-01 02:46:02.155 1443 1837 D RILJ : RIL(2) :[UNSL RIL]< UNSOL_CALL_RING [C@422899d0这里是UnSolicited事件,触发processUnsolicited方法,并执行到以下代码处:
case RIL_UNSOL_CALL_RING: if (RILJ_LOGD) unsljLogRet(response, ret); if (mRingRegistrant != null) { //观察者模式 mRingRegistrant.notifyRegistrant( new AsyncResult (null, ret, null)); }前面的文章中我们已经分析过Registrant这种触发模式,这里再次分析下notifyRegistrant()方法触发后的跳转地点。
首先查看到mRingRegistrant的定义在SourceCode/frameworks/opt/telephony/src/java/com/android/internal/telephony/BaseCommands.java中,且赋值在setOnCallRing方法中,如下:
@Override public void setOnCallRing(Handler h, int what, Object obj) { mRingRegistrant = new Registrant (h, what, obj); }这里的setOnCallRing方法在SourceCode/frameworks/opt/telephony/src/java/com/android/internal/telephony/PhoneBase.java的构造方法中调用,如下:
mCi.setOnCallRing(this, EVENT_CALL_RING, null);mCi是CommandsInterface的对象,而BaseCommands implements CommandsInterface,也就是说在PhoneBase的构造方法被调用时,就应经完成了对mRingRegistrant的赋值。
(1). PhoneBase extends Handler,因此setOnCallRing中的this即代表了PhoneBase本身。换句话说,当触发notifyRegistrant时,便会回调到PhoneBase的handleMessage中;
(2). setOnCallRing中的EVENT_CALL_RING表示当触发notifyRegistrant时,回调handleMessage中的相应case;
当Phone第一次启动时便会执行PhoneFactory中的makeDefaultPhone()方法,用于完成Phone的初始化,在初始化过程中即完成了mRingRegistrant的注册。
case EVENT_CALL_RING: 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;这里继续查看notifyIncomingRing()方法:
private void notifyIncomingRing() { if (!mIsVoiceCapable) return; AsyncResult ar = new AsyncResult(null, this, null); mIncomingRingRegistrants.notifyRegistrants(ar); }同样使用了观察者模式,查找相应的registerXXX方法,如下:
@Override public void registerForIncomingRing( Handler h, int what, Object obj) { checkCorrectThread(h); mIncomingRingRegistrants.addUnique(h, what, obj); }可以找到在CallManager的registerForPhoneStates方法中,调用了IncomingRing的register方法:
if (FeatureOption.MTK_GEMINI_SUPPORT == true && !(phone instanceof SipPhone)) {
if(phone instanceof GeminiPhone) {
int offset;
int count = (MAXIMUM_SIM_COUNT < PhoneConstants.GEMINI_SIM_NUM) ? MAXIMUM_SIM_COUNT : PhoneConstants.GEMINI_SIM_NUM;
Phone targetPhone;
for (int i = 0; i < count; i++) {
offset = i * NOTIFICATION_ID_OFFSET;
targetPhone = ((GeminiPhone)phone).getPhonebyId(PhoneConstants.GEMINI_SIM_1 + i);
//... ...省略
targetPhone.registerForIncomingRing(mHandler, EVENT_INCOMING_RING + offset, null);
这里涉及到MTK的双卡机制,同时可能大家会有疑惑如何断定是这里调用的呢?我们可以反向思考,当发现这里调用之后,我们反过来看是哪里调用了registerForPhoneStates,然后依次查看。最终我们可以看到这些都是在Phone初始化时候顺序调用的,我们只是反过来查找而已。
通过上面CallManager中的代码可以知道:
(1). mHandler在CallManager中定义,相关handleMessage即可找到;
(2). case对应事件为:EVENT_INCOMING_RING;
mIncomingRingRegistrants的注册流程始于Phone启动并初始化时,需要关注的一点是CallManager中的registerForPhoneStates()方法。为什么这里直接从CallManager跳转到PhoneBase呢?实际上targetPhone对象是通过PhoneProxy传递过来的,而PhoneProxy是GSMPhone和CDMAPhone的代理,GSMPhone和CDMAPhone都继承自PhoneBase,最终的实现也在PhoneBase中,这里省略了部分跳转,请读者知悉。
根据前面的分析,在PhoneBase的notifyIncomingRing()方法中会调用mIncomingRingRegistrants.notifyRegistrants()方法,可以找到在CallManager中对应的handleMessage方法以及对应的处理事件EVENT_INCOMING_RING:
@Override public void handleMessage(Message msg) { int index; switch (msg.what) { //... ...省略 case EVENT_INCOMING_RING: case EVENT_INCOMING_RING + NOTIFICATION_ID_OFFSET: case EVENT_INCOMING_RING + (NOTIFICATION_ID_OFFSET * 2): case EVENT_INCOMING_RING + (NOTIFICATION_ID_OFFSET * 3): if (!hasActiveFgCall()) { index = (msg.what - EVENT_INCOMING_RING) / NOTIFICATION_ID_OFFSET; mIncomingRingRegistrantsGemini[index].notifyRegistrants((AsyncResult) msg.obj); mIncomingRingRegistrants.notifyRegistrants((AsyncResult) msg.obj); } break;看到这里继续查看mIncomingRingRegistrantsGemini和mIncomingRingRegistrants的registerXXX方法,代码如下:
//mIncomingRingRegistrantsGemini的registe方法 public void registerForIncomingRingEx(Handler h, int what, Object obj, int simId){ int index = getRegistrantsArrayIndex(simId); if (index != -1) { mIncomingRingRegistrantsGemini[index].addUnique(h, what, obj); } } //mIncomingRingRegistrants的registe方法 public void registerForIncomingRing(Handler h, int what, Object obj){ mIncomingRingRegistrants.addUnique(h, what, obj); }以上方法会根据手机制式来调用,如果是双卡则调用Gemini,在CallManagerWrapper中可以找到:
public static void registerForIncomingRing(Handler handler, int what, Object obj) { if (GeminiUtils.isGeminiSupport()) { final int[] geminiSlots = GeminiUtils.getSlots(); for (int geminiSlot : geminiSlots) { //双卡 CallManager.getInstance().registerForIncomingRingEx(handler, what, obj, geminiSlot); } } else { //单卡 CallManager.getInstance().registerForIncomingRing(handler, what, obj); } }而以上方法在CallManagerWrapper中还经过了一层包装:
public static void registerForIncomingRing(Handler handler, int what) { registerForIncomingRing(handler, what, null); }那么后续调用是在哪里呢?我们可以在CallStateMonitor的registerForNotifications()方法中找到:
CallManagerWrapper.registerForIncomingRing(this, PHONE_INCOMING_RING);而registerForNotifications()方法在CallStateMonitor初始化以及Radio状态改变的时候会调用。
通过以上分析我们可以知道:
(1). 在CallStateMonitor中注册了来电响铃回调,也就是这里的this。CallStateMonitor继承自Handler,那么CallManager中的notifyRegistrants()方法会跳转到CallStateMonitor中;
(2). 对应的case事件为:PHONE_INCOMING_RING;
整个注册流程是从TeleService启动时开始的,TeleService有监听BOOT_COMPLETE的广播,在随机启动之后便开始了整个注册流程。在第8步需要注意,双卡执行CallManager.getInstance().registerForIncomingRingEx(),单卡则执行CallManager.getInstance().registerForIncomingRing()。
@Override public void handleMessage(Message msg) { for (Handler handler : registeredHandlers) { handler.handleMessage(msg); } }这里会根据registerHandler触发对应的回调,在前面来电(MT)流程的分析过程有看到,CallNotifier和CallModeler注册了CallStateMonitor的Handler回调,但通过进一步分析后发现,只有CallNotifier中才处理了PHONE_INCOMING_RING的事件,所以接着我们需要查看CallNotifier对响铃事件的处理。
@Override public void handleMessage(Message msg) { //... ...省略 case CallStateMonitor.PHONE_INCOMING_RING: log("PHONE_INCOMING_RING !"); if (msg.obj != null && ((AsyncResult) msg.obj).result != null) { //... ...省略 if (provisioned && !isRespondViaSmsDialogShowing()) { mRinger.ring(); } } else { if (DBG) log("RING before NEW_RING, skipping"); } } break;通过这里会调用Ringer的ring()方法,从而开始响铃。
void ring() { synchronized (this) { //... ...省略 //创建Looper线程,用于播放/停止铃声,通过handleMessage接收播放/停止请求 makeLooper(); //如果是第一次播放则mFirstRingEventTime = -1 if (mFirstRingEventTime < 0) { //这里获取系统开机后经过的时间,包括休眠 mFirstRingEventTime = SystemClock.elapsedRealtime(); if (mRingHandler != null) { //发起播放铃声的请求 mRingHandler.sendEmptyMessage(PLAY_RING_ONCE); } } else { //如果不是第一次播放 if (mFirstRingStartTime > 0) { if (mRingHandler != null) { //延迟发送播放请求,延迟时间为第一次启动播放时间减去第一次发送PLAY_RING_ONCE的时间(133ms) mRingHandler.sendEmptyMessageDelayed(PLAY_RING_ONCE, mFirstRingStartTime - mFirstRingEventTime); } } else { mFirstRingEventTime = SystemClock.elapsedRealtime(); } } } }在这里就要特别注意了,通过makeLooper()方法创建了一个Looper线程,用于播放/停止铃声,那这里为什么要用Looper呢?
private void makeLooper() { //如果第一响铃mRingThread==null if (mRingThread == null) { //Worker实现了Runnable接口,在其构造方法Worker(String name) //中创建并启动了名为"ringer"的工作线程 mRingThread = new Worker("ringer"); //若还未获取到ringer线程的Looper对象则返回 if (mRingThread.getLooper() == null) { return ; } //创建Handler并依附于ringer线程的Looper对象 mRingHandler = new Handler(mRingThread.getLooper()) { @Override public void handleMessage(Message msg) { Ringtone r = null; switch (msg.what) { case PLAY_RING_ONCE: if (DBG) log("mRingHandler: PLAY_RING_ONCE..."); if (mRingtone == null && !hasMessages(STOP_RING)) { // create the ringtone with the uri if (DBG) log("creating ringtone: " + mCustomRingtoneUri); r = RingtoneManager.getRingtone(mContext, mCustomRingtoneUri); synchronized (Ringer.this) { if (!hasMessages(STOP_RING)) { mRingtone = r; } } } r = mRingtone; if (r != null && !hasMessages(STOP_RING) && !r.isPlaying()) { PhoneLog.d(LOG_TAG, "play ringtone... "); PhoneUtils.setAudioMode(); //播放铃声 r.play(); synchronized (Ringer.this) { //将第一次播放时间(开机后的时间包括休眠)赋值给mFirstRingStartTime if (mFirstRingStartTime < 0) { mFirstRingStartTime = SystemClock.elapsedRealtime(); } } } break; case STOP_RING: if (DBG) log("mRingHandler: STOP_RING..."); r = (Ringtone) msg.obj; if (r != null) { //停止播放铃声 r.stop(); } else { if (DBG) log("- STOP_RING with null ringtone! msg = " + msg); } //退出Looper循环 getLooper().quit(); break;
private class Worker implements Runnable { //创建mLock锁 private final Object mLock = new Object(); private Looper mLooper; Worker(String name) { //创建并启动名为"name"的线程 Thread t = new Thread(null, this, name); t.start(); synchronized (mLock) { while (mLooper == null) { try { //阻塞直到前面的"name"线程已成功运行(执行了run方法),最大阻塞时间5s mLock.wait(5000); } catch (InterruptedException ex) { } } } } public Looper getLooper() { //返回"name"线程的Looper对象 return mLooper; } public void run() { synchronized (mLock) { //启用Looper Looper.prepare(); //返回当前线程(也就是这里的子线程"name")的Looper对象 mLooper = Looper.myLooper(); //唤醒锁,不再阻塞 mLock.notifyAll(); } //开启Looper循环 Looper.loop(); } public void quit() { //退出Looper循环 mLooper.quit(); } }Looper用于在线程中开启消息循环,普通线程默认是没有消息循环的,在线程中通过调用Looper.prepare()开启消息循环,通过Looper.loop()处理消息循环直到线程循环终止,我们可以调用Looper的quit()方法退出循环。