文章目錄
短多媒體訊息的接收流程
涉及的檔案
com.android.internal.telephony/Ril.javacom.android.internal.telephony/SMSDispatchercom.android.internal.telephony/CommandsInterfacecom.android.internal.telephony/GsmSMSDispatchercom.android.internal.telephony/CdmanSMSDispatchercom.android.internal.telephony/ImsSMSDispatcherhardware/ril/libril/ril.cppcom.android.mms.transaction/PrivilegedSmsReceiver
流程分析時序圖
android ril java層接收短息的流程
1)監聽底層上報的資料
在Ril.java中定義了一個receive的架構:當接收到簡訊時,底層首先通過rild將接收到的簡訊通過socket傳送給Ril.java,那大家都知道這個簡訊接收是一個不定時的,所以就必須有一個監聽器一直監視這個socket一旦有簡訊就觸發其相應的操作。那Ril.java是否有定義這樣的一個監聽器或者類似的功能了?(補充:這涉及一個Modem端與rild的通訊,rild是一個守護進程,是整個android ril層的進入點,這部分筆者不是很清楚,推薦網頁http://blog.163.com/yan_zhennan@126/blog/static/10934475020122275412446/)
通過查看代碼我們可以發現RILReceiver的內部類:
class RILReceiver implements Runnable { byte[] buffer; RILReceiver() { buffer = new byte[RIL_MAX_COMMAND_BYTES]; } public void run() { int retryCount = 0; String rilSocket = "rild"; try {for (;;) { LocalSocket s = null; LocalSocketAddress l; boolean multiRild = SystemProperties.getBoolean("ro.multi.rild", false); if (mInstanceId == 0 || multiRild == false) { rilSocket = SOCKET_NAME_RIL; } else { rilSocket = SOCKET_NAME_RIL1; } try { s = new LocalSocket(); l = new LocalSocketAddress(rilSocket, LocalSocketAddress.Namespace.RESERVED); s.connect(l); } if (retryCount == 8) { Log.e (LOG_TAG, "Couldn't find '" + rilSocket + "' socket after " + retryCount + " times, continuing to retry silently"); } else if (retryCount > 0 && retryCount < 8) { Log.i (LOG_TAG, "Couldn't find '" + rilSocket + "' socket; retrying after timeout"); } try { Thread.sleep(SOCKET_OPEN_RETRY_MILLIS); } catch (InterruptedException er) { } retryCount++; continue; } retryCount = 0; mSocket = s; Log.i(LOG_TAG, "Connected to '" + rilSocket + "' socket"); int length = 0; try { InputStream is = mSocket.getInputStream(); for (;;) { Parcel p; length = readRilMessage(is, buffer); if (length < 0) { // End-of-stream reached break; } p = Parcel.obtain(); p.unmarshall(buffer, 0, length); p.setDataPosition(0);processResponse(p); p.recycle(); }
2)對底層上報的資料進行處理從上面的代碼看出這個線程一直和守護進程rild進行sorcket通訊,並擷取守護進程上報的資料。可以看出做了很多的工作但是最重要的是processResponse()方法向上彙報資料,下面是其處理代碼:
private void processResponse (Parcel p) { int type; type = p.readInt(); if (type == RESPONSE_UNSOLICITED) { processUnsolicited (p); } else if (type == RESPONSE_SOLICITED) { processSolicited (p); } releaseWakeLockIfDone(); }
可以看出在上報資料進行了分類處理,RESPONSE_UNSOLICITED表示接收到資料就直接上報的類型,主動上報,如網路狀態和簡訊、來電等等。RESPONSE_SOLICITED是必須先請求然後才響應的類型。當然這裡是簡訊接收肯定會走前者。processUnsolicited該方法會根據當前的請求的類型,如果是簡訊則是RIL_UNSOL_RESPONSE_NEW_SMS,以下是其調用的代碼;
case RIL_UNSOL_RESPONSE_NEW_SMS: { if (RILJ_LOGD) unsljLog(response); // FIXME this should move up a layer String a[] = new String[2]; a[1] = (String)ret; SmsMessage sms; sms = SmsMessage.newFromCMT(a); if (mSMSRegistrant != null) { mSMSRegistrant .notifyRegistrant(new AsyncResult(null, sms, null)); } break; }
3)追溯該方法,mSMSRegistrant對象的建立過程mSMSRegistrant是BaseCommands的成員變數,且在調用setOnNewSMS()方法來賦值的,BaseCommands是幹什麼的有的童鞋會問,我們看一下Ril.java的繼承關係就知道了,Ril.java是它的子類。瞭解了這些童鞋肯定會問那誰又調用了setOnNewSMS方法?以下是該流程的時序圖。
最後發現該方法設定handler的源頭是在GsmSMSDispatcher類裡,但最後會調用SmsDispatcher的handMessage方法。原因是GsmSMSDispatcher是SmsDispatcher的子類而且GsmSMSDispatcher沒有複寫handMessage方法,所以接收到訊息後肯定由父類的handMessage方法來處理。
到此為止android的ril java層走完了,剩餘的就交給中介層慢慢去做。
注意:
1)這是2.3的代碼,對比一下4.0的代碼可以發現GsmSMSDispatcher複寫了handMessage的方法,自己會去處理,但是僅限於EVENT_NEW_SMS_STATUS_REPORT、EVENT_NEW_BROADCAST_SMS、EVENT_WRITE_SMS_COMPLETE其餘的事件仍由父類SmsDispatcher來完成。
2)4.0中沒有setOnNewSMS該方法,替換成了setOnNewGsmSms、setOnNewCdmaSms方法,對應於不同類型的phone做自己的註冊。
framework SMSDispatcher接收簡訊後的處理流程
中介層SMSDispatcher處理流程:
1)該類做了一件重要的事:
給CommandInterface設定handler的處理方法,就是當接收到簡訊後觸發mSMSRegistrant.notifyRegistrant(new AsyncResult(null, sms, null));方法
然後回調調用之前傳入的handler,接著在handler裡面處理簡訊訊息。
2)handler處理接收到的簡訊訊息:
@Override public void handleMessage(Message msg) { AsyncResult ar; switch (msg.what) { case EVENT_NEW_SMS: // A new SMS has been received by the device if (Config.LOGD) { Log.d(TAG, "New SMS Message Received"); } SmsMessage sms; ar = (AsyncResult) msg.obj; if (ar.exception != null) { Log.e(TAG, "Exception processing incoming SMS. Exception:" + ar.exception); return; } sms = (SmsMessage) ar.result; try { int result = dispatchMessage(sms.mWrappedSmsMessage); if (result != Activity.RESULT_OK) { // RESULT_OK means that message was broadcast for app(s) to // handle. // Any other result, we should ack here. boolean handled = (result == Intents.RESULT_SMS_HANDLED); notifyAndAcknowledgeLastIncomingSms(handled, result, null); } } catch (RuntimeException ex) { Log.e(TAG, "Exception dispatching message", ex); notifyAndAcknowledgeLastIncomingSms(false, Intents.RESULT_SMS_GENERIC_ERROR, null); } break; } }
說明:
int result = dispatchMessage(sms.mWrappedSmsMessage);
該段會通過子類(GsmSMSDispatcher)的dispatchMessage方法處理。
經一系列的判斷處理最後普通簡訊將交給dispatchPdus(pdus);這個方法處理。
protected void dispatchPdus(byte[][] pdus) {Intent intent = new Intent(Intents.SMS_RECEIVED_ACTION);intent.putExtra("pdus", pdus);dispatch(intent, "android.permission.RECEIVE_SMS");}void dispatch(Intent intent, String permission) {// Hold a wake lock for WAKE_LOCK_TIMEOUT seconds, enough to give any// receivers time to take their own wake locks.mWakeLock.acquire(WAKE_LOCK_TIMEOUT);mContext.sendOrderedBroadcast(intent, permission, mResultReceiver,this, Activity.RESULT_OK, null, null);}
3)我們可以看出這個方法將簡訊通過順序廣播播放出去(action是SMS_RECEIVED_ACTION),無論廣播是否被中斷最後都會調用mResultReceiver,這裡會將已讀或未讀的狀態告訴給對方。如果簡訊廣播中間沒有受到終止。然後簡訊app中PrivilegedSmsReceiver廣播接收器接收到廣播後會調用onReceiveWithPrivilege方法,由於PrivilegedSmsReceiver繼承與SmsReceiver,所以會調用父類的該方法。其代碼:
protected void onReceiveWithPrivilege(Context context, Intent intent, boolean privileged) { // If 'privileged' is false, it means that the intent was delivered to the base // no-permissions receiver class. If we get an SMS_RECEIVED message that way, it // means someone has tried to spoof the message by delivering it outside the normal // permission-checked route, so we just ignore it. if (!privileged && (intent.getAction().equals(Intents.SMS_RECEIVED_ACTION) || intent.getAction().equals(Intents.SMS_CB_RECEIVED_ACTION))) { return; } intent.setClass(context, SmsReceiverService.class); intent.putExtra("result", getResultCode()); beginStartingService(context, intent); }
最後交由SmsReceiverService該service去處理,到此為止已經到應用程式層Mms。
多媒體訊息的接收 可能有些童鞋看到這明白了簡訊的接收可能會問到那多媒體訊息的接收又會使什麼樣的了,為瞭解惑所以在此簡單描述多媒體訊息接收的過程,由於很多和簡訊相似。這個過程了就畫一個時序圖個大家,注意:這直到應用程式層,應用程式層的具體實現會有專門的文章來講述。在這以GSM為例,以下是其時序圖: 說明:大家可以看出和簡訊的接收來他們的區別在於dispatchMessage方法會根據smsHeader.portAddrs來判斷當前是多媒體訊息還是簡訊,然後調用對應的方法。總結
這裡沒有去分析rild是怎麼和ril.java 建立socket通訊,也沒有講rild怎麼和moderm端進行通訊的,這些我會繼續研究,希望儘早分享給大家。