长短信会分割成多条发送过来,每一条头部会带上总共有多少条,和这是第几条。(具体的细节我也没太深究)
手机收到其中一条短信时,如果辨别出是长短信,则先把短信存储在raw表内(sqlite路径:/data/data/com.android.providers.telephony/databases/mmssms.db)
当收完全部短信时,就把raw表的相关内容删除,传播到其他程序处理
贴代码充数。。。。o(╯□╰)o
主要代码在SMSDispatcher.java里
/**
* If this is the last part send the parts out to the application, otherwise
* the part is stored for later processing. Handles both 3GPP concatenated messages
* as well as 3GPP2 format WAP push messages processed by
* {@link com.android.internal.telephony.cdma.CdmaSMSDispatcher#processCdmaWapPdu}.
*
* @param pdu the message PDU, or the datagram portion of a CDMA WDP datagram segment
* @param address the originating address
* @param referenceNumber distinguishes concatenated messages from the same sender
* @param sequenceNumber the order of this segment in the message
* (starting at 0 for CDMA WDP datagrams and 1 for concatenated messages).
* @param messageCount the number of segments in the message
* @param timestamp the service center timestamp in millis
* @param destPort the destination port for the message, or -1 for no destination port
* @param isCdmaWapPush true if pdu is a CDMA WDP datagram segment and not an SM PDU
*
* @return a result code from {@link Telephony.Sms.Intents}, or
* {@link Activity#RESULT_OK} if the message has been broadcast
* to applications
*/
protected int processMessagePart(byte[] pdu, String address, int referenceNumber,
int sequenceNumber, int messageCount, long timestamp, int destPort,
boolean isCdmaWapPush) {
byte[][] pdus = null;
Cursor cursor = null;
try {
// used by several query selection arguments
String refNumber = Integer.toString(referenceNumber);
String seqNumber = Integer.toString(sequenceNumber);
// Check for duplicate message segment 检查有没有重复的片段,有就忽略了
cursor = mResolver.query(mRawUri, PDU_PROJECTION,
"address=? AND reference_number=? AND sequence=?",
new String[] {address, refNumber, seqNumber}, null);
// moveToNext() returns false if no duplicates were found
if (cursor.moveToNext()) {
Log.w(TAG, "Discarding duplicate message segment from address=" + address
+ " refNumber=" + refNumber + " seqNumber=" + seqNumber);
String oldPduString = cursor.getString(PDU_COLUMN);
byte[] oldPdu = HexDump.hexStringToByteArray(oldPduString);
if (!Arrays.equals(oldPdu, pdu)) {
Log.e(TAG, "Warning: dup message segment PDU of length " + pdu.length
+ " is different from existing PDU of length " + oldPdu.length);
}
return Intents.RESULT_SMS_HANDLED;
}
cursor.close();
// not a dup, query for all other segments of this concatenated message
String where = "address=? AND reference_number=?";
String[] whereArgs = new String[] {address, refNumber};
cursor = mResolver.query(mRawUri, PDU_SEQUENCE_PORT_PROJECTION, where, whereArgs, null);
int cursorCount = cursor.getCount();
if (cursorCount != messageCount - 1) { //如果不是最后一条,就插入raw表
// We don't have all the parts yet, store this one away
ContentValues values = new ContentValues();
values.put("date", timestamp);
values.put("pdu", HexDump.toHexString(pdu));
values.put("address", address);
values.put("reference_number", referenceNumber);
values.put("count", messageCount);
values.put("sequence", sequenceNumber);
if (destPort != -1) {
values.put("destination_port", destPort);
}
mResolver.insert(mRawUri, values);
return Intents.RESULT_SMS_HANDLED;
}
// All the parts are in place, deal with them
pdus = new byte[messageCount][];
for (int i = 0; i < cursorCount; i++) {
cursor.moveToNext();
int cursorSequence = cursor.getInt(SEQUENCE_COLUMN);
// GSM sequence numbers start at 1; CDMA WDP datagram sequence numbers start at 0
if (!isCdmaWapPush) {
cursorSequence--;
}
pdus[cursorSequence] = HexDump.hexStringToByteArray(
cursor.getString(PDU_COLUMN));
// Read the destination port from the first segment (needed for CDMA WAP PDU).
// It's not a bad idea to prefer the port from the first segment for 3GPP as well.
if (cursorSequence == 0 && !cursor.isNull(DESTINATION_PORT_COLUMN)) {
destPort = cursor.getInt(DESTINATION_PORT_COLUMN);
}
}
// This one isn't in the DB, so add it
// GSM sequence numbers start at 1; CDMA WDP datagram sequence numbers start at 0
if (isCdmaWapPush) {
pdus[sequenceNumber] = pdu;
} else {
pdus[sequenceNumber - 1] = pdu;
}
// Remove the parts from the database
mResolver.delete(mRawUri, where, whereArgs);
} catch (SQLException e) {
Log.e(TAG, "Can't access multipart SMS database", e);
return Intents.RESULT_SMS_GENERIC_ERROR;
} finally {
if (cursor != null) cursor.close();
}
// Special handling for CDMA WDP datagrams
if (isCdmaWapPush) {
// Build up the data stream
ByteArrayOutputStream output = new ByteArrayOutputStream();
for (int i = 0; i < messageCount; i++) {
// reassemble the (WSP-)pdu
output.write(pdus[i], 0, pdus[i].length);
}
byte[] datagram = output.toByteArray();
// Dispatch the PDU to applications
if (destPort == SmsHeader.PORT_WAP_PUSH) {
// Handle the PUSH
return mWapPush.dispatchWapPdu(datagram);
} else {
pdus = new byte[1][];
pdus[0] = datagram;
// The messages were sent to any other WAP port
dispatchPortAddressedPdus(pdus, destPort);
return Activity.RESULT_OK;
}
}
// Dispatch the PDUs to applications
if (destPort != -1) {
if (destPort == SmsHeader.PORT_WAP_PUSH) {
// Build up the data stream
ByteArrayOutputStream output = new ByteArrayOutputStream();
for (int i = 0; i < messageCount; i++) {
SmsMessage msg = SmsMessage.createFromPdu(pdus[i], getFormat());
byte[] data = msg.getUserData();
output.write(data, 0, data.length);
}
// Handle the PUSH
return mWapPush.dispatchWapPdu(output.toByteArray());
} else {
// The messages were sent to a port, so concoct a URI for it
dispatchPortAddressedPdus(pdus, destPort);
}
} else {
// The messages were not sent to a port
dispatchPdus(pdus);
}
return Activity.RESULT_OK;
}
/**
* Dispatches standard PDUs to interested applications
*
* @param pdus The raw PDUs making up the message
*/
protected void dispatchPdus(byte[][] pdus) {
Intent intent = new Intent(Intents.SMS_RECEIVED_ACTION);
intent.putExtra("pdus", pdus);
intent.putExtra("format", getFormat());
dispatch(intent, RECEIVE_SMS_PERMISSION);
}
参考
Android MMS模块数据存取
android sms接收流程(ril分析)
Raw access to SMS/MMS database on Android phones