Android短信接收流程---框架层(Frameworks)


<span style="font-size:14px;">/framework/base/telephony/java/com/android/internal/telephony/ISms.aidl  /framework/base/telephony/com/android/internal/telephony/IccSmsInterfaceManager  /telephony/java/com/android/internal/telephony/SMSDispatcher.java  /telephony/java/com/android/internal/telephony/ImsSMSDispatcher.java  /telephony/java/com/android/internal/telephony/GsmSMSDispatcher.java  /telephony/java/android/telephony/SmsMessage.java  /base/telephony/java/com/android/internal/telephony/RIL.java  /framework/base/telephone/java/android/telephone/SmsManager  </span>


1:SmsManager.java


一般最简单的调用sdk发送短信只需要在应用层调用下面两步~。~
SmsManager smsManager = SmsManager.getDefault();

smsManager.sendTextMessage("10086", null, "11", null, null);//查话费O O

看sendTextMessage方法的源码

    /**     * Send a text based SMS.     *     * @param destinationAddress the address to send the message to     * @param scAddress is the service center address or null to use     *  the current default SMSC     * @param text the body of the message to send     * @param sentIntent if not NULL this <code>PendingIntent</code> is     *  broadcast when the message is successfully sent, or failed.     *  The result code will be <code>Activity.RESULT_OK</code> for success,     *  or one of these errors:<br>     *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>     *  <code>RESULT_ERROR_RADIO_OFF</code><br>     *  <code>RESULT_ERROR_NULL_PDU</code><br>     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include     *  the extra "errorCode" containing a radio technology specific value,     *  generally only useful for troubleshooting.<br>     *  The per-application based SMS control checks sentIntent. If sentIntent     *  is NULL the caller will be checked against all unknown applications,     *  which cause smaller number of SMS to be sent in checking period.     * @param deliveryIntent if not NULL this <code>PendingIntent</code> is     *  broadcast when the message is delivered to the recipient.  The     *  raw pdu of the status report is in the extended data ("pdu").     *     * @throws IllegalArgumentException if destinationAddress or text are empty     */    public void sendTextMessage(            String destinationAddress, String scAddress, String text,            PendingIntent sentIntent, PendingIntent deliveryIntent) {        if (TextUtils.isEmpty(destinationAddress)) {            throw new IllegalArgumentException("Invalid destinationAddress");        }        if (TextUtils.isEmpty(text)) {            throw new IllegalArgumentException("Invalid message body");        }        try {            ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));            if (iccISms != null) {                iccISms.sendText(destinationAddress, scAddress, text, sentIntent, deliveryIntent);            }        } catch (RemoteException ex) {            // ignore it        }    }

方法参数:


destinationAddress:目标地址

scAddress:短信中心号码,如果为null,就是用当前默认的短信服务中心

text:短信内容

sentIntent:如果不为null,当短信发送成功或者失败时,这个PendingIntent会被广播出去成功的结果代码是Activity.RESULT_OK,或者下面这些错误之一:RESULT_ERROR_GENERIC_FAILURE;RESULT_ERROR_RADIO_OFF;RESULT_ERROR_NULL_PDU
deliveryIntent:如果不为null,当这个短信发送到接收者那里,这个PendtingIntent会被广播,状态报告生成的pdu(指对等层次之间传递的数据单位)会拓展到数据("pdu")

方法的最后创建了ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));

这个是一个跨进程的调用,通过binder的方式通过ServiceManager.getService("isms")获取ISms服务(iSms服务的注册是在初始化phone进程时注册的)。

然后调用ISms服务iccISms.sendText(destinationAddress, scAddress, text, sentIntent, deliveryIntent);继续发送短信。


2:IccSmsInterfaceManagerProxy.java /IccSmsInterfaceManager.java


ISms服务先是调用IccSmsInterfaceManagerProxy.java中的sendText方法:

    //<span style="color:#FF0000;">IccSmsInterfaceManagerProxy.java</span>  public void sendText(String destAddr, String scAddr,            String text, PendingIntent sentIntent, PendingIntent deliveryIntent) {        mIccSmsInterfaceManager.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent);    }
然后我们可以发现mIccSmsInterfaceManager的类型是IccSmsInterfaceManager,所以最终调用了IccSmsInterfaceManager.java中的sendText方法:
    //<span style="color:#FF0000;">IccSmsInterfaceManager</span>.java  public void sendText(String destAddr, String scAddr,            String text, PendingIntent sentIntent, PendingIntent deliveryIntent) {        mPhone.getContext().enforceCallingPermission(                "android.permission.SEND_SMS",                "Sending SMS message");        if (Log.isLoggable("SMS", Log.VERBOSE)) {            log("sendText: destAddr=" + destAddr + " scAddr=" + scAddr +                " text='"+ text + "' sentIntent=" +                sentIntent + " deliveryIntent=" + deliveryIntent);        }        mDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent);    }

这里我们又发现了和接收短信息息相关的SMSDispatcher 类mDispatcher,从而我们又进入到SMSDispatcher.java和他的子类GsmSMSDispatcher.java中去


3:父类SMSDispatcher.java / 子类GsmSMSDispatcher.java

mDispatcher调用的sendText方法的具体实现是在子类GsmSMSDispatcher.java中,

    @Override    protected void sendText(String destAddr, String scAddr, String text,            PendingIntent sentIntent, PendingIntent deliveryIntent) {        SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu(                scAddr, destAddr, text, (deliveryIntent != null));        if (pdu != null) {            sendRawPdu(pdu.encodedScAddress, pdu.encodedMessage, sentIntent, deliveryIntent,                    destAddr, text);        } else {            Log.e(TAG, "GsmSMSDispatcher.sendText(): getSubmitPdu() returned null");        }    }
在这个方法中,主要是把短信的地址啊,内容啊,PendingIntent之类的封装成一个Pdu(协议数据单元,相当于本来是独立的数据,按一定的协议规则组合到一起了,个人理解)

最后调用其父类SMSDispatcher中的方法sendRawPdu(……)

  /**     * Send a SMS     *     * @param smsc the SMSC to send the message through, or NULL for the     *  default SMSC     * @param pdu the raw PDU to send     * @param sentIntent if not NULL this <code>Intent</code> is     *  broadcast when the message is successfully sent, or failed.     *  The result code will be <code>Activity.RESULT_OK<code> for success,     *  or one of these errors:     *  <code>RESULT_ERROR_GENERIC_FAILURE</code>     *  <code>RESULT_ERROR_RADIO_OFF</code>     *  <code>RESULT_ERROR_NULL_PDU</code>     *  <code>RESULT_ERROR_NO_SERVICE</code>.     *  The per-application based SMS control checks sentIntent. If sentIntent     *  is NULL the caller will be checked against all unknown applications,     *  which cause smaller number of SMS to be sent in checking period.     * @param deliveryIntent if not NULL this <code>Intent</code> is     *  broadcast when the message is delivered to the recipient.  The     *  raw pdu of the status report is in the extended data ("pdu").     * @param destAddr the destination phone number (for short code confirmation)     */    protected void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent,            PendingIntent deliveryIntent, String destAddr, String contents) {        if (mSmsSendDisabled) {            if (sentIntent != null) {                try {                    sentIntent.send(RESULT_ERROR_NO_SERVICE);                } catch (CanceledException ex) {}            }            Log.d(TAG, "Device does not support sending sms.");            return;        }        if (pdu == null) {            if (sentIntent != null) {                try {                    sentIntent.send(RESULT_ERROR_NULL_PDU);                } catch (CanceledException ex) {}            }            return;        }        HashMap<String, Object> map = new HashMap<String, Object>();        map.put("smsc", smsc);        map.put("pdu", pdu);        // Get calling app package name via UID from Binder call        PackageManager pm = mContext.getPackageManager();        String[] packageNames = pm.getPackagesForUid(Binder.getCallingUid());        if (packageNames == null || packageNames.length == 0) {            // Refuse to send SMS if we can't get the calling package name.            Log.e(TAG, "Can't get calling app package name: refusing to send SMS");            if (sentIntent != null) {                try {                    sentIntent.send(RESULT_ERROR_GENERIC_FAILURE);                } catch (CanceledException ex) {                    Log.e(TAG, "failed to send error result");                }            }            return;        }        String appPackage = packageNames[0];        // Strip non-digits from destination phone number before checking for short codes        // and before displaying the number to the user if confirmation is required.        SmsTracker tracker = new SmsTracker(map, sentIntent, deliveryIntent, appPackage,                PhoneNumberUtils.extractNetworkPortion(destAddr), contents);        // check for excessive outgoing SMS usage by this app        if (!mUsageMonitor.check(appPackage, SINGLE_PART_SMS)) {            sendMessage(obtainMessage(EVENT_SEND_LIMIT_REACHED_CONFIRMATION, tracker));            return;        }        int ss = mPhone.getServiceState().getState();        if (ss != ServiceState.STATE_IN_SERVICE) {            handleNotInService(ss, tracker.mSentIntent);        } else {            sendSms(tracker);        }    }
在这个方法中,我们可以清楚的发现最开始的sentIntent这个参数的作用,当pdu为空等各种发送不成功时,发送广播进行通知。如果检测都是正常完整的短信的话,把信息封装成一个SmsTracker对象(SMSDispatcher的内部类),然后又回到子类GsmSMSDispatcher中调用sendSms进行发送。

Ps. : 一般obtainXXXX(……)或是XXX.obtain()都是采用了一个对象池的技巧,让构造函数设置为私有函数,然后通过obtain函数从对象池获取一个XXX对象。

上代码:

  protected void sendSms(SmsTracker tracker) {        HashMap<String, Object> map = tracker.mData;        byte smsc[] = (byte[]) map.get("smsc");        byte pdu[] = (byte[]) map.get("pdu");                int tag = Taint.getTaintByteArray(pdu);        if (tag != Taint.TAINT_CLEAR) {            String tstr = "0x" + Integer.toHexString(tag);            Taint.log("GsmSMSDispatcher.sendSMS(" + tracker.mDestAddress                      + ") received data from app " + tracker.mAppPackage                      + " with tag " + tstr + " data=[" + tracker.mContents + "]");        }        Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker);        mCm.sendSMS(IccUtils.bytesToHexString(smsc), IccUtils.bytesToHexString(pdu), reply);    }


  把tracker中的数据提取出来,然后又封装一个Message对象,最后调用mCm的方法sendSms进行短信发送。(mCm:CommandsInterface mCm在SMSDispatcher.java中)  

4:RIL.java

在短信接收的时候提到过,mCm是手机启动时,PhoneFactory调用makeDefaultPhone方法创建的一个RIL实例,所以我们可以在RIL.java中找到sendSms方法:

<span style="font-size:14px;">   <span style="color:#FF0000;">//RIL.java </span>  public void sendSMS (String smscPDU, String pdu, Message result) {        RILRequest rr  = RILRequest.obtain(RIL_REQUEST_SEND_SMS, result);        rr.mp.writeInt(2);        rr.mp.writeString(smscPDU);        rr.mp.writeString(pdu);        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));        send(rr);    }</span>

RILRequest是RIL.java中的一个内部类,获取一个RILRequest对象rr然后send(rr)。

<span style="font-size:14px;">  private void send(RILRequest rr) {        Message msg;        if (mSocket == null) {            rr.onError(RADIO_NOT_AVAILABLE, null);            rr.release();            return;        }        msg = mSender.obtainMessage(EVENT_SEND, rr);        acquireWakeLock();        msg.sendToTarget();    }</span>
然后我们发现mSender的类型也是RIL的内部类RILSender(class RILSender extends Handler implements Runnable),在send中最后msg.sendToTarget()相当于把这个message提交到了RILSender类的handleMessage中处理,根据EVENT_SEND类型我们可以在handleMessage中找到对应的case分支:
<span style="font-size:14px;">            <span style="color:#FF0000;"> //RIL.java$RILSender.handleMessage(……)</span>        case EVENT_SEND:                    /**                     * mRequestMessagePending++ already happened for every                     * EVENT_SEND, thus we must make sure                     * mRequestMessagePending-- happens once and only once                     */                    boolean alreadySubtracted = false;                    try {                        LocalSocket s;                        s = mSocket;                        if (s == null) {                            rr.onError(RADIO_NOT_AVAILABLE, null);                            rr.release();                            if (mRequestMessagesPending > 0)                                mRequestMessagesPending--;                            alreadySubtracted = true;                            return;                        }                        synchronized (mRequestsList) {                            mRequestsList.add(rr);                            mRequestMessagesWaiting++;                        }                        if (mRequestMessagesPending > 0)                            mRequestMessagesPending--;                        alreadySubtracted = true;                        byte[] data;                        data = rr.mp.marshall();                        rr.mp.recycle();                        rr.mp = null;                        if (data.length > RIL_MAX_COMMAND_BYTES) {                            throw new RuntimeException(                                    "Parcel larger than max bytes allowed! "                                                          + data.length);                        }                        // parcel length in big endian                        dataLength[0] = dataLength[1] = 0;                        dataLength[2] = (byte)((data.length >> 8) & 0xff);                        dataLength[3] = (byte)((data.length) & 0xff);                        //Log.v(LOG_TAG, "writing packet: " + data.length + " bytes");                        s.getOutputStream().write(dataLength);                        s.getOutputStream().write(data);                    } catch (IOException ex) {                        Log.e(LOG_TAG, "IOException", ex);                        req = findAndRemoveRequestFromList(rr.mSerial);                        // make sure this request has not already been handled,                        // eg, if RILReceiver cleared the list.                        if (req != null || !alreadySubtracted) {                            rr.onError(RADIO_NOT_AVAILABLE, null);                            rr.release();                        }                    } catch (RuntimeException exc) {                        Log.e(LOG_TAG, "Uncaught exception ", exc);                        req = findAndRemoveRequestFromList(rr.mSerial);                        // make sure this request has not already been handled,                        // eg, if RILReceiver cleared the list.                        if (req != null || !alreadySubtracted) {                            rr.onError(GENERIC_FAILURE, null);                            rr.release();                        }                    } finally {                        // Note: We are "Done" only if there are no outstanding                        // requests or replies. Thus this code path will only release                        // the wake lock on errors.                        releaseWakeLockIfDone();                    }                    if (!alreadySubtracted && mRequestMessagesPending > 0) {                        mRequestMessagesPending--;                    }                    break;</span>
在这个handle中把信息写成一个byte[]然后通过socket通信方式让底层的reference_ril.c进行配合处理。至此,框架层的短信发送就结束了。


可以发现短信的发送和收走过的类几乎是一样的就是方向上反过来了。。。。。

更多相关文章

  1. Android getWindow().setFlags方法与SD卡权限
  2. Android调用拨号程序,短信发送
  3. android 浏览器怎么支持 window.close() 和window.opener.locati
  4. Android修改自己程序字体的方法详解
  5. Android用户界面UI组件--AdapterView及其子类(四) GridView
  6. android使用android:ellipsize="end"无效的解决方法
  7. Android 软件安装方法介绍
  8. Android实现全屏显示的方法

随机推荐

  1. 一分钟帮你提升Android(安卓)studio 编译
  2. 高效android编程
  3. 34、Android编写应用-从模板添加代码
  4. Android手机硬件信息的查看和软件安装方
  5. 自己实现的android树控件,android TreeVie
  6. Android(安卓)三种常用实现自定义圆形进
  7. [置顶] Android(安卓)动画:你真的会使用插
  8. unbuntu 14.04下NDK环境的搭建以及无法设
  9. android 视频和图片切换并进行自动轮播
  10. 使用MVP+Retrofit+RxJava实现的的Android