您的位置:首页 > 移动开发 > Android开发

Android 4.2短信小记

2014-06-11 20:11 411 查看
Android4.2短信小记
一、短信发送流程
1.
ComposeMessageActivity.java
这个类中主要处理用户输入并且响应用户的点击事件。
在onClick()中,函数调用顺序confirmSendMessageIfNeeded()-> sendMessage(true)
2.
sendMessage中会调用到WorkingMessage的send方法:
mWorkingMessage.send(mDebugRecipients);


WorkingMessage的send方法会对此时消息做判断,如果包含Email或是MMS则启动彩信发送程序发送SendReq请求向MMSC. 彩信流程将会在以后介绍。
如果send方法判定为短信,则会new新线程。
new Thread(new Runnable() {
@Override
public void run() {
preSendSmsWorker(conv,msgText, recipientsInUI);
updateSendStats(conv);
}
}, "WorkingMessage.sendSMS").start();


3.
在新建线程中会调用preSendSmsWorker函式。
preSendSmsWorker其实只做以下几件事:
a. 调用MessageStatusListener的onPreMessageSent方法通知UI线程更新状态。
b. 调用sendSmsWorker函数去发送短信,参数包含了消息体接收人,所属线程id(此为消息所属会话线程ID,并非操作系统中的线程ID。
4.
sendSmsWorker函数中会创建SmsMessageSender实例并调用其sendMessage函式。
MessageSendersender = new SmsMessageSender(mActivity, dests, msgText, threadId);
sender.sendMessage(threadId);
5.
SmsMessageSender的sendMessage其实只是调用了自己的queueMessage。
queueMessage将消息入队,调用Framework中Telephony.java的内部类Sms,addMessageToUri将消息插入至SMS数据库(数据库的实现在smsprovider.java)
其中主要填写以下字段:
a. SUB_ID: 用于双卡标识
b. ADDRESS:发送地址
c. DATE:发送时间
d. READ:是否已读
e. SUBJECT:短信么有
f. BODY:消息体
g. STATUS:分为STATUS_COMPLETE,STATUS_PENDING,STATUS_FAILED,STATUS_NONE,此时会写为STATUS_PENDING。
h. THREAD_ID:会话线程ID.
值得注意的是STATUS与smsprovider在insert时会加入的TYPE, TYPE 中包含了MESSAGE_TYPE_INBOX,

MESSAGE_TYPE_SENT,
MESSAGE_TYPE_QUEUED,
MESSAGE_TYPE_OUTBOX等等。
此时我们是MESSAGE_TYPE_QUEUED类型。
6.
此时我们从Framework中回到app中。继续看queueMessage函式,在把数据加入队列后会发送广播消息ACTION_SEND_MESSAGE。此消息由SmsReceiver.java去接收。
mContext.sendBroadcast(newIntent(SmsReceiverService.ACTION_SEND_MESSAGE,
null,
mContext,
SmsReceiver.class));


7.
SmsReceiver.java接到消息就去startservice。这是编写android程序时常用的方法,在receiver中启动服务。在receiver中最好不处理长时间的数据,因为如果时间太长会阻塞UI线程并触发ANR。
public void onReceive(Context context, Intent intent) {
onReceiveWithPrivilege(context, intent, false);
}
protected voidonReceiveWithPrivilege(Context context, Intent intent, boolean privileged) {
if (!privileged &&intent.getAction().equals(Intents.SMS_RECEIVED_ACTION)) {
return;
}
intent.setClass(context,SmsReceiverService.class);
intent.putExtra("result",getResultCode());
beginStartingService(context, intent);
}


8.
SmsReceiverService的handleMessage会接收到ACTION_SEND_MESSAGE,此时会调用handleSendMessage,它会判断是否在发送状态,如果不在发送中则会调用sendFirstQueuedMessage去发送队列中的消息。
if(ACTION_SEND_MESSAGE.endsWith(action)) {
handleSendMessage();
}
private voidhandleSendMessage() {
if (!mSending) {
sendFirstQueuedMessage();
}
}


此队列就是我们之前调用framework的addMessageToUri函式插入的消息的队列。
9.
final Uri uri =Uri.parse("content://sms/queued");
ContentResolverresolver = getContentResolver();
Cursor c =SqliteWrapper.query(this, resolver, uri,
SEND_PROJECTION, null, null, "date ASC");


通过查询队列,取到队列中的消息后我们会构造SmsSingleRecipientSender实例,SmsSingleRecipientSender用于单笔消息的发送。SmsSingleRecipientSender的sendMessage函式将被调用。
SmsMessageSendersender = new SmsSingleRecipientSender(this,
address, msgText, threadId, status == Sms.STATUS_PENDING,msgUri);
try {
sender.sendMessage(SendingProgressTokenManager.NO_TOKEN);;
mSending = true;
} catch (MmsExceptione) {
mSending = false;
messageFailedToSend(msgUri,SmsManager.RESULT_ERROR_GENERIC_FAILURE);
success = false;
}


10.
sendMessage()主要做了以下几件事:
a. 如果目的地址为EMail地址,则会调用MmsConfig的getEmailGateway()取得预配置的SMS Email发送网关地址作为发送目的地址;
b. 调用SmsManager 的divideMessage;
c. 修改数据库中消息的TYPE,由MESSAGE_TYPE_QUEUED至MESSAGE_TYPE_OUTBOX;
d. 调用SmsManager的sendMultipartTextMessage去发送消息,单卡多卡会出现很多区别,使用的isms服务也存在区别。
11.
if (parts.size() > 1) {
try {
ISms iccISms =ISms.Stub.asInterface(ServiceManager.getService("isms"));
if(iccISms != null) {
iccISms.sendMultipartText(destinationAddress, scAddress, parts,
sentIntents, deliveryIntents);
}
} catch(RemoteException ex) {
//ignore it
}
} else {
PendingIntent sentIntent = null;
PendingIntent deliveryIntent = null;
if (sentIntents!= null && sentIntents.size() > 0) {
sentIntent = sentIntents.get(0);
}
if(deliveryIntents != null && deliveryIntents.size() > 0) {
deliveryIntent = deliveryIntents.get(0);
}
sendTextMessage(destinationAddress, scAddress, parts.get(0),
sentIntent, deliveryIntent);
}


这里不管是长短信还是普通短信,注意:
ISms iccISms =ISms.Stub.asInterface(ServiceManager.getService("isms"));
搜索代码可以发现只有IccSmsInterfaceManagerProxy类在ServiceManager登记了isms服务:
public IccSmsInterfaceManagerProxy(IccSmsInterfaceManager
iccSmsInterfaceManager) {
this.mIccSmsInterfaceManager = iccSmsInterfaceManager;
if(ServiceManager.getService("isms") == null) {
ServiceManager.addService("isms",this);
}
}


当是普通短信时,调用SmsManager的sendTextMessage函数,这里同样:
try {
ISmsiccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
if(iccISms != null) {
iccISms.sendText(destinationAddress,scAddress, text, sentIntent, deliveryIntent);
}
} catch(RemoteException ex) {
//ignore it
}


继续看IccSmsInterfaceManagerProxy类的sendText,
mIccSmsInterfaceManager.sendText(destAddr, scAddr, text,sentIntent, deliveryIntent);
继续看IccSmsInterfaceManager类的sendText,
mDispatcher.sendText(destAddr, scAddr, text, sentIntent,deliveryIntent);
查看SMSDispatcher类的sendText,这是个abstract函数:
protected abstract void sendText(String destAddr, String scAddr,
Stringtext, PendingIntent sentIntent, PendingIntent deliveryIntent);
搜索实现的类,CdmaSMSDispatcher和GsmSMSDispatcher都继承了SMSDispatcher。这里调用了GsmSMSDispatcher的sendText。在PhoneProxy的handleMessage中收到EVENT_RADIO_ON后调用:
mCommandsInterface.getVoiceRadioTechnology(
this.obtainMessage(EVENT_REQUEST_VOICE_RADIO_TECH_DONE));
之后:
case EVENT_VOICE_RADIO_TECH_CHANGED:
caseEVENT_REQUEST_VOICE_RADIO_TECH_DONE:
updatePhoneObject(newVoiceTech);
在此调用deleteAndCreatePhone(newVoiceRadioTech),关键之处是:
if (ServiceState.isCdma(newVoiceRadioTech)) {
mActivePhone = PhoneFactory.getCdmaPhone();
} else if(ServiceState.isGsm(newVoiceRadioTech)) {
mActivePhone = PhoneFactory.getGsmPhone();
}


根据手机类型,PhoneFactory创建相应的Phone:
Phone phone = new GSMPhone(sContext, sCommandsInterface,sPhoneNotifier);
在相应的构造函数中实例化SMSDispatcher mSMS:
mSMS = new GsmSMSDispatcher(this, mSmsStorageMonitor,mSmsUsageMonitor);
因此短信发送直接调用的是GsmSMSDispatcher的sendText。
12.
无论是sendMultipartText或sendText都会调用到ImsSMSDispatcher的相应函式,并且都会判断其发送方式CDMA或GSM. 两者的实例类为CdmaSMSDispatcher和GsmSMSDispatcher。
在sendText函式中会调用sendRawPdu函式,后会调用CdmaSMSDispatcher或GsmSMSDispatcher的sendSms函式,这里将会调用到Ril的sendSMS.
13.
Ril中将组装RILRequest,并发送至ril层。
14.
当RIL发送成功后processSolicited将接收到RIL_REQUEST_SEND_SMS的response.此时会触发消息并由SMSDispatcher的handleMessage接收,消息名为EVENT_SEND_SMS_COMPLETE,此时会调用handleSendComplete函式并把结果传入(AsyncResult)。
以下几件事会被handleSendComplete执行:
a. 如果发现mDeliveryIntent不等于空则表明需要传送报告,所以会将SmsTracker加入deliveryPendingList以等待传送报告回执。
b. 如果返回的exception不存在,则说明发送时未出现异常,所以会发送intent至SmsReceiver。(可能这里会感觉Ril怎么能知道通知谁并用什么action呢?其实都是得益于发送时传入的deliveryIntents与sentIntents,这个可以查看SmsSingleRecipientSender的sendMessage,每当你发送时都会事先构造好回执的intent.)SmsReceiverService收到MESSAGE_SENT_ACTION后会触发下一个队列中消息的发送。

二、短信接收流程
短信接收是从Ril.cpp通过socket与Ril.java的socket交流,在Ril.java中由RILReceiver进行监听。
for (;;) {
Parcel p;
length = readRilMessage(is, buffer);
………………
processResponse(p);
}


在这个for循环中读取数据并处理得到的数据。
private void processResponse (Parcel p) {
int type;
type = p.readInt();
if (type == RESPONSE_UNSOLICITED) {
processUnsolicited (p);
} else if (type == RESPONSE_SOLICITED){
processSolicited (p);
}
releaseWakeLockIfDone();
}


这里有主动上报(比如网络、短信、来电)和被动响应两种处理方式,短信属于主动上报,使用processUnsolicites进行处理。
case RIL_UNSOL_RESPONSE_NEW_SMS: {
……
SmsMessage sms;
sms = SmsMessage.newFromCMT(a);
if (mGsmSmsRegistrant != null) {
mGsmSmsRegistrant
.notifyRegistrant(newAsyncResult(null, sms, null));
}
break;


最终触发以上方法mGsmSmsRegistrant.notifyRegistrant()。这个方法在GsmSMSDispatcher的构造函数中给CommandsInterface设置handle的处理方法:
mCm.setOnNewGsmSms(this, EVENT_NEW_SMS, null);
mCm.setOnSmsStatus(this,EVENT_NEW_SMS_STATUS_REPORT, null);
mCm.setOnNewGsmBroadcastSms(this,EVENT_NEW_BROADCAST_SMS, null);


在SMSDispatcher的handleMessage函数中响应EVENT_NEW_SMS,最终在GsmSMSDispatcher的dispatchMessage函数中的dispatchNormalMessage处理,处理函数是dispatchPdus(pdus)。
protected void dispatchPdus(byte[][] pdus) {
Intent intent = newIntent(Intents.SMS_RECEIVED_ACTION);
intent.putExtra("pdus", pdus);
intent.putExtra("format",getFormat());
dispatch(intent, RECEIVE_SMS_PERMISSION);
}
public void dispatch(Intent intent, Stringpermission) {
mWakeLock.acquire(WAKE_LOCK_TIMEOUT);
mContext.sendOrderedBroadcast(intent,permission, mResultReceiver,
this, Activity.RESULT_OK, null, null);
}
private final BroadcastReceiver mResultReceiver = newBroadcastReceiver() {
@Override
publicvoid onReceive(Context context, Intent intent) {
if(intent.getAction().equals(Intents.SMS_CB_RECEIVED_ACTION) ||
intent.getAction().equals(Intents.SMS_EMERGENCY_CB_RECEIVED_ACTION)) {
// Ignore this intent. Apps will process it.
}else {
// Assume the intent is one of the SMS receive intents that
// was sent as an ordered broadcast. Check result and ACK.
int rc = getResultCode();
boolean success = (rc == Activity.RESULT_OK) || (rc ==Intents.RESULT_SMS_HANDLED);

// For a multi-part message, this only ACKs the last part.
// Previous parts were ACK'd as they were received.
acknowledgeLastIncomingSms(success, rc, null);
//子类调用接口mCm.acknowledgeLastIncomingGsmSms(success,resultToCause(result), response);
}
}
};


最后,可以看出这个方法将短信通过顺序广播播放出去(action是SMS_RECEIVED_ACTION= "android.provider.Telephony.SMS_RECEIVED";),无论广播是否被中断最后都会调用mResultReceiver,这里会将已读或未读的状态告诉给对方。 如果短信广播中间没有受到終止,那么接下来的流程是:在最上层的 APP中Mms模块中transation中的PrivilegedSmsReceiver类接收到android.provider.Telephony.SMS_RECEIVED广播请求,并获取携带短信数据的intent,然后调用intent.setClass(context,SmsReceiverService.class);
启动SmsReceiverService服务类来处理短信并保存短信(短信内容号码在PrivilegedSmsReceiver中接收到的intent里面)。
protected void onReceiveWithPrivilege(Contextcontext, Intent intent, boolean privileged) {
if(!privileged && intent.getAction().equals(Intents.SMS_RECEIVED_ACTION)){
return;
}
intent.setClass(context, SmsReceiverService.class);
intent.putExtra("result", getResultCode());
beginStartingService(context, intent);
}


最上层的App中的Mms里面:发送和接收短信的过程:
PrivilegedSmsReceiver把intent传递到 SmsReceiverService中SmsReceiverService中
@Override
public voidonCreate() {
//Temporarily removed for this duplicate message track down.
//        if(Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
//           Log.v(TAG, "onCreate");
//        }

//Start up the thread running the service. Note that we create a
//separate thread because the service normally runs in the process's
// mainthread, which we don't want to block.
HandlerThread thread = new HandlerThread(TAG,Process.THREAD_PRIORITY_BACKGROUND);
thread.start();

mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public intonStartCommand(Intent intent, int flags, int startId) {
//Temporarily removed for this duplicate message track down.
//        if(Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
//            Log.v(TAG, "onStart: #" + startId +": " + intent.getExtras());
//        }

mResultCode = intent != null ? intent.getIntExtra("result", 0): 0;

Messagemsg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj= intent;
mServiceHandler.sendMessage(msg);
returnService.START_NOT_STICKY;
}
启动service,调用 onStartCommand()把 intent转到Message里面,发送到ServiceHandler中处理
private final class ServiceHandler extends Handler {
publicServiceHandler(Looper looper) {
super(looper);
}

/**
*Handle incoming transaction requests.
* Theincoming requests are initiated by the MMSC Server or by the MMS Client itself.
*/
@Override
public voidhandleMessage(Message msg) {
intserviceId = msg.arg1;
Intent intent = (Intent)msg.obj;
if(intent != null) {
String action = intent.getAction();

int error = intent.getIntExtra("errorCode", 0);

if (MESSAGE_SENT_ACTION.equals(intent.getAction())) {
handleSmsSent(intent, error);
} else if (SMS_RECEIVED_ACTION.equals(action)) {
handleSmsReceived(intent, error);
} else if(SMS_CB_RECEIVED_ACTION.equals(action)) {
handleCbSmsReceived(intent, error);
} else if (ACTION_BOOT_COMPLETED.equals(action)) {
handleBootCompleted();
} else if (TelephonyIntents.ACTION_SERVICE_STATE_CHANGED.equals(action)){
handleServiceStateChanged(intent);
} else if (ACTION_SEND_MESSAGE.endsWith(action)) {
handleSendMessage();
} else if (Sms.Intents.WAP_PUSH_RECEIVED_ACTION.equals(action)) {
handleWapPushReceived(intent);
}
}
//NOTE: We MUST not call stopSelf() directly, since we need to
//make sure the wake lock acquired by AlertReceiver is released.
SmsReceiver.finishStartingService(SmsReceiverService.this, serviceId);
}
}


接收短信时,调用 handleSmsReceived()保存短信,得到 messageUri,通知更新相关标识符:
保存短信的过程分为两种情况:替换和保存(更新和插入数据表(Inbox.CONTENT_URI))
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: