短信的接收, 请先看一个 Demo
private void initReceiverSms() {
tv_content = (TextView) findViewById(R.id.tv_content);
receiveFilter = new IntentFilter();
receiveFilter.addAction("android.provider.Telephony.SMS_RECEIVED");
messageReceiver = new MessageReceiver();
registerReceiver(messageReceiver, receiveFilter);
}
private class MessageReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")) {
Bundle bundle = intent.getExtras();
//使用pdu秘钥来提取一个pdus数组
Object[] pdus = (Object[]) bundle.get("pdus");
SmsMessage[] messages = new SmsMessage[pdus.length];
for (int i = 0; i < messages.length; i++) {
messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
}
//获取发送方号码
String address = messages[0].getOriginatingAddress();
//获取短信内容
String fullMessage = "";
for (SmsMessage message : messages) {
fullMessage += message.getMessageBody();
}
tv_content.setText(fullMessage);
}
}
}
短信接收, 需要注册 BroadcastReceiver 来接收接收到的短信信息, 该信息在 Intent 中被传递解析出来, 并进行获取.
因为 数据时经由 modem 层向上数据传输. 应该需要经由 RIL.java.
# RIL
class RILReceiver implements Runnable {
byte[] buffer;
RILReceiver() {
buffer = new byte[RIL_MAX_COMMAND_BYTES];
}
@Override
public void
run() {
int retryCount = 0;
String rilSocket = "rild";
try {for (;;) {
LocalSocket s = null;
LocalSocketAddress l;
...
riljLog("rilSocket[" + mInstanceId + "] = " + rilSocket);
try {
s = new LocalSocket();
l = new LocalSocketAddress(rilSocket,
LocalSocketAddress.Namespace.RESERVED);
s.connect(l);
}
...
retryCount = 0;
mSocket = s;
Rlog.i(RILJ_LOG_TAG, "(" + mInstanceId + ") 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);
//Rlog.v(RILJ_LOG_TAG, "Read packet: " + length + " bytes");
processResponse(p);
p.recycle();
}
}
...
setRadioState (RadioState.RADIO_UNAVAILABLE);
try {
mSocket.close();
} catch (IOException ex) {
}
mSocket = null;
RILRequest.resetSerial();
// Clear request list on close
clearRequestList(RADIO_NOT_AVAILABLE, false);
}
...
/* We're disconnected so we don't know the ril version */
notifyRegistrantsRilConnectionChanged(-1);
}
}
因为 SMS 通过发送者将信息送至 modem 层, 手机上层主要是读取 modem 层的数据, 这里它们使用了 socket 来跨进程读取 modem 处的数据, 使用 Parcel 获取数据, 然后再 processResponse(p) 处理.
# RIL
processResponse (Parcel p) {
int type;
type = p.readInt();
if (type == RESPONSE_UNSOLICITED || type == RESPONSE_UNSOLICITED_ACK_EXP) {
processUnsolicited (p, type); //here
} else if (type == RESPONSE_SOLICITED || type == RESPONSE_SOLICITED_ACK_EXP) {
RILRequest rr = processSolicited (p, type);
if (rr != null) {
if (type == RESPONSE_SOLICITED) {
decrementWakeLock(rr);
}
rr.release();
return;
}
} else if (type == RESPONSE_SOLICITED_ACK) {
int serial;
serial = p.readInt();
RILRequest rr;
synchronized (mRequestList) {
rr = mRequestList.get(serial);
}
if (rr == null) {
Rlog.w(RILJ_LOG_TAG, "Unexpected solicited ack response! sn: " + serial);
} else {
decrementWakeLock(rr);
if (RILJ_LOGD) {
riljLog(rr.serialString() + " Ack < " + requestToString(rr.mRequest));
}
}
}
}
从这里看, 这里会对类型进行判断而区分进行下一步操作. 对于短信, 其是一种广播形式. 这里先分析 processUnsolicited (p, type);
# RIL
private void
processUnsolicited (Parcel p, int type) {
int response;
Object ret;
response = p.readInt();
case RIL_UNSOL_RESPONSE_NEW_SMS: ret = responseString(p); break;
switch(response) {
case RIL_UNSOL_RESPONSE_NEW_SMS: {
if (RILJ_LOGD) unsljLog(response);
mEventLog.writeRilNewSms(response);
// FIXME this should move up a layer
String a[] = new String[2];
a[1] = (String)ret;
SmsMessage sms;
sms = SmsMessage.newFromCMT(a);
if (mGsmSmsRegistrant != null) {
mGsmSmsRegistrant
.notifyRegistrant(new AsyncResult(null, sms, null));
}
break;
}
}
}
可以看出,
```
case RIL_UNSOL_RESPONSE_NEW_SMS: ret = responseString(p); break;
```
获取了短信接收的消息., 最后被封装到了 SmsMessage 中. 然后再上传到 Registrant.
# Registrant
/*package*/ void
internalNotifyRegistrant (Object result, Throwable exception)
{
Handler h = getHandler();
if (h == null) {
clear();
/// M: Registrant Debug Log Enhancement
Log.d("Registrant", "internalNotifyRegistrant(): Warning! Handler is null, it could be already GCed. ( what=" + what + ", userObj=" + userObj + ", result=" + result + ", exception=" + exception + " )");
} else {
Message msg = Message.obtain();
msg.what = what;
msg.obj = new AsyncResult(userObj, result, exception);
h.sendMessage(msg);
}
}
这里就很明确了, 消息需要 Handler 进行处理, 同时 msg.what = "EVENT_NEW_SMS", 所以实际的处理在 GsmInboundSmsHandler, 其继承于 InboundSmsHandler, 基类为 StateMachine. 其中 Handler h = getHandler()的 Handler 是 StateMachine 的成员变量. 事件分发 handlemessage().
# StateMachine
public final void handleMessage(Message msg) {
...
/** Save the current message */
mMsg = msg;
/** State that processed the message */
State msgProcessedState = null;
if (mIsConstructionCompleted) {
/** Normal path */
msgProcessedState = processMsg(msg); //here
}
...
}
}
}
rivate final State processMsg(Message msg) {
StateInfo curStateInfo = mStateStack[mStateStackTopIndex];
if (mDbg) {
mSm.log("processMsg: " + curStateInfo.state.getName());
}
if (isQuit(msg)) {
transitionTo(mQuittingState);
} else {
//com.android.internal.util.State implements IState
while (!curStateInfo.state.processMessage(msg)) {
curStateInfo = curStateInfo.parentStateInfo;
if (curStateInfo == null) {
/**
* No parents left so it's not handled
*/
mSm.unhandledMessage(msg);
break;
}
if (mDbg) {
mSm.log("processMsg: " + curStateInfo.state.getName());
}
}
}
return (curStateInfo != null) ? curStateInfo.state : null;
}
State 拥有多个子类: DefaultState, StartupState, IdleState, DeliveringState, WaitingState, 这里就看 DeliveringState 的实现
# InboundSmsHandler
private class DeliveringState extends State {
@Override
public void enter() {
if (DBG) log("entering Delivering state");
}
@Override
public void exit() {
if (DBG) log("leaving Delivering state");
}
@Override
public boolean processMessage(Message msg) {
log("DeliveringState.processMessage:" + msg.what);
switch (msg.what) {
case EVENT_NEW_SMS: //here
// handle new SMS from RIL
handleNewSms((AsyncResult) msg.obj);
sendMessage(EVENT_RETURN_TO_IDLE);
return HANDLED;
case EVENT_INJECT_SMS:
// handle new injected SMS
handleInjectSms((AsyncResult) msg.obj);
sendMessage(EVENT_RETURN_TO_IDLE);
return HANDLED;
case EVENT_BROADCAST_SMS:
// if any broadcasts were sent, transition to waiting state
InboundSmsTracker inboundSmsTracker = (InboundSmsTracker) msg.obj;
if (processMessagePart(inboundSmsTracker)) {
transitionTo(mWaitingState);
} else {
// if event is sent from SmsBroadcastUndelivered.broadcastSms(), and
// processMessagePart() returns false, the state machine will be stuck in
// DeliveringState until next message is received. Send message to
// transition to idle to avoid that so that wakelock can be released
log("No broadcast sent on processing EVENT_BROADCAST_SMS in Delivering " +
"state. Return to Idle state");
sendMessage(EVENT_RETURN_TO_IDLE);
}
return HANDLED;
case EVENT_RETURN_TO_IDLE:
// return to idle after processing all other messages
transitionTo(mIdleState);
return HANDLED;
case EVENT_RELEASE_WAKELOCK:
mWakeLock.release(); // decrement wakelock from previous entry to Idle
if (!mWakeLock.isHeld()) {
// wakelock should still be held until 3 seconds after we enter Idle
loge("mWakeLock released while delivering/broadcasting!");
}
return HANDLED;
// we shouldn't get this message type in this state, log error and halt.
case EVENT_BROADCAST_COMPLETE:
case EVENT_START_ACCEPTING_SMS:
default:
// let DefaultState handle these unexpected message types
return NOT_HANDLED;
}
}
}
首先使用 handleNewSms, 然后再通知 Sms 系统空闲.主要看 handleNewSms().
# InboundSmsHandler
private void handleNewSms(AsyncResult ar) {
int result;
try {
SmsMessage sms = (SmsMessage) ar.result;
result = dispatchMessage(sms.mWrappedSmsMessage);
} catch (RuntimeException ex) {
loge("Exception dispatching message", ex);
result = Intents.RESULT_SMS_GENERIC_ERROR;
}
// RESULT_OK means that the SMS will be acknowledged by special handling,
// e.g. for SMS-PP data download. Any other result, we should ack here.
if (result != Activity.RESULT_OK) {
boolean handled = (result == Intents.RESULT_SMS_HANDLED);
notifyAndAcknowledgeLastIncomingSms(handled, result, null);
}
}
其首先将 SmsMessage 数据从 AsyncResult 解析出来, 接着再 dispatchMessage 分派处理.
# InboundSmsHandler
private int dispatchMessage(SmsMessageBase smsb) {
// If sms is null, there was a parsing error.
if (smsb == null) {
loge("dispatchSmsMessage: message is null");
return Intents.RESULT_SMS_GENERIC_ERROR;
}
if (mSmsReceiveDisabled) {
// Device doesn't support receiving SMS,
log("Received short message on device which doesn't support "
+ "receiving SMS. Ignored.");
return Intents.RESULT_SMS_HANDLED;
}
// onlyCore indicates if the device is in cryptkeeper
boolean onlyCore = false;
try {
onlyCore = IPackageManager.Stub.asInterface(ServiceManager.getService("package")).
isOnlyCoreApps();
} catch (RemoteException e) {
}
if (onlyCore) {
// Device is unable to receive SMS in encrypted state
log("Received a short message in encrypted state. Rejecting.");
return Intents.RESULT_SMS_GENERIC_ERROR;
}
return dispatchMessageRadioSpecific(smsb);
}
接着针对 GSM 和 CDMA 分别在 InboundSmsHandler 的子类中进行 dispatchMessageRadioSpecific(smsb), 这里 smsb 是 sms 接收的信息.
# GsmInboundSmsHandler
protected int dispatchMessageRadioSpecific(SmsMessageBase smsb) {
SmsMessage sms = (SmsMessage) smsb;
if (sms.isTypeZero()) {
// As per 3GPP TS 23.040 9.2.3.9, Type Zero messages should not be
// Displayed/Stored/Notified. They should only be acknowledged.
log("Received short message type 0, Don't display or store it. Send Ack");
return Intents.RESULT_SMS_HANDLED;
}
// Send SMS-PP data download messages to UICC. See 3GPP TS 31.111 section 7.1.1.
if (sms.isUsimDataDownload()) {
UsimServiceTable ust = mPhone.getUsimServiceTable();
return mDataDownloadHandler.handleUsimDataDownload(ust, sms);
}
boolean handled = false;
if (sms.isMWISetMessage()) {
updateMessageWaitingIndicator(sms.getNumOfVoicemails());
handled = sms.isMwiDontStore();
if (DBG) log("Received voice mail indicator set SMS shouldStore=" + !handled);
} else if (sms.isMWIClearMessage()) {
updateMessageWaitingIndicator(0);
handled = sms.isMwiDontStore();
if (DBG) log("Received voice mail indicator clear SMS shouldStore=" + !handled);
}
if (handled) {
return Intents.RESULT_SMS_HANDLED;
}
if (!mStorageMonitor.isStorageAvailable() &&
sms.getMessageClass() != SmsConstants.MessageClass.CLASS_0) {
// It's a storable message and there's no storage available. Bail.
// (See TS 23.038 for a description of class 0 messages.)
return Intents.RESULT_SMS_OUT_OF_MEMORY;
}
return dispatchNormalMessage(smsb);
}
进过一系列的判断处理后, 在 dispatchNormalMessage 中进行处理
# InboundSmsHandler
protected int dispatchNormalMessage(SmsMessageBase sms) {
SmsHeader smsHeader = sms.getUserDataHeader();
InboundSmsTracker tracker;
if ((smsHeader == null) || (smsHeader.concatRef == null)) {
// Message is not concatenated.
int destPort = -1;
if (smsHeader != null && smsHeader.portAddrs != null) {
// The message was sent to a port.
destPort = smsHeader.portAddrs.destPort;
if (DBG) log("destination port: " + destPort);
}
// MTK-START
tracker = TelephonyComponentFactory.getInstance().makeInboundSmsTracker(
mPhone.getSubId(), sms.getPdu(), sms.getTimestampMillis(), destPort, is3gpp2(),
false, sms.getDisplayOriginatingAddress(), sms.getMessageBody());
// MTK-END
} else {
// Create a tracker for this message segment.
SmsHeader.ConcatRef concatRef = smsHeader.concatRef;
SmsHeader.PortAddrs portAddrs = smsHeader.portAddrs;
int destPort = (portAddrs != null ? portAddrs.destPort : -1);
// MTK-START
tracker = TelephonyComponentFactory.getInstance().makeInboundSmsTracker(
mPhone.getSubId(), sms.getPdu(), sms.getTimestampMillis(), destPort, is3gpp2(),
sms.getDisplayOriginatingAddress(), concatRef.refNumber, concatRef.seqNumber,
concatRef.msgCount, false, sms.getMessageBody());
// MTK-END
}
if (VDBG) log("created tracker: " + tracker);
// de-duping is done only for text messages
// destPort = -1 indicates text messages, otherwise it's a data sms
return addTrackerToRawTableAndSendMessage(tracker,
tracker.getDestPort() == -1 /* de-dup if text message */);
}
这里将 SMSMessage 数据封装到了 InboundSmsTracker 中. 然后调用 addTrackerToRawTableAndSendMessage().
# InboundSmsHandler
protected int addTrackerToRawTableAndSendMessage(InboundSmsTracker tracker, boolean deDup) {
switch(addTrackerToRawTable(tracker, deDup)) {
case Intents.RESULT_SMS_HANDLED:
sendMessage(EVENT_BROADCAST_SMS, tracker);
return Intents.RESULT_SMS_HANDLED;
case Intents.RESULT_SMS_DUPLICATED:
return Intents.RESULT_SMS_HANDLED;
case Intents.RESULT_SMS_GENERIC_ERROR:
default:
return Intents.RESULT_SMS_GENERIC_ERROR;
}
}
这里接受短信息, 执行了
```
case Intents.RESULT_SMS_HANDLED:
sendMessage(EVENT_BROADCAST_SMS, tracker);
return Intents.RESULT_SMS_HANDLED;
```
针对接收短信, 其再一次进入了 DeliveringState 中, 并进行其分派行为:
# InboundSmsHandler
case EVENT_BROADCAST_SMS:
// if any broadcasts were sent, transition to waiting state
InboundSmsTracker inboundSmsTracker = (InboundSmsTracker) msg.obj;
if (processMessagePart(inboundSmsTracker)) {
transitionTo(mWaitingState);
} else {
// if event is sent from SmsBroadcastUndelivered.broadcastSms(), and
// processMessagePart() returns false, the state machine will be stuck in
// DeliveringState until next message is received. Send message to
// transition to idle to avoid that so that wakelock can be released
log("No broadcast sent on processing EVENT_BROADCAST_SMS in Delivering " +
state. Return to Idle state");
endMessage(EVENT_RETURN_TO_IDLE);
}
return HANDLED;
这里执行 processMessagePart(), 具体实现
# InboundSmsHandler
private boolean processMessagePart(InboundSmsTracker tracker) {
int messageCount = tracker.getMessageCount();
byte[][] pdus;
int destPort = tracker.getDestPort();
if (messageCount == 1) {
// single-part message
pdus = new byte[][]{tracker.getPdu()};
} else {
// MTK-START
// To lock the raw table of sms database
synchronized (mRawLock) {
// MTK-END
// multi-part message
Cursor cursor = null;
try {
// used by several query selection arguments
String address = tracker.getAddress();
String refNumber = Integer.toString(tracker.getReferenceNumber());
String count = Integer.toString(tracker.getMessageCount());
// MTK-START
String subId = Integer.toString(mPhone.getSubId());
// MTK-END
// query for all segments and broadcast message if we have all the parts
// MTK-START
String[] whereArgs = {address, refNumber, count, subId};
// MTK-END
cursor = mResolver.query(sRawUri, PDU_SEQUENCE_PORT_PROJECTION,
SELECT_BY_REFERENCE, whereArgs, null);
int cursorCount = cursor.getCount();
if (cursorCount < messageCount) {
// Wait for the other message parts to arrive. It's also possible for
// the last segment to arrive before processing the EVENT_BROADCAST_SMS for
// one of the earlier segments. In that case, the broadcast will be sent as
// soon as all segments are in the table, and any later EVENT_BROADCAST_SMS
// messages will get a row count of 0 and return.
// MTK-START
// Refresh the timer if receive another new concatenated segments but not
// finish
if (!SystemProperties.get("ro.mtk_bsp_package").equals("1")) {
if (tracker.getIndexOffset() == 1 && tracker.getDestPort() == -1) {
log("ConcatenatedSmsFwkExt: refresh timer, ref = " +
tracker.getReferenceNumber());
TimerRecord record =
(TimerRecord)mConcatenatedSmsFwkExt.queryTimerRecord(
tracker.getAddress(), tracker.getReferenceNumber(),
tracker.getMessageCount());
if (record == null) {
log("ConcatenatedSmsFwkExt: fail to " +
"get TimerRecord to refresh timer");
} else {
mConcatenatedSmsFwkExt.refreshTimer(getHandler(), record);
}
}
}
// MTK-END
return false;
}
// MTK-START
if (!SystemProperties.get("ro.mtk_bsp_package").equals("1")) {
if (tracker.getIndexOffset() == 1 && tracker.getDestPort() == -1) {
// cancel the timer, because all segments are in place
log("ConcatenatedSmsFwkExt: cancel timer, ref = " +
tracker.getReferenceNumber());
TimerRecord record =
(TimerRecord)mConcatenatedSmsFwkExt.queryTimerRecord(
tracker.getAddress(), tracker.getReferenceNumber(),
tracker.getMessageCount());
if (record == null) {
log("ConcatenatedSmsFwkExt: fail to " +
"get TimerRecord to cancel timer");
} else {
mConcatenatedSmsFwkExt.cancelTimer(getHandler(), record);
}
}
}
// MTK-END
// All the parts are in place, deal with them
pdus = new byte[messageCount][];
while (cursor.moveToNext()) {
// subtract offset to convert sequence to 0-based array index
int index = cursor.getInt(SEQUENCE_COLUMN) - tracker.getIndexOffset();
pdus[index] = 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 in other
// cases.
if (index == 0 && !cursor.isNull(DESTINATION_PORT_COLUMN)) {
int port = cursor.getInt(DESTINATION_PORT_COLUMN);
// strip format flags and convert to real port number, or -1
port = InboundSmsTracker.getRealDestPort(port);
if (port != -1) {
destPort = port;
}
}
}
} catch (SQLException e) {
loge("Can't access multipart SMS database", e);
return false;
} finally {
if (cursor != null) {
cursor.close();
}
}
}
// MTK-START
}
// MTK-END
// Do not process null pdu(s). Check for that and return false in that case.
List<byte[]> pduList = Arrays.asList(pdus);
if (pduList.size() == 0 || pduList.contains(null)) {
loge("processMessagePart: returning false due to " +
(pduList.size() == 0 ? "pduList.size() == 0" : "pduList.contains(null)"));
return false;
}
if (!mUserManager.isUserUnlocked()) {
return processMessagePartWithUserLocked(tracker, pdus, destPort);
}
SmsBroadcastReceiver resultReceiver = new SmsBroadcastReceiver(tracker);
if (destPort == SmsHeader.PORT_WAP_PUSH) {
// Build up the data stream
ByteArrayOutputStream output = new ByteArrayOutputStream();
for (byte[] pdu : pdus) {
// 3GPP needs to extract the User Data from the PDU; 3GPP2 has already done this
if (!tracker.is3gpp2()) {
SmsMessage msg = SmsMessage.createFromPdu(pdu, SmsConstants.FORMAT_3GPP);
if (msg != null) {
pdu = msg.getUserData();
} else {
loge("processMessagePart: SmsMessage.createFromPdu returned null");
return false;
}
}
output.write(pdu, 0, pdu.length);
}
// MTK-START
int result;
// Put the extra information on bundle
if (SmsConstants.isWapPushSupport()) {
log("dispatch wap push pdu with addr & sc addr");
Bundle bundle = new Bundle();
if (!tracker.is3gpp2WapPdu()) {
SmsMessage sms = SmsMessage.createFromPdu(pdus[0], tracker.getFormat());
if (sms != null) {
bundle.putString(Telephony.WapPush.ADDR, sms.getOriginatingAddress());
String sca = sms.getServiceCenterAddress();
if (sca == null) {
/* null for app is not a item, it needs to transfer to empty string */
sca = "";
}
bundle.putString(Telephony.WapPush.SERVICE_ADDR, sca);
}
} else {
//for CDMA, all info has been parsed into tracker before
bundle.putString(Telephony.WapPush.ADDR, tracker.getAddress());
bundle.putString(Telephony.WapPush.SERVICE_ADDR, "");
}
result = mWapPush.dispatchWapPdu(output.toByteArray(), resultReceiver, this,
bundle);
} else {
//int result = mWapPush.dispatchWapPdu(output.toByteArray(), resultReceiver, this);
log("dispatch wap push pdu");
result = mWapPush.dispatchWapPdu(output.toByteArray(), resultReceiver, this);
}
// MTK-END
if (DBG) log("dispatchWapPdu() returned " + result);
// result is Activity.RESULT_OK if an ordered broadcast was sent
if (result == Activity.RESULT_OK) {
return true;
} else {
deleteFromRawTable(tracker.getDeleteWhere(), tracker.getDeleteWhereArgs(),
MARK_DELETED);
return false;
}
}
if (BlockChecker.isBlocked(mContext, tracker.getAddress())) {
deleteFromRawTable(tracker.getDeleteWhere(), tracker.getDeleteWhereArgs(),
DELETE_PERMANENTLY);
return false;
}
boolean carrierAppInvoked = filterSmsWithCarrierOrSystemApp(
pdus, destPort, tracker, resultReceiver, true /* userUnlocked */);
if (!carrierAppInvoked) {
// MTK-START
dispatchSmsDeliveryIntent(pdus, tracker.getFormat(), destPort, resultReceiver,
IConcatenatedSmsFwkExt.UPLOAD_FLAG_NONE);
// MTK-END
}
return true;
}
首先针对短信的长度, 切割成多段来处理之.
SmsBroadcastReceiver resultReceiver = new SmsBroadcastReceiver(tracker); //广播接收者.
//数据分发,
dispatchSmsDeliveryIntent(pdus, tracker.getFormat(), destPort, resultReceiver,
IConcatenatedSmsFwkExt.UPLOAD_FLAG_NONE);
黑名单处理
if (BlockChecker.isBlocked(mContext, tracker.getAddress())) {
deleteFromRawTable(tracker.getDeleteWhere(), tracker.getDeleteWhereArgs(),
DELETE_PERMANENTLY);
return false;
}
所以实际上, 系统将数据由广播接收者再进行处理
# InboundSmsHandler
private void dispatchSmsDeliveryIntent(byte[][] pdus, String format, int destPort,
BroadcastReceiver resultReceiver, int longSmsUploadFlag) {
// MTK-END
Intent intent = new Intent();
intent.putExtra("pdus", pdus);
intent.putExtra("format", format);
if (destPort == -1) {
intent.setAction(Intents.SMS_DELIVER_ACTION);
// Direct the intent to only the default SMS app. If we can't find a default SMS app
// then sent it to all broadcast receivers.
// We are deliberately delivering to the primary user's default SMS App.
ComponentName componentName = SmsApplication.getDefaultSmsApplication(mContext, true);
if (componentName != null) {
// Deliver SMS message only to this receiver.
intent.setComponent(componentName);
log("Delivering SMS to: " + componentName.getPackageName() +
" " + componentName.getClassName());
} else {
intent.setComponent(null);
}
// TODO: Validate that this is the right place to store the SMS.
if (SmsManager.getDefault().getAutoPersisting()) {
final Uri uri = writeInboxMessage(intent);
if (uri != null) {
// Pass this to SMS apps so that they know where it is stored
intent.putExtra("uri", uri.toString());
}
}
// MTK-START
// To check if needs to add upload flag to app
if (!SystemProperties.get("ro.mtk_bsp_package").equals("1")) {
int uploadFlag = longSmsUploadFlag;
// If someone already decide to use the spcified flag, it should not change it
if (uploadFlag == IConcatenatedSmsFwkExt.UPLOAD_FLAG_NONE) {
// To check if needs to add upload flag to app
uploadFlag = IConcatenatedSmsFwkExt.UPLOAD_FLAG_NEW;
SmsMessage msg = SmsMessage.createFromPdu(pdus[0], format);
if (msg != null) {
SmsHeader udh = msg.getUserDataHeader();
if (udh != null && udh.concatRef != null) {
TimerRecord tr = new TimerRecord(msg.getOriginatingAddress(),
udh.concatRef.refNumber, udh.concatRef.msgCount, null);
// MTK-START
// To lock the raw table of sms database
synchronized (mRawLock) {
uploadFlag = mConcatenatedSmsFwkExt.getUploadFlag(tr);
}
// MTK-END
}
}
log("uploadFlag=" + uploadFlag);
}
if (uploadFlag == IConcatenatedSmsFwkExt.UPLOAD_FLAG_UPDATE ||
uploadFlag == IConcatenatedSmsFwkExt.UPLOAD_FLAG_NEW) {
log("dispatch all pdus with new/upload flag");
intent.putExtra(IConcatenatedSmsFwkExt.UPLOAD_FLAG_TAG, uploadFlag);
}
}
// If Phone Privacy Lock feature turns on,
// change and send mPhonePrivacyLockReceiver to check permission first
// mPhonePrivacyLockReceiver -> default sms application -> others
if (SmsConstants.isPrivacyLockSupport()) {
// Change action as "android.intent.action.MOMS_SMS_RECEIVED" to let
// Moms check first
intent.setAction(Intents.PRIVACY_LOCK_SMS_RECEIVED_ACTION);
intent.setComponent(null);
}
// MTK-END
} else {
intent.setAction(Intents.DATA_SMS_RECEIVED_ACTION);
Uri uri = Uri.parse("sms://localhost:" + destPort);
intent.setData(uri);
intent.setComponent(null);
}
Bundle options = handleSmsWhitelisting(intent.getComponent());
dispatchIntent(intent, android.Manifest.permission.RECEIVE_SMS,
AppOpsManager.OP_RECEIVE_SMS, options, resultReceiver, UserHandle.SYSTEM);
}
从上面 intent将 pdus 数据进行封装
```
Intent intent = new Intent();
intent.putExtra("pdus", pdus);// 这就是为什么我们要从pdus中获取数据.
intent.putExtra("format", format);
```
短信不需要使用端口号:
if (destPort == -1) {
intent.setAction(Intents.SMS_DELIVER_ACTION);
// Direct the intent to only the default SMS app. If we can't find a default SMS app
// then sent it to all broadcast receivers.
// We are deliberately delivering to the primary user's default SMS App.
//获取默认短信应用
ComponentName componentName = SmsApplication.getDefaultSmsApplication(mContext, true);
if (componentName != null) {
// Deliver SMS message only to this receiver.
intent.setComponent(componentName); //指定默认短信应用包名
log("Delivering SMS to: " + componentName.getPackageName() +
" " + componentName.getClassName());
} else {
intent.setComponent(null);
}
// TODO: Validate that this is the right place to store the SMS.
//持久化处理
if (SmsManager.getDefault().getAutoPersisting()) {
final Uri uri = writeInboxMessage(intent);
if (uri != null) {
// Pass this to SMS apps so that they know where it is stored
intent.putExtra("uri", uri.toString());
}
}
}
}
最后在进行行为上的分派.
# InboundSmsHandler
public void dispatchIntent(Intent intent, String permission, int appOp,
Bundle opts, BroadcastReceiver resultReceiver, UserHandle user) {
intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT);//添加标志位, 非终止
// MTK-START
intent.putExtra("rTime", System.currentTimeMillis()); //时间戳
// MTK-END
final String action = intent.getAction();
if (Intents.SMS_DELIVER_ACTION.equals(action)
|| Intents.SMS_RECEIVED_ACTION.equals(action)
|| Intents.WAP_PUSH_DELIVER_ACTION.equals(action)
|| Intents.WAP_PUSH_RECEIVED_ACTION.equals(action)) {
// Some intents need to be delivered with high priority:
// SMS_DELIVER, SMS_RECEIVED, WAP_PUSH_DELIVER, WAP_PUSH_RECEIVED
// In some situations, like after boot up or system under load, normal
// intent delivery could take a long time.
// This flag should only be set for intents for visible, timely operations
// which is true for the intents above.
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); //提高优先级.
}
SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId());
if (user.equals(UserHandle.ALL)) {//接收到的是 UserHandle.ALL
// Get a list of currently started users.
int[] users = null;
try {
users = ActivityManagerNative.getDefault().getRunningUserIds();
} catch (RemoteException re) {
}
if (users == null) {
users = new int[] {user.getIdentifier()};
}
// Deliver the broadcast only to those running users that are permitted
// by user policy.
for (int i = users.length - 1; i >= 0; i--) {
UserHandle targetUser = new UserHandle(users[i]);
if (users[i] != UserHandle.USER_SYSTEM) {
// Is the user not allowed to use SMS?
if (mUserManager.hasUserRestriction(UserManager.DISALLOW_SMS, targetUser)) {
continue;
}
// Skip unknown users and managed profiles as well
UserInfo info = mUserManager.getUserInfo(users[i]);
if (info == null || info.isManagedProfile()) {
continue;
}
}
// Only pass in the resultReceiver when the USER_SYSTEM is processed.
mContext.sendOrderedBroadcastAsUser(intent, targetUser, permission, appOp, opts,
users[i] == UserHandle.USER_SYSTEM ? resultReceiver : null,
getHandler(), Activity.RESULT_OK, null, null);
}
} else {
mContext.sendOrderedBroadcastAsUser(intent, user, permission, appOp, opts,
resultReceiver, getHandler(), Activity.RESULT_OK, null, null);
}
}
这里主要针对多用户进行处理, 实际这里是执行体,
```
mContext.sendOrderedBroadcastAsUser(intent, targetUser, permission, appOp, opts,
users[i] == UserHandle.USER_SYSTEM ? resultReceiver : null,
getHandler(), Activity.RESULT_OK, null, null);
```
这里执行的是一个有序广播.
>优点:
1,按优先级的不同,优先Receiver可对数据进行处理,并传给下一个Receiver
2,通过abortBroadcast可终止广播的传播
看其参数:
intent: SMS_DELIVER_ACTION, SMS_RECEIVED_ACTION, FLAG_RECEIVER_FOREGROUND, FLAG_RECEIVER_NO_ABORTtargetUser: 默认就主用户吧. 不讨论
permission: android.Manifest.permission.RECEIVE_SMS
appOp: AppOpsManager.OP_RECEIVE_SMS, 应用需要该权限. 一般是默认短信应用才具有.
users[i] == UserHandle.USER_SYSTEM ? resultReceiver : null, 默认resultReceiver.
Activity.RESULT_OK: 返回的标志位. 不讨论
这里, 就可以发现, 这个有序广播发送了 SMS_RECEIVED_ACTION 信息. 这里基本上就可以明确 Demo 为什么这样写了.