Document directory
Receiving PROCESS OF SHORT MMS
Involved files
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
Process Analysis sequence diagram
Process for receiving messages at the android RIL Java Layer
1) Listen to the data reported at the underlying layer
In RIL. java defines a receive framework: when receiving a text message, the underlying layer first transmits the received text message to RIL through rild through socket. java, then we all know that this short message is received at an irregular time, so there must be a listener that keeps monitoring this socket. Once there is a short message, it will trigger corresponding operations. Does RIL. Java define such a listener or similar functions? (Supplement: This involves the communication between modem and rild. rild is a daemon and the entry point of the entire android RIL layer. I am not very clear about this part. I recommend the webpage http://blog.163.com/yan_zhennan@126/blog/static/10934475020122275412446)
By viewing the code, we can find the internal class of 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) process the data reported at the underlying layer. From the code above, we can see that this thread has been communicating with the rild of the daemon, and obtains the data reported by the daemon. We can see that a lot of work has been done, but the most important thing is that the processresponse () method reports data up. The following is the processing code:
private void processResponse (Parcel p) { int type; type = p.readInt(); if (type == RESPONSE_UNSOLICITED) { processUnsolicited (p); } else if (type == RESPONSE_SOLICITED) { processSolicited (p); } releaseWakeLockIfDone(); }
It can be seen that the reported data is classified. response_unsolicited indicates the type directly reported when the data is received, and actively reported, such as the network status, SMS, and incoming calls. Response_solicited is the type that must be requested before response. Of course, the text message reception will certainly follow the former. Processunsolicited this method will be based on the type of the current request. For short messages, ril_unsol_response_new_sms. The following is the code it calls;
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) trace back to this method. During the creation process of the msmsregistrant object, msmsregistrant is a member variable of basecommands and is assigned a value by calling the setonnewsms () method. Some children's shoes who do basecommands will ask, let's take a look at RIL. the inheritance relationship of Java is known, rIL. java is its subclass. After learning about these shoes, I will certainly ask who has called the setonnewsms method? The following figure shows the sequence of the process.
Finally, we found that the source of handler setting in this method is in the gsmsmsdispatcher class, but at last we will call the handmessage method of smsdispatcher. The reason is that gsmsmsdispatcher is a subclass of smsdispatcher, and gsmsmsdispatcher does not have the handmessage Method for rewriting. Therefore, the handmessage method of the parent class must process the received message.
So far, the RIL Java layer of Android is finished, and the rest will be handed over to the middle layer for further implementation.
Note:
1) This is the 2.3 code. By comparing the 4.0 code, we can find that the handsmsdispatcher rewrites the handmessage method and will handle it on its own, however, only event_new_sms_status_report, event_new_broadcast_sms, and event_write_sms_complete events are completed by the parent class smsdispatcher.
2) If the setonnewsms method is not found in 4.0, it is replaced with the setonnewgsmsms and setonnewcdmasms methods, which correspond to different types of phones for registration.
Process after the Framework smsdispatcher receives the text message
Intermediate layer smsdispatcher processing process:
1) this class has done an important thing:
The handler setting method for commandinterface is to trigger msmsregistrant. yyregistrant (New asyncresult (null, SMS, null) after receiving the SMS.
Then, call the previously passed handler and process the text message in the handler.
2) handler processes the received text message:
@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; } }
Note:
Int result = dispatchmessage (SMS. mwrappedsmessage );
This section is processed by the dispatchmessage method of the subclass (gsmsmsdispatcher.
After a series of judgment and processing, the common text message will be handed over to 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) We can see that this method broadcasts messages in sequence (the action is sms_received_action). mresultreceiver is called no matter whether the broadcast is interrupted or not, the read or unread status is reported to the other party. If the SMS broadcast is not blocked. Then, after receiving the broadcast, the privilegedsmsreceiver broadcast receiver in the SMS app calls the onreceivewithprivilege method. Because privilegedsmsreceiver inherits from smsreceiver, this method of the parent class is called. Its code:
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); }
Finally, it is handled by the smsreceiverservice, which has reached the application layer MMs.
Some children may see the receipt of the mms. I understand what the MMS reception may make. In order to solve the problem, I would like to briefly describe the process of receiving the MMS, many of them are similar to text messages. In this process, we will draw a sequence chart. Note: This is until the application layer, the specific implementation of the application layer will be described in a special article. Here, we take GSM as an example. The following is the time sequence diagram: Note: The difference between dispatchmessage and SMS is that the dispatchmessage method is based on smsheader. portaddrs is used to determine whether the current message is a MMS Message or a text message, and then the corresponding method is called. Summary
I will not analyze how rild establishes socket communication with RIL. Java, nor how rild communicates with moderm. I will continue to study these issues and hope to share them with you as soon as possible.