犀渠玉剑良家子,白马金羁侠少年。这篇文章主要讲述Android5.0框架层短信接收过程分析相关的知识,希望能为你提供帮助。
本文分析使用的是android5.0的源代码,
涉及的相关文件:
frameworks\\opt\\telephony\\src\\java\\com\\android\\internal\\telephony\\RIL.java
frameworks\\base\\core\\java\\com\\android\\internal\\util\\StateMachine.java
frameworks\\opt\\telephony\\src\\java\\com\\android\\internal\\telephony\\InboundSmsTracker.java
frameworks\\opt\\telephony\\src\\java\\com\\android\\internal\\telephony\\InboundSmsHandler.java
frameworks\\opt\\telephony\\src\\java\\com\\android\\internal\\telephony\\gsm\\GsmInboundSmsHandler.java
先上时序图如下:
文章图片
第一部分: RIL.java
当安卓系统收到短信后, 首先被提交到RIL.java中进行处理:
1, 在RIL类中有一个内部类RILReceiver, 在该类的run方法中用来不断循环, 获取socket传来的数据, 调用readRilMessage方法获取短信Parcel对象p, 调用 processResponse(p)方法进行处理
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;
if (mInstanceId =
=
null || mInstanceId =
=
0 ) {
rilSocket =
SOCKET_NAME_RIL[0];
} else {
rilSocket =
SOCKET_NAME_RIL[mInstanceId];
}try {
s =
new LocalSocket();
l =
new LocalSocketAddress(rilSocket,
LocalSocketAddress.Namespace.RESERVED);
s.connect(l);
} catch (IOException ex){
try {
if (s !=
null) {
s.close();
}
} catch (IOException ex2) {
//ignore failure to close after failure to connect
}// don'
t print an error message after the the first time
// or after the 8th timeif (retryCount =
=
8) {
Rlog.e (RILJ_LOG_TAG,
"
Couldn'
t find '
"
+
rilSocket
+
"
'
socket after "
+
retryCount
+
"
times, continuing to retry silently"
);
} else if (retryCount >
0 &
&
retryCount <
8) {
Rlog.i (RILJ_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;
Rlog.i(RILJ_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);
//Rlog.v(RILJ_LOG_TAG, "
Read packet: "
+
length +
"
bytes"
);
processResponse(p);
p.recycle();
}
} catch (java.io.IOException ex) {
Rlog.i(RILJ_LOG_TAG, "
'
"
+
rilSocket +
"
'
socket closed"
,
ex);
} catch (Throwable tr) {
Rlog.e(RILJ_LOG_TAG, "
Uncaught exception read length=
"
+
length +
"
Exception:"
+
tr.toString());
}Rlog.i(RILJ_LOG_TAG, "
Disconnected from '
"
+
rilSocket
+
"
'
socket"
);
setRadiostate (RadioState.RADIO_UNAVAILABLE);
try {
mSocket.close();
} catch (IOException ex) {
}mSocket =
null;
RILRequest.resetSerial();
// Clear request list on close
clearRequestList(RADIO_NOT_AVAILABLE, false);
}} catch (Throwable tr) {
Rlog.e(RILJ_LOG_TAG,"
Uncaught exception"
, tr);
}/* We'
re disconnected so we don'
t know the ril version */
notifyRegistrantsRilConnectionChanged(-1);
}
}
2, 在processResponse方法中, 对应接收短信的Parcel类型是RESPONSE_UNSOLICITED( 未经请求) , 发送短信时是RESPONSE_SOLICITED( 被请求的) , 因此接收短信将调用processUnsolicited (p)方法。
private void processResponse (Parcel p) {
int type;
type =
p.readInt();
if (type =
=
RESPONSE_UNSOLICITED) {
processUnsolicited (p);
} else if (type =
=
RESPONSE_SOLICITED) {
RILRequest rr =
processSolicited (p);
if (rr !=
null) {
rr.release();
decrementWakeLock();
}
}
}
3, processUnsolicited方法将对不同的命令调用不同的操作, 通过调试可以发现将调用的是RIL_UNSOL_RESPONSE_NEW_SMS分支的操作, 把从Parcel中取出来的字符串封装成一个SmsMessage对象
private void processUnsolicited (Parcel p) {
…………
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 (mGsmSmsRegistrant !=
null) {
mGsmSmsRegistrant
.notifyRegistrant(new AsyncResult(null, sms, null));
}
break;
…………
}
4, 然后调用mGsmSmsRegistrant.notifyRegistrant(new AsyncResult(null, sms, null));
这里需要注意的是mGsmSmsRegistrant这个对象。该对象是在 RIL类的父类BaseCommands类中申明, 并通过setOnNewGsmSms方法来进行初始化的, 给这个Registrant指定handler h, 待发送给handler的消息的类型 what 以及待发送给handler的待处理的对象obj
frameworks\\opt\\telephony\\src\\java\\com\\android\\internal\\telephony\\BaseCommands.java
@
Override
public void setOnNewGsmSms(Handler h, int what, Object obj) {
mGsmSmsRegistrant =
new Registrant (h, what, obj);
//注意这个what
}
知道了这个mGsmSmsRegistrant这个对象是一个Registrant对象后, 我们来看他的notifyRegistrant方法
public void notifyRegistrant(AsyncResult ar)
{
internalNotifyRegistrant (ar.result, ar.exception);
}/*package*/ void
internalNotifyRegistrant (Object result, Throwable exception)
{
Handler h =
getHandler();
if (h =
=
null) {
clear();
} else {
Message msg =
Message.obtain();
msg.what =
what;
//这个what是在new Registrant(Handler h, int what, Object obj)进行初始化时赋值的一个成员变量msg.obj =
new AsyncResult(userObj, result, exception);
h.sendMessage(msg);
}
}
通过internalNotifyRegistrant方法我们可以发现, msg中包含了消息的类型, msg.obj中包含了我们将要处理的短信对象( SMsMessage对象) , 然后通过初始化时指定的Handler对象来处理这个msg, 因此, 我们需要找到这个处理短信数据的对象的Handler类。
在GsmInboundSmsHandler.java的GsmInboundSmsHandler类中发现GsmInboundSmsHandler构造函数中调用了setOnNewGsmSms方法
frameworks\\opt\\telephony\\src\\java\\com\\android\\internal\\telephony\\gsm\\GsmInboundSmsHandler.javaprivate GsmInboundSmsHandler(Context context, SmsStorageMonitor storageMonitor,
PhoneBase phone) {
super("
GsmInboundSmsHandler"
, context, storageMonitor, phone,
GsmCellBroadcastHandler.makeGsmCellBroadcastHandler(context, phone));
phone.mCi.setOnNewGsmSms(getHandler(), EVENT_NEW_SMS, null);
mDataDownloadHandler =
new UsimDataDownloadHandler(phone.mCi);
}GsmInboundSmsHandler父类是InboundSmsHandler
InboundSmsHandler的父类是StateMachine
getHandler()是StateMachine类中的方法,
返回成员变量private SmHandler mSmHandler;
public final Handler getHandler() {
return mSmHandler;
}
因此, 我们可以发现。 mGsmSmsRegistrant.notifyRegistrant(new AsyncResult(null, sms, null)); 这个函数的实质就是, 向SmHandler对象发送了一个消息Msg, 消息的类型是EVENT_NEW_SMS, 消息包含的对象时短信SmsMessgae对象。
至此, 第一部分RIL.java部分的短信处理完毕
第二部分: StateMachine, InboundSmsHandler, GsmInboundSmsHandler 通过状态机处理短信接收流程
这一部分是和android4.X版本中的短信接收较为不同的部分。这部分使用的是一个状态机的设计模式来解决短信问题。( 暂未完全理解)
接下来涉及到的主要三个类StateMachine, InboundSmsHandler, GsmInboundSmsHandler, 他们之间是继承的关系, InboundSmsHandler 继承自StateMachine, GsmInboundSmsHandler继承自InboundSmsHandler。
在第二部分的StateMachine类中主要是通过StateMachine的内部类SmHandler来进行消息的分发处理。( SmHandler代码都在StateMachine.java中)
【Android5.0框架层短信接收过程分析】( 通过时序图我们可以发现StateMachine( SmHandler) 主要是处理消息的分发, 主要是负责到达短信的处理, GsmInboundSmsHandler仅负责Gsm短信相关的判断处理。我们可以发现, 消息的分发是最一般的处理, 短信处理是次一般的处理, 而Gsm短信则是最特殊的处理。不得不说, 这源码写的真的漂亮)
在第一部分中RIL层向SmHandler对象发送了一个类型为EVENT_NEW_SMS的消息。由Handler机制, 我们可以知道, 必然会通过SmHandler的handleMessage方法进行处理, 即时序图中的第5步。
6, SmHandler的handleMessage方法主要是就是调用SmHandler的processMsg方法来处理消息。
private final State processMsg(Message msg) {
StateInfo curStateInfo =
mStateStack[mStateStackTopIndex];
if (mDbg) {
mSm.log("
processMsg: "
+
curStateInfo.state.getName());
}if (isQuit(msg)) {
transitionTo(mQuittingState);
} else {
while (!curStateInfo.state.processMessage(msg)) {
/**
* Not processed
*/
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;
}
这里需要注意curStateInfo.state是一个State对象, 主要包括在InboundSmsHandler类中定义几个内部类, DefaultState, StartupState, IdleState, DeliveringState, WaitingState这5个State之间相关转换, 这5个类都是继承自State类。
我是这么理解InboundSmsHandler的, 中文表述成, 已到达短信处理机, 这个处理机有5个状态, 分别是DefaultState, StartupState, IdleState, DeliveringState, WaitingState。在我的调试过程中, 主要是两个状态的转换, 当第一次调用SmHandler的processMsg方法时, curStateInfo.state.processMessage(msg)是通过WaitingState类的processMessage方法处理消息, 然后无法进行处理返回后, 通过curStateInfo = curStateInfo.parentStateInfo; 把WaitingState变成其父状态DeliveringState。然后再调用curStateInfo.state.processMessage(msg), 即调用DeliveringState的processMessage的方法进行短信消息处理。
InboundSmsHandler.javaclass 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:
// 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
if (processMessagePart((InboundSmsTracker) msg.obj)) {
transitionTo(mWaitingState);
}
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;
}
}
}
已知消息类型是EVENT_NEW_SMS, 即执行EVENT_NEW_SMS分支的代码, 即时序图中第13步调用handleNewSms((AsyncResult) msg.obj)
void handleNewSms(AsyncResult ar) {
if (ar.exception !=
null) {
loge("
Exception processing incoming SMS: "
+
ar.exception);
return;
}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);
}
}
14, 该方法取出消息中包含的SmsMessage对象。然后调用方法dispatchMessage;
15, 在dispatchMessage中调用dispatchMessageRadioSpecific方法, 该方法是在GsmInboundSmsHandler类中定义的方法。
16, dispatchMessageRadioSpecific方法的最后重新回到InboundSmsHandler.java中的dispatchNormalMessage方法, 把短信重新包装成一个InboundSmsTracker对象
17-19, 然后调用addTrackerToRawTableAndSendMessage(tracker)方法, 该方法会调用父类StateMachine的sendMessage(EVENT_BROADCAST_SMS, tracker)方法, 向其内部类SmHandler对象发送一个消息, 消息的类型是EVENT_BROADCAST_SMS, 消息包含的对象是InboundSmsTracker对象
20-23, StateMachine的内部类SmHandler对象再次处理消息, 最后消息也将在DeliveringState的processMessage方法中处理, 执行其EVENT_BROADCAST_SMS分支的代码。
24: 最后调用InboundSmsHandler类中的processMessagePart((InboundSmsTracker) msg.obj)方法
/**
* Process the inbound SMS segment. If the message is complete, send it as an ordered
* broadcast to interested receivers and return true. If the message is a segment of an
* incomplete multi-part SMS, return false.
* @
param tracker the tracker containing the message segment to process
* @
return true if an ordered broadcast was sent;
false if waiting for more message segments
*/
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 {
// 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());
// query for all segments and broadcast message if we have all the parts
String[] whereArgs =
{address, refNumber, count};
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.
return false;
}// 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();
}
}
}BroadcastReceiver 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);
pdu =
msg.getUserData();
}
output.write(pdu, 0, pdu.length);
}
int result =
mWapPush.dispatchWapPdu(output.toByteArray(), resultReceiver, this);
if (DBG) log("
dispatchWapPdu() returned "
+
result);
// result is Activity.RESULT_OK if an ordered broadcast was sent
return (result =
=
Activity.RESULT_OK);
}Intent intent =
new Intent(Intents.SMS_FILTER_ACTION);
List<
String>
carrierPackages =
null;
UiccCard card =
UiccController.getInstance().getUiccCard();
if (card !=
null) {
carrierPackages =
card.getCarrierPackageNamesForIntent(
mContext.getPackageManager(), intent);
}
if (carrierPackages !=
null &
&
carrierPackages.size() =
=
1) {
intent.setPackage(carrierPackages.get(0));
intent.putExtra("
destport"
, destPort);
} else {
setAndDirectIntent(intent, destPort);
}intent.putExtra("
pdus"
, pdus);
intent.putExtra("
format"
, tracker.getFormat());
dispatchIntent(intent, android.Manifest.permission.RECEIVE_SMS,
AppOpsManager.OP_RECEIVE_SMS, resultReceiver, UserHandle.OWNER);
return true;
}
该方法主要是创建了 BroadcastReceiver resultReceiver = new SmsBroadcastReceiver(tracker); 一个广播接收器。
创建了intent, 并通过setAndDirectIntent方法把intent的action设置成Intents.SMS_DELIVER_ACTION。这代表这个广播只能被默认短信应用接收。
最后调用dispatchIntent(intent, android.Manifest.permission.RECEIVE_SMS,AppOpsManager.OP_RECEIVE_SMS, resultReceiver, UserHandle.OWNER); 发送广播。
/**
* Dispatch the intent with the specified permission, appOp, and result receiver, using
* this state machine'
s handler thread to run the result receiver.
*
* @
param intent the intent to broadcast
* @
param permission receivers are required to have this permission
* @
param appOp app op that is being performed when dispatching to a receiver
* @
param user user to deliver the intent to
*/
protected void dispatchIntent(Intent intent, String permission, int appOp,
BroadcastReceiver resultReceiver, UserHandle user) {
intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT);
SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId());
if (user.equals(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_OWNER) {
// 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_OWNER is processed.
mContext.sendOrderedBroadcastAsUser(intent, targetUser, permission, appOp,
users[i] =
=
UserHandle.USER_OWNER ? resultReceiver : null,
getHandler(), Activity.RESULT_OK, null, null);
}
} else {
mContext.sendOrderedBroadcastAsUser(intent, user, permission, appOp,
resultReceiver,
getHandler(), Activity.RESULT_OK, null, null);
}
}
29, 最后调用sendOrderedBroadcastAsUser方法发送广播, 且该广播的最后一个接收者是之前创建的 SmsBroadcastReceiver类型的广播
30, 因此, 当发送完这条给默认短信应用专用的短信广播后, 将会回到SmsBroadcastReceiver的onReceive方法中
/**
* Handler for an {@
link InboundSmsTracker} broadcast. Deletes PDUs from the raw table and
* logs the broadcast duration (as an error if the other receivers were especially slow).
*/
private final class SmsBroadcastReceiver extends BroadcastReceiver {
private final String mDeleteWhere;
private final String[] mDeleteWhereArgs;
private long mBroadcastTimeNano;
SmsBroadcastReceiver(InboundSmsTracker tracker) {
mDeleteWhere =
tracker.getDeleteWhere();
mDeleteWhereArgs =
tracker.getDeleteWhereArgs();
mBroadcastTimeNano =
System.nanoTime();
}@
Override
public void onReceive(Context context, Intent intent) {
String action =
intent.getAction();
if (action.equals(Intents.SMS_FILTER_ACTION)) {
int rc =
getResultCode();
if (rc =
=
Activity.RESULT_OK) {
// Overwrite pdus data if the SMS filter has set it.
Bundle resultExtras =
getResultExtras(false);
if (resultExtras !=
null &
&
resultExtras.containsKey("
pdus"
)) {
intent.putExtra("
pdus"
, (byte[][]) resultExtras.get("
pdus"
));
}
if (intent.hasExtra("
destport"
)) {
int destPort =
intent.getIntExtra("
destport"
, -1);
intent.removeExtra("
destport"
);
setAndDirectIntent(intent, destPort);
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());
}
}
dispatchIntent(intent, android.Manifest.permission.RECEIVE_SMS,
AppOpsManager.OP_RECEIVE_SMS, this, UserHandle.OWNER);
} else {
loge("
destport doesn'
t exist in the extras for SMS filter action."
);
}
} else {
// Drop this SMS.
log("
SMS filtered by result code "
+
rc);
deleteFromRawTable(mDeleteWhere, mDeleteWhereArgs);
sendMessage(EVENT_BROADCAST_COMPLETE);
}
} else if (action.equals(Intents.SMS_DELIVER_ACTION)) {
// Now dispatch the notification only intent
intent.setAction(Intents.SMS_RECEIVED_ACTION);
intent.setComponent(null);
// All running users will be notified of the received sms.
dispatchIntent(intent, android.Manifest.permission.RECEIVE_SMS,
AppOpsManager.OP_RECEIVE_SMS, this, UserHandle.ALL);
} else if (action.equals(Intents.WAP_PUSH_DELIVER_ACTION)) {
// Now dispatch the notification only intent
intent.setAction(Intents.WAP_PUSH_RECEIVED_ACTION);
intent.setComponent(null);
// Only the primary user will receive notification of incoming mms.
// That app will do the actual downloading of the mms.
dispatchIntent(intent, android.Manifest.permission.RECEIVE_SMS,
AppOpsManager.OP_RECEIVE_SMS, this, UserHandle.OWNER);
} else {
// Now that the intents have been deleted we can clean up the PDU data.
if (!Intents.DATA_SMS_RECEIVED_ACTION.equals(action)
&
&
!Intents.SMS_RECEIVED_ACTION.equals(action)
&
&
!Intents.DATA_SMS_RECEIVED_ACTION.equals(action)
&
&
!Intents.WAP_PUSH_RECEIVED_ACTION.equals(action)) {
loge("
unexpected BroadcastReceiver action: "
+
action);
}int rc =
getResultCode();
if ((rc !=
Activity.RESULT_OK) &
&
(rc !=
Intents.RESULT_SMS_HANDLED)) {
loge("
a broadcast receiver set the result code to "
+
rc
+
"
, deleting from raw table anyway!"
);
} else if (DBG) {
log("
successful broadcast, deleting from raw table."
);
}deleteFromRawTable(mDeleteWhere, mDeleteWhereArgs);
sendMessage(EVENT_BROADCAST_COMPLETE);
int durationMillis =
(int) ((System.nanoTime() - mBroadcastTimeNano) / 1000000);
if (durationMillis >
=
5000) {
loge("
Slow ordered broadcast completion time: "
+
durationMillis +
"
ms"
);
} else if (DBG) {
log("
ordered broadcast completed in: "
+
durationMillis +
"
ms"
);
}
}
}
}
看到else if (action.equals(Intents.SMS_DELIVER_ACTION))分支处, 重新设置intent的action为 Intents.SMS_RECEIVED_ACTION, 然后同样通过dispatchIntent方法, 将这条广播发送给所有人。即所有普通应用将收到这条广播。
疑问: 为什么sendOrderedBroadcastAsUser方法发送的有序广播无法被截断?
分析完了短信接收, 最大的疑问就是都是通过dispatchIntent方法最后调用sendOrderedBroadcastAsUser方法来发送广播, 这样子理论上来说都是发送的有序广播。那么和网上的说法发送两条广播一条是发送给默认短信应用的有序广播, 一条是发给所有人的无序广播的说法不一致啊。。
接下来, 我进行了试验测试,
我写了两个应用A,B, 都注册短信广播, 并且A的广播优先级高于B, A和B都获取短信后调用abortBroadcast截断广播。
A广播代码:
package com.yyt.sockettest;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Message;
import android.telephony.SmsMessage;
import android.util.Log;
import android.widget.Toast;
public class SmsBroadCastReceiver extends BroadcastReceiver { @
Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stubBundle bundleres =
getResultExtras(true);
if(bundleres=
=
null){
Log.e("
smsA"
, "
bundleRes null"
);
}else{
Log.e("
smsA"
, "
bundleRes not null"
);
int xx=
bundleres.getInt("
myCount"
);
Log.e("
Broadcast ResInt"
, Integer.toString(xx));
}bundleres.putInt("
myCount"
, 100);
setResultExtras(bundleres);
Bundle bundle =
intent.getExtras();
Object[] object =
(Object[])bundle.get("
pdus"
);
SmsMessage sms[]=
new SmsMessage[object.length];
for(int i=
0;
i<
object.length;
i+
+
)
{
sms[i] =
SmsMessage.createFromPdu((byte[])object[i]);
Toast.makeText(context, "
来自"
+
sms[i].getDisplayOriginatingAddress()+
"
的消息是:
"
+
sms[i].getDisplayMessageBody(), Toast.LENGTH_SHORT).show();
}
Log.e("
smssms"
, sms[0].getDisplayMessageBody());
//终止广播,
在这里我们可以稍微处理,
根据用户输入的号码可以实现短信防火墙。
abortBroadcast();
Message msg =
Message.obtain();
msg.obj =
sms[0].getDisplayMessageBody();
MainActivity.handler.sendMessage(msg);
}
}
静态注册的广播,
优先级为1000
<
receiver android:name=
"
.SmsBroadCastReceiver"
>
<
intent-filter android:priority=
"
1000"
>
<
action android:name=
"
android.provider.Telephony.SMS_RECEIVED"
/>
<
/intent-filter>
<
/receiver>
B广播代码:
package com.example.testsms2;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Message;
import android.telephony.SmsMessage;
import android.util.Log;
import android.widget.Toast;
public class SmsBroadCastReceiver extends BroadcastReceiver { @
Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
Bundle bundleres =
getResultExtras(true);
if(bundleres=
=
null){
Log.e("
smsB"
, "
bundleRes null"
);
}else{
Log.e("
smsB"
, "
bundleRes not null"
);
int xx=
bundleres.getInt("
myCount"
);
Log.e("
Broadcast ResInt22"
, Integer.toString(xx));
}bundleres.putInt("
myCount"
, 500);
setResultExtras(bundleres);
Bundle bundle =
intent.getExtras();
Object[] object =
(Object[])bundle.get("
pdus"
);
SmsMessage sms[]=
new SmsMessage[object.length];
for(int i=
0;
i<
object.length;
i+
+
)
{
sms[i] =
SmsMessage.createFromPdu((byte[])object[i]);
Toast.makeText(context, "
来自"
+
sms[i].getDisplayOriginatingAddress()+
"
的消息是:
"
+
sms[i].getDisplayMessageBody(), Toast.LENGTH_SHORT).show();
}
Log.e("
smssms2222"
, sms[0].getDisplayMessageBody());
//终止广播,
在这里我们可以稍微处理,
根据用户输入的号码可以实现短信防火墙。
abortBroadcast();
Message msg =
Message.obtain();
msg.obj =
sms[0].getDisplayMessageBody();
}
}在MainActivity的OnCreate方法中动态注册
receiver =
new SmsBroadCastReceiver();
IntentFilter iFilter =
new IntentFilter("
android.provider.Telephony.SMS_RECEIVED"
);
iFilter.setPriority(20000);
registerReceiver(receiver, iFilter);
模拟发送短信测试后, 发现A,B应用都能获取到短信。。。
我又进行测试, 通过getResultExtras发现A,B都能获取到非空的budle对象, 且B应用输出数字0, A应用输出数字500, 说明B确实优先A收到的短信, 但是截断不成功。
理论上说如果接收的是无序广播, 那么getResultExtras方法返回的值必然是空, 而非空, 则代表是有序广播, 那么无法截断又如何解释呢。。。。。。。
奇怪的问题。。。未完待续。。。。。。。。。。。。。
推荐阅读
- Android7.0下载Apk自动安装
- Android异常分析(转)
- Android单元测试Junit的配置
- Android防止Service被杀死
- 开发 Material Design+RxJava+Retrofit+MVP App 参考资料
- iMX6开发板烧写Android系统
- Android自动化测试怎么填写Xpath
- IDEA基于kotlin开发android程序配置小结
- Android后台执行的定时器实现