`

彩信流程(一)

 
阅读更多

写彩信发送过程。

我想追踪的内容是:用户按下发送之后,彩信的图片阿数据阿文件阿,是怎么包装起来,最后发送出去。

按我看源码的先后顺序来写了。 写完可能最后整理下。

1. com.android.mms.data.WorkingMessage.java 类

send()函数。 注释如下:
/**
* Send this message over the network. Will call back with onMessageSent()
* once it has been dispatched to the telephony stack. This WorkingMessage
* object is no longer useful after this method has been called.
*/
这个是2.1的源码
Java代码

复制到剪贴板 Java代码
  1. public void send(){
  2. if (Log.isLoggable(LogTag.TRANSACTION,Log.VERBOSE)){
  3. LogTag.debug( "send" );
  4. }
  5. //Getreadytowritetodisk.
  6. prepareForSave( true /*notify*/ );
  7. //WeneedtherecipientlistforbothSMSandMMS.
  8. final Conversationconv=mConversation;
  9. StringmsgTxt=mText.toString();
  10. if (requiresMms()||addressContainsEmailToMms(conv,msgTxt)){
  11. //Makelocalcopiesofthebitsweneedforsendingamessage,
  12. //becausewewillbedoingitoffofthemainthread,whichwill
  13. //immediatelycontinueontoresettingsomeofthisstate.
  14. final UrimmsUri=mMessageUri;
  15. final PduPersisterpersister=PduPersister
  16. .getPduPersister(mContext);
  17. final SlideshowModelslideshow=mSlideshow;
  18. final SendReqsendReq=makeSendReq(conv,mSubject);
  19. //Makesurethetextinslide0isnolongerholdingontoa
  20. //referencetothetext
  21. //inthemessagetextbox.
  22. slideshow.prepareForSend();
  23. //DothedirtyworkofsendingthemessageoffofthemainUI
  24. //thread.
  25. new Thread( new Runnable(){
  26. public void run(){
  27. sendMmsWorker(conv,mmsUri,persister,slideshow,sendReq);
  28. }
  29. }).start();
  30. } else {
  31. //Samerulesapplyasabove.
  32. final StringmsgText=mText.toString();
  33. new Thread( new Runnable(){
  34. public void run(){
  35. sendSmsWorker(conv,msgText);
  36. }
  37. }).start();
  38. }
  39. //updatetheRecipientcachewiththenewtoaddress,ifit'sdifferent
  40. RecipientIdCache
  41. .updateNumbers(conv.getThreadId(),conv.getRecipients());
  42. //Markthemessageasdiscardedbecauseitis"offthemarket"after
  43. //beingsent.
  44. mDiscarded= true ;
  45. }

粗浅的解说一下,
(1) prapareForSave. 先确保有slidshow,也就是实质内容。 确保文字已拷贝。确保标题。
(2a) 根据消息分类,如果是短信直接起一个线程,跑sendSmsWorker函数,发送短信
(2b) 如果是彩信,先跑这么个函数,确保文本信息
// Make sure the text in slide 0 is no longer holding onto a // reference to the text // in the message text box.
slideshow.prepareForSend();
TheCranberriers(卡百利)的歌真好听。
然后起一个线程,单独跑sendMmsWorker函数,后文有介绍。
彩 信比sms麻烦很多。从sendMmsWorker函数的参数就可以看出来:(conv, mmsUri, persister, slideshow, sendReq) 上下文,uri,PduPersister(彩信是用pdu的),slideshow包含了所有的彩信信息,sendreq包含了mime封装mms时的 headers(在我的剥壳彩信2里面有提到)。包括了 ContentType("application/vnd.wap.multipart.related" ,from,to等信息 。

(3)。 不管是短信还是彩信,起了那俩个worker函数之一就算发送信息成功了。
最后修改Recipient cache, 重置标志位,过程就结束了。


2。函数 sendMmsWorker
Java代码

复制到剪贴板 Java代码
  1. private void sendMmsWorker(Conversationconv,UrimmsUri,
  2. PduPersisterpersister,SlideshowModelslideshow,SendReqsendReq){
  3. //Firstmakesurewedon'thavetoomanyoutstandingunsentmessage.
  4. Cursorcursor= null ;
  5. try {
  6. Log.d( "GN@@@" , "mContext:" +mContext.toString());
  7. Log.d( "GN@@@" , "mContentResolver:" +mContentResolver.toString());
  8. Log.d( "GN@@@" , "Mms.Outbox.CONTENT_URI:" +Mms.Outbox.CONTENT_URI.toString());
  9. cursor=SqliteWrapper.query(mContext,mContentResolver,
  10. Mms.Outbox.CONTENT_URI,MMS_OUTBOX_PROJECTION, null , null ,
  11. null );
  12. if (cursor!= null ){
  13. long maxMessageSize=MmsConfig
  14. .getMaxSizeScaleForPendingMmsAllowed()
  15. *MmsConfig.getMaxMessageSize();
  16. long totalPendingSize= 0 ;
  17. while (cursor.moveToNext()){
  18. totalPendingSize+=cursor.getLong(MMS_MESSAGE_SIZE_INDEX);
  19. }
  20. if (totalPendingSize>=maxMessageSize){
  21. unDiscard(); //itwasn'tsuccessfullysent.Allowittobe
  22. //savedasadraft.
  23. mStatusListener.onMaxPendingMessagesReached();
  24. return ;
  25. }
  26. }
  27. } finally {
  28. if (cursor!= null ){
  29. cursor.close();
  30. }
  31. }
  32. mStatusListener.onPreMessageSent();
  33. //MakesurewearestillusingthecorrectthreadIDforour
  34. //recipientset.
  35. long threadId=conv.ensureThreadId();
  36. if (Log.isLoggable(LogTag.APP,Log.VERBOSE)){
  37. LogTag.debug( "sendMmsWorker:updatedraftMMSmessage" +mmsUri);
  38. }
  39. if (mmsUri== null ){
  40. //CreateanewMMSmessageifonehasn'tbeenmadeyet.
  41. mmsUri=createDraftMmsMessage(persister,sendReq,slideshow);
  42. } else {
  43. //Otherwise,synctheMMSmessageinprogresstodisk.
  44. updateDraftMmsMessage(mmsUri,persister,slideshow,sendReq);
  45. }
  46. //BeparanoidandcleananydraftSMSup.
  47. deleteDraftSmsMessage(threadId);
  48. MessageSendersender= new MmsMessageSender(mContext,mmsUri,slideshow
  49. .getCurrentMessageSize());
  50. try {
  51. if (!sender.sendMessage(threadId)){
  52. //ThemessagewassentthroughSMSprotocol,weshould
  53. //deletethecopywhichwaspreviouslysavedinMMSdrafts.
  54. SqliteWrapper.delete(mContext,mContentResolver,mmsUri, null ,
  55. null );
  56. }
  57. //Makesurethisthreadisn'toverthelimitsinmessagecount
  58. Recycler.getMmsRecycler().deleteOldMessagesByThreadId(mContext,
  59. threadId);
  60. } catch (Exceptione){
  61. Log.e(TAG, "Failedtosendmessage:" +mmsUri+ ",threadId="
  62. +threadId,e);
  63. }
  64. mStatusListener.onMessageSent();
  65. }

依旧是粗浅的解说:
a )前面挺长一段代码,检查这个对话(conversation)之前还有没有未发送的信息,uri是Mms.Outbox.CONTENT_URI。
这 里需要提到一下MessageStatusListener,这个Interface接口实现在WorkingMessage.java里,而短信类的主 题ComposeMessageActivity.java实现了这个接口,所以前者在一些状态改变的时候可以很方便的调用后者的一些函数,作相应的改 动。主要是:onProtocolChanged彩信短信互切换,onAttachmentChanged福建改变,onPreMessageSent发 消息前,onMessageSent发消息后。
b)
当然,这里调用了onPreMessageSent这个监听函数,
然后ComposeMessageActivity 就会调用resetMessage函数 ,这个函数会调整显示,focus,软键盘等等。
c)
然后检查mmsUri。如果这个uri是空的话,直接造一个新的uri继续发送。这个真是让我叫亚灭爹。因为一开始不知道
这个createDraftMmsMessage(persister, sendReq, slideshow);函数可以包含所有发送需要的信息,以为这么发出去太可怕了。
如果uri不为空。 调用的是updateDraftMmsMessage(mmsUri, persister, slideshow, sendReq);
总之功能是,把这个将发送的mms,存disk了,也就是存draft了。为什么要发送还要存draft呢,后面另会说,因为这个是我写这个文章前想要找的东西。。。这个过程还有一些信息写道mmsUri了。所以之后mmsUri就可以代表将发送的mms的全部信息。
d)deleteDraftSmsMessage 删除草稿
e)创建一个MmsMessageSender,用这个sender来调用sendMessage函数
可以猜到的,Sms那边是SmsMessageSender,同样调用sendMessage函数
通过这里之后,短信已经真的发掉了。 这个类后面有介绍。
f)这里这个if相当搞笑,按正常流程下来,按理这里本来这里是一个彩信的发送,然后有一些数据在draft数据库,会在上面的流程中被移到send数据库。
但是搞笑的地方来了:因为忽然发现函数返回值表示刚刚发送出去的其实是一个短信sms,而已。于是要把数据库里存着的draft删掉。
我也不知道这个if里面的情况会不会发生,反正源码是这么写的,我只管不负责任直译。。。
g)调用onMessageSent这个监听函数。调用ComposeMessageActivity的onMessageSent,这个函数功能是重新显示conversation list。


3 MmsMessageSender.java类。在mms/transaction下面。实现了MessageSender接口。这个接口只有一个事儿, 就是sendMessage并返回boolean的值。弱发送的是mms,返回true。若发送的是sms,返回false。出错返回 啥?exception。

我最先想要追踪的发送流程也在这里了。贴一些代码
Java代码

复制到剪贴板 Java代码
  1. public MmsMessageSender(Contextcontext,Urilocation, long messageSize){
  2. mContext=context;
  3. mMessageUri=location;
  4. mMessageSize=messageSize;
  5. if (mMessageUri== null ){
  6. throw new IllegalArgumentException( "NullmessageURI." );
  7. }
  8. }
  9. Java代码
  10. public boolean sendMessage( long token) throws MmsException{
  11. //LoadtheMMSfromthemessageuri
  12. PduPersisterp=PduPersister.getPduPersister(mContext);
  13. GenericPdupdu=p.load(mMessageUri);
  14. if (pdu.getMessageType()!=PduHeaders.MESSAGE_TYPE_SEND_REQ){
  15. throw new MmsException( "Invalidmessage:" +pdu.getMessageType());
  16. }
  17. SendReqsendReq=(SendReq)pdu;
  18. //Updateheaders.
  19. updatePreferencesHeaders(sendReq);
  20. //MessageClass.
  21. sendReq.setMessageClass(DEFAULT_MESSAGE_CLASS.getBytes());
  22. //Updatethe'date'fieldofthemessagebeforesendingit.
  23. sendReq.setDate(System.currentTimeMillis()/1000L);
  24. sendReq.setMessageSize(mMessageSize);
  25. p.updateHeaders(mMessageUri,sendReq);
  26. //MovethemessageintoMMSOutbox
  27. p.move(mMessageUri,Mms.Outbox.CONTENT_URI);
  28. //StartMMStransactionservice
  29. SendingProgressTokenManager
  30. .put(ContentUris.parseId(mMessageUri),token);
  31. mContext.startService( new Intent(mContext,TransactionService. class ));
  32. return true ;
  33. }

解说:
现从PduPersister那里拿数据,包括需要拼装的发送报头和需要发送的数据信息。
然后把要发送的信息相关数据从数据库的draft那里转移到send,表示已经发送。
最后起一个TransactionService服务,这个服务也是从PduPersister里找,找到需要发送的数据,并通过不同的用户网络送出去。
这块我猜一般人都没有改的需求。。

4.
createDraftMmsMessage(persister, sendReq, slideshow); 和
updateDraftMmsMessage(mmsUri, persister, slideshow, sendReq); 这两个函数

刨掉 try catch , createDraftMmsMessage 函数大概有这么几句:

复制到剪贴板 Java代码
  1. Java代码
  2. PduBodypb=slideshow.toPduBody();
  3. sendReq.setBody(pb);
  4. Urires=persister.persist(sendReq,Mms.Draft.CONTENT_URI);
  5. slideshow.sync(pb);
  6. updateDraftMmsMessage函数大概有这么几句:
  7. Java代码
  8. persister.updateHeaders(uri,sendReq);
  9. final PduBodypb=slideshow.toPduBody();
  10. persister.updateParts(uri,pb);
  11. slideshow.sync(pb);

两个函数从本质上讲是一样的:把附件的东西以pdubody的形式存下来,另外就是更新uri。
什么叫PduBody呢? 厉害了。就是n个PduPart。什么叫PduPart呢?厉害了,就是数据库里的那个Part! 那个part是什么?
那个最厉害了。数据库里的PART_1234455这种数据,文件名代表创建时间(在mediaModel产生时就进系统了),导出来就是源文件,比如图片文件,改个jpg就可以看了。

sync函数不怎么动,无责任解说:把每个slide里面每个媒体跟真实文件位置对应上。

slideshow.toPduBody();里面,用SMILDocument mDocumentCache;
调用到SlideshowModel.java的
Java代码

复制到剪贴板 Java代码
  1. //其中context= null 。isMakingCopy= false 。document=mDocumentCache
  2. private PduBodymakePduBody(Contextcontext,SMILDocumentdocument,
  3. boolean isMakingCopy){
  4. PduBodypb= new PduBody();
  5. boolean hasForwardLock= false ;
  6. for (SlideModelslide:mSlides){
  7. for (MediaModelmedia:slide){
  8. if (isMakingCopy){
  9. if (media.isDrmProtected()&&!media.isAllowedToForward()){
  10. hasForwardLock= true ;
  11. continue ;
  12. }
  13. }
  14. PduPartpart= new PduPart();
  15. if (media.isText()){
  16. TextModeltext=(TextModel)media;
  17. //Don'tcreateemptytextpart.
  18. if (TextUtils.isEmpty(text.getText())){
  19. continue ;
  20. }
  21. //SetCharsetifit'satextmedia.
  22. part.setCharset(text.getCharset());
  23. }
  24. //SetContent-Type.
  25. part.setContentType(media.getContentType().getBytes());
  26. Stringsrc=media.getSrc();
  27. Stringlocation;
  28. boolean startWithContentId=src.startsWith( "cid:" );
  29. if (startWithContentId){
  30. location=src.substring( "cid:" .length());
  31. } else {
  32. location=src;
  33. }
  34. //SetContent-Location.
  35. part.setContentLocation(location.getBytes());
  36. //SetContent-Id.
  37. if (startWithContentId){
  38. //KeeptheoriginalContent-Id.
  39. part.setContentId(location.getBytes());
  40. } else {
  41. int index=location.lastIndexOf( "." );
  42. StringcontentId=(index==- 1 )?location:location
  43. .substring( 0 ,index);
  44. part.setContentId(contentId.getBytes());
  45. }
  46. if (media.isDrmProtected()){
  47. DrmWrapperwrapper=media.getDrmObject();
  48. part.setDataUri(wrapper.getOriginalUri());
  49. part.setData(wrapper.getOriginalData());
  50. } else if (media.isText()){
  51. part.setData(((TextModel)media).getText().getBytes());
  52. } else if (media.isImage()||media.isVideo()
  53. ||media.isAudio()){
  54. part.setDataUri(media.getUri());
  55. } else {
  56. Log.w(TAG, "Unsupportmedia:" +media);
  57. }
  58. pb.addPart(part);
  59. }
  60. }
  61. if (hasForwardLock&&isMakingCopy&&context!= null ){
  62. Toast.makeText(context,
  63. context.getString(R.string.cannot_forward_drm_obj),
  64. Toast.LENGTH_LONG).show();
  65. document=SmilHelper.getDocument(pb);
  66. }
  67. //CreateandinsertSMILpart(asthefirstpart)intothePduBody.
  68. ByteArrayOutputStreamout= new ByteArrayOutputStream();
  69. SmilXmlSerializer.serialize(document,out);
  70. PduPartsmilPart= new PduPart();
  71. smilPart.setContentId( "smil" .getBytes());
  72. smilPart.setContentLocation( "smil.xml" .getBytes());
  73. smilPart.setContentType(ContentType.APP_SMIL.getBytes());
  74. smilPart.setData(out.toByteArray());
  75. pb.addPart( 0 ,smilPart);
  76. return pb;
  77. }

好了,齐活儿了

顺序有点乱。抱歉。。。

分享到:
评论

相关推荐

    移动业务下手机的彩信信令流程(包括信令结构,用于移动通信)

    总的来说,彩信的信令流程是一个涉及多个步骤的复杂过程,涉及到WAP协议栈、PDU编码和多种交互消息。理解这一流程对于开发MMS应用、优化网络性能以及解决移动通信中的问题都至关重要。通过MMS,用户能够享受到更丰富...

    彩信业务的流程与介绍

    彩信业务,全称多媒体信息服务(Multimedia Messaging Service, 简称MMS),是一种允许移动设备用户发送和接收包含多媒体内容,如图片、音频、视频片段和文本的富通信服务。与传统的短信(SMS)相比,彩信提供了更...

    Android MMS彩信发送代码流程+UML流程图

    Android MMS 彩信发送代码流程是 Android 操作系统中一个复杂的过程,涉及到多个应用层和系统服务的交互。下面将对该过程进行详细解释,从 Messaging 应用层到 framework 应用层的实现细节。 一、Messaging 应用层 ...

    GSM模块发彩信的步骤流程

    ### GSM模块发彩信的步骤流程 #### 概述 - **主题**:介绍如何使用GSM模块发送彩信(MMS),包括理解彩信发送的过程、步骤、所需的指令和程序。 - **适用对象**:对GSM模块感兴趣的工程师、开发者和技术人员。 ###...

    彩信收发流程分析方法

    #### 一、彩信接收分析 彩信接收流程涉及复杂的信令交互,其分析对理解网络性能及优化至关重要。以下是对彩信(1.0)与彩信(2.0)接收流程的深入解析。 ##### 1.1 彩信(1.0)接收信令流程分析 彩信(1.0)基于...

    MMS彩信业务流程及代码实现

    **MMS彩信业务流程及代码实现** MMS(Multimedia Messaging Service)即多媒体信息服务,是一种在移动网络中发送和接收包含文本、图像、音频、视频等多媒体内容的消息服务。与传统的SMS短信相比,MMS提供了更为丰富...

    彩信信令流程.pdf

    彩信信令流程是移动通信领域中的一种重要的业务流程,涉及到移动终端、MMSC(Multimedia Messaging Service Center)、WAP 网关、短信中心等多个组件。下面我们将详细解释彩信信令流程中的各个步骤和组件。 第一步...

    最简单的android彩信发送代码。适合学习彩信发送流程

    最简单的android彩信发送代码。适合学习彩信发送流程。 事实上android中的Mms模块中,对这个流程进行了很少的封装,这里就是将其简化,帮助初学者了解流程。

    彩信业务常见问题客服流程

    在IT行业中,彩信业务是一种常见的通信服务,它允许用户发送包含多媒体内容的短信,如图片、音频或视频片段。华为作为全球领先的电信设备和服务提供商,其彩信业务的客服流程对于开发人员和运维团队来说至关重要,...

    短信彩信全流程 动画版本PPT

    **短信与彩信全流程解析** 短信(Short Message Service, SMS)和彩信(Multimedia ...通过深入学习这个PPT,无论是IT从业者还是普通用户,都能对短信和彩信服务有更全面的认识,对于通信网络的理解也会更上一层楼。

    彩信的交互过程,彩信的PDU,彩信的PDU编码

    每种PDU类型都有其特定的格式和用途,它们共同协作完成整个彩信的传输流程。 彩信的PDU编码是数据传输的重要环节。彩信PDU的编码方式与HTTP协议有所相似,但采取的是二进制编码方式,这样做是为了更高效地利用带宽...

    cmpp,sgip,smgp 彩信,视频短信发送和接收流程.doc

    介绍了 cmpp sgip smgp协议的彩信,视频短信的的开发流程 包含了pdu编码解析,流程讲解等

    彩信收发原理图,彩信

    通过对彩信收发原理图的分析与解读,我们不仅了解了彩信的基本概念及其与传统短信的区别,还深入探讨了彩信系统的组成结构以及彩信收发的具体流程和技术细节。随着移动通信技术的不断进步和发展,彩信作为一种重要的...

    中移动彩信协议MM1-MM8

    中国移动的彩信协议,全称为Multimedia Messaging Service (MMS),是一种允许用户发送和接收多媒体内容,如图片、音频和视频片段,通过手机网络的技术。彩信协议是短信服务(SMS)的扩展,旨在提供更丰富的通信体验...

    彩信业务基础知识 结构 协议 流程

    彩信业务是一种基于MMS(Multimedia Messaging Service)技术的通信方式,它允许用户发送和接收包含文本、图片、音频、视频等多种媒体类型的富媒体消息。下面将详细介绍彩信业务的基础知识,包括MMSC结构、系统接口...

    Android短彩信收发流程(Framework)

    Android 短彩信收发流程(Framework) Android 短彩信收发流程(Framework)是 Android 操作系统中处理短信收发的核心机制。该流程主要涉及到 SmsManager、Isms、IccSmsInterfaceManager、SMSDispatcher、...

    彩信的编码解码

    在IT行业中,彩信(Multimedia Messaging Service,MMS)是一种允许用户发送和接收多媒体内容,如图片、音频和视频片段的通信技术。相对于传统的文本短信(SMS),彩信提供了更丰富的信息传递方式。本文将深入探讨...

    MM7协议彩信网关

    1 彩信下行类业务流程 1. 用特定的编辑软件,如索爱提供的MMS Composer 制作出相应的彩信内容, 彩信内容包括彩信所需要的图片,铃声,文本信息,以及彩信的解释文件smil 文件; 2. 将制作好的彩信...

    史上最全的彩信收发流程分析方法(超详细).zip

    一、彩信接收分析. 1.1彩信(1.0)接收信令流程分析 1.1.1 信令过程异常分析 1.1.2 成功率分析 1.1.3 彩信接收失败原因分析 1.1.3.1 timeout 失败原因分析 1.1.3.2 abort 失败原因分析 1.1.3.3 disconnect ...

Global site tag (gtag.js) - Google Analytics