前言:最近需要做 iot 上的相关需求,设计到短信 app,本文梳理了 Framework 层的大致流程。

短信发送包括发送一般的短信、彩信. 发送的请求从 app 层通过 SmsManager 对象的 sendMultipartTextMessage 方法调用,传递到了 Telephony Framework 层中,Telephony Framework 层与 RIL 层交互,最终完成短信的发送请求,转换成 RIL 请求,其处理流程如下所示:

本文基于 9.0 的源码,梳理的流程。按照以上流程图,找出对应关键位置的源码,方便梳理整个短信发送在 Framework 层的整个流程。

SmsManager

//SmsManager
public void sendTextMessage(
        String destinationAddress, String scAddress, String text,
        PendingIntent sentIntent, PendingIntent deliveryIntent,
        int priority, boolean expectMore, int validityPeriod) {
    sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent,
            true /* persistMessage*/, priority, expectMore, validityPeriod);
}

private void sendTextMessageInternal(
String destinationAddress, String scAddress, String text,
PendingIntent sentIntent, PendingIntent deliveryIntent, boolean persistMessage,
int priority, boolean expectMore, int validityPeriod)
{
if (TextUtils.isEmpty(destinationAddress)) {
throw new IllegalArgumentException(“Invalid destinationAddress”);
}

<span class="hljs-keyword">if</span> (TextUtils.isEmpty(text)) {
    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> IllegalArgumentException(<span class="hljs-string">"Invalid message body"</span>);
}

<span class="hljs-keyword">if</span> (priority &lt; <span class="hljs-number">0x00</span> || priority &gt; <span class="hljs-number">0x03</span>) {
    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> IllegalArgumentException(<span class="hljs-string">"Invalid priority"</span>);
}

<span class="hljs-keyword">if</span> (validityPeriod &lt; <span class="hljs-number">0x05</span> || validityPeriod &gt; <span class="hljs-number">0x09b0a0</span>) {
    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> IllegalArgumentException(<span class="hljs-string">"Invalid validity period"</span>);
}

<span class="hljs-keyword">try</span> {
    <span class="hljs-comment">//AIDL 调用</span>
     ISms iccISms = getISmsServiceOrThrow();
    <span class="hljs-keyword">if</span> (iccISms != <span class="hljs-keyword">null</span>) {
        <span class="hljs-comment">// 搜索sendTextForSubscriberWithOptions,在UiccSmsController </span>
        iccISms.sendTextForSubscriberWithOptions(getSubscriptionId(),
                ActivityThread.currentPackageName(), destinationAddress, scAddress, text,
                sentIntent, deliveryIntent, persistMessage,  priority, expectMore,
                validityPeriod);
    }
} <span class="hljs-keyword">catch</span> (RemoteException ex) {
    <span class="hljs-comment">// ignore it</span>
}

}

复制代码

UiccSmsController

//com.android.internal.telephony.UiccSmsController
@Override
    public void sendTextForSubscriberWithOptions(int subId, String callingPackage,
            String destAddr, String scAddr, String parts, PendingIntent sentIntents,
            PendingIntent deliveryIntents, boolean persistMessage, int priority,
            boolean expectMore, int validityPeriod) {
        IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId);
        if (iccSmsIntMgr != null ) {
            // 调用 IccSmsInterfaceManager 的 sendTextWithOptions 方法
      iccSmsIntMgr.sendTextWithOptions(callingPackage, destAddr, scAddr, parts, sentIntents,deliveryIntents, persistMessage,  priority, expectMore, validityPeriod);
        } else {
            Rlog.e(LOG_TAG,"sendTextWithOptions iccSmsIntMgr is null for" +
                          "Subscription:" + subId);
        }
    }
复制代码

IccSmsInterfaceManager

//IccSmsInterfaceManager
public void sendMultipartText(String callingPackage, String destAddr, String scAddr,
            List<String> parts, List<PendingIntent> sentIntents,
            List<PendingIntent> deliveryIntents, boolean persistMessageForNonDefaultSmsApp) {
        sendMultipartTextWithOptions(callingPackage, destAddr, scAddr, parts, sentIntents,
                deliveryIntents, persistMessageForNonDefaultSmsApp,
                SMS_MESSAGE_PRIORITY_NOT_SPECIFIED, false /* expectMore */,
                SMS_MESSAGE_PERIOD_NOT_SPECIFIED);
    }

// 转移到 mDispatchersController
public void sendMultipartTextWithOptions(String callingPackage, String destAddr,
String scAddr, List<String> parts, List<PendingIntent> sentIntents,
List<PendingIntent> deliveryIntents, boolean persistMessageForNonDefaultSmsApp,
int priority, boolean expectMore, int validityPeriod)
{
if (!checkCallingSendTextPermissions(
persistMessageForNonDefaultSmsApp, callingPackage, “Sending SMS message”)) {
return;
}
if (Rlog.isLoggable(“SMS”, Log.VERBOSE)) {
int i = 0;
for (String part : parts) {
log(“sendMultipartTextWithOptions: destAddr=” + destAddr + “, srAddr=” + scAddr +“, part[“ + (i++) + ”]=” + part);
}
}

    destAddr = filterDestAddress(destAddr);

    <span class="hljs-keyword">if</span> (parts.size() &gt; <span class="hljs-number">1</span> &amp;&amp; parts.size() &lt; <span class="hljs-number">10</span> &amp;&amp; !SmsMessage.hasEmsSupport()) {
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; parts.size(); i++) {
            <span class="hljs-comment">// If EMS is not supported, we have to break down EMS into single segment SMS</span>
            <span class="hljs-comment">// and add page info " x/y".</span>
            String singlePart = parts.get(i);
            <span class="hljs-keyword">if</span> (SmsMessage.shouldAppendPageNumberAsPrefix()) {
                singlePart = String.valueOf(i + <span class="hljs-number">1</span>) + <span class="hljs-string">'/'</span> + parts.size() + <span class="hljs-string">' '</span> + singlePart;
            } <span class="hljs-keyword">else</span> {
                singlePart = singlePart.concat(<span class="hljs-string">' '</span> + String.valueOf(i + <span class="hljs-number">1</span>) + <span class="hljs-string">'/'</span> + parts.size());
            }

            PendingIntent singleSentIntent = <span class="hljs-keyword">null</span>;
            <span class="hljs-keyword">if</span> (sentIntents != <span class="hljs-keyword">null</span> &amp;&amp; sentIntents.size() &gt; i) {
                singleSentIntent = sentIntents.get(i);
            }

            PendingIntent singleDeliveryIntent = <span class="hljs-keyword">null</span>;
            <span class="hljs-keyword">if</span> (deliveryIntents != <span class="hljs-keyword">null</span> &amp;&amp; deliveryIntents.size() &gt; i) {
                singleDeliveryIntent = deliveryIntents.get(i);
            }

            mDispatchersController.sendText(destAddr, scAddr, singlePart,
                    singleSentIntent, singleDeliveryIntent,
                    <span class="hljs-keyword">null</span><span class="hljs-comment">/*messageUri*/</span>, callingPackage,
                    persistMessageForNonDefaultSmsApp,
                    priority, expectMore, validityPeriod);
        }
        <span class="hljs-keyword">return</span>;
    }

	<span class="hljs-comment">//转移到 mDispatchersController</span>
    mDispatchersController.sendMultipartText(destAddr,
                                  scAddr,
                                  (ArrayList&lt;String&gt;) parts,
                                  (ArrayList&lt;PendingIntent&gt;) sentIntents,
                                  (ArrayList&lt;PendingIntent&gt;) deliveryIntents,
                                  <span class="hljs-keyword">null</span>, callingPackage, persistMessageForNonDefaultSmsApp,
                                  priority, expectMore, validityPeriod);
}
复制代码

SMSDispatcher

转到 SmsDispatchersController,分别调用 sendData、sendText、sendMultipartText

protected void sendMultipartText(String destAddr, String scAddr,
            ArrayList<String> parts, ArrayList<PendingIntent> sentIntents,
            ArrayList<PendingIntent> deliveryIntents, Uri messageUri, String callingPkg,
            boolean persistMessage, int priority, boolean expectMore, int validityPeriod) {
        if (mImsSmsDispatcher.isAvailable()) {
            mImsSmsDispatcher.sendMultipartText(destAddr, scAddr, parts, sentIntents,
                    deliveryIntents, messageUri, callingPkg, persistMessage,
                    SMS_MESSAGE_PRIORITY_NOT_SPECIFIED,
                    false /*expectMore*/, SMS_MESSAGE_PERIOD_NOT_SPECIFIED);
        } else {
            if (isCdmaMo()) {
                mCdmaDispatcher.sendMultipartText(destAddr, scAddr, parts, sentIntents,
                        deliveryIntents, messageUri, callingPkg, persistMessage, priority,
                        expectMore, validityPeriod);
            } else {
                mGsmDispatcher.sendMultipartText(destAddr, scAddr, parts, sentIntents,
                        deliveryIntents, messageUri, callingPkg, persistMessage, priority,
                        expectMore, validityPeriod);
            }
        }
    }
复制代码

SMSDispatcher

protected void sendData(String destAddr, String scAddr, int destPort,
            byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) {
        SmsMessageBase.SubmitPduBase pdu = getSubmitPdu(
                scAddr, destAddr, destPort, data, (deliveryIntent != null));
        if (pdu != null) {
            HashMap map = getSmsTrackerMap(destAddr, scAddr, destPort, data, pdu);
            SmsTracker tracker = getSmsTracker(map, sentIntent, deliveryIntent, getFormat(),
                    null /*messageUri*/, false /*expectMore*/,
                    null /*fullMessageText*/, false /*isText*/,
                    true /*persistMessage*/);
        <span class="hljs-keyword">if</span> (!sendSmsByCarrierApp(<span class="hljs-keyword">true</span> <span class="hljs-comment">/* isDataSms */</span>, tracker)) {
            sendSubmitPdu(tracker);
        }
    } <span class="hljs-keyword">else</span> {
        Rlog.e(TAG, <span class="hljs-string">"SMSDispatcher.sendData(): getSubmitPdu() returned null"</span>);
        triggerSentIntentForFailure(sentIntent);
    }
}

protected void sendMultipartText(String destAddr, String scAddr,
ArrayList<String> parts, ArrayList<PendingIntent> sentIntents,
ArrayList<PendingIntent> deliveryIntents, Uri messageUri, String callingPkg,
boolean persistMessage, int priority, boolean expectMore, int validityPeriod)
{
final String fullMessageText = getMultipartMessageText(parts);
int refNumber = getNextConcatenatedRef() & 0x00FF;
int msgCount = parts.size();
int encoding = SmsConstants.ENCODING_UNKNOWN;

    TextEncodingDetails[] encodingForParts = <span class="hljs-keyword">new</span> TextEncodingDetails[msgCount];
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; msgCount; i++) {
        TextEncodingDetails details = calculateLength(parts.get(i), <span class="hljs-keyword">false</span>);
        <span class="hljs-keyword">if</span> (encoding != details.codeUnitSize
                &amp;&amp; (encoding == SmsConstants.ENCODING_UNKNOWN
                        || encoding == SmsConstants.ENCODING_7BIT)) {
            encoding = details.codeUnitSize;
        }
        encodingForParts[i] = details;
    }

    SmsTracker[] trackers = <span class="hljs-keyword">new</span> SmsTracker[msgCount];

    <span class="hljs-comment">// States to track at the message level (for all parts)</span>
    <span class="hljs-keyword">final</span> AtomicInteger unsentPartCount = <span class="hljs-keyword">new</span> AtomicInteger(msgCount);
    <span class="hljs-keyword">final</span> AtomicBoolean anyPartFailed = <span class="hljs-keyword">new</span> AtomicBoolean(<span class="hljs-keyword">false</span>);

    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; msgCount; i++) {
        SmsHeader.ConcatRef concatRef = <span class="hljs-keyword">new</span> SmsHeader.ConcatRef();
        concatRef.refNumber = refNumber;
        concatRef.seqNumber = i + <span class="hljs-number">1</span>;  <span class="hljs-comment">// 1-based sequence</span>
        concatRef.msgCount = msgCount;
        <span class="hljs-comment">// <span class="hljs-doctag">TODO:</span> We currently set this to true since our messaging app will never</span>
        <span class="hljs-comment">// send more than 255 parts (it converts the message to MMS well before that).</span>
        <span class="hljs-comment">// However, we should support 3rd party messaging apps that might need 16-bit</span>
        <span class="hljs-comment">// references</span>
        <span class="hljs-comment">// Note:  It's not sufficient to just flip this bit to true; it will have</span>
        <span class="hljs-comment">// ripple effects (several calculations assume 8-bit ref).</span>
        concatRef.isEightBits = <span class="hljs-keyword">true</span>;
        SmsHeader smsHeader = <span class="hljs-keyword">new</span> SmsHeader();
        smsHeader.concatRef = concatRef;

        <span class="hljs-comment">// Set the national language tables for 3GPP 7-bit encoding, if enabled.</span>
        <span class="hljs-keyword">if</span> (encoding == SmsConstants.ENCODING_7BIT) {
            smsHeader.languageTable = encodingForParts[i].languageTable;
            smsHeader.languageShiftTable = encodingForParts[i].languageShiftTable;
        }

        PendingIntent sentIntent = <span class="hljs-keyword">null</span>;
        <span class="hljs-keyword">if</span> (sentIntents != <span class="hljs-keyword">null</span> &amp;&amp; sentIntents.size() &gt; i) {
            sentIntent = sentIntents.get(i);
        }

        PendingIntent deliveryIntent = <span class="hljs-keyword">null</span>;
        <span class="hljs-keyword">if</span> (deliveryIntents != <span class="hljs-keyword">null</span> &amp;&amp; deliveryIntents.size() &gt; i) {
            deliveryIntent = deliveryIntents.get(i);
        }

        trackers[i] =
            getNewSubmitPduTracker(destAddr, scAddr, parts.get(i), smsHeader, encoding,
                    sentIntent, deliveryIntent, (i == (msgCount - <span class="hljs-number">1</span>)),
                    unsentPartCount, anyPartFailed, messageUri,
                    fullMessageText, priority, expectMore, validityPeriod);
        trackers[i].mPersistMessage = persistMessage;
    }

    <span class="hljs-keyword">if</span> (parts == <span class="hljs-keyword">null</span> || trackers == <span class="hljs-keyword">null</span> || trackers.length == <span class="hljs-number">0</span>
            || trackers[<span class="hljs-number">0</span>] == <span class="hljs-keyword">null</span>) {
        Rlog.e(TAG, <span class="hljs-string">"Cannot send multipart text. parts="</span> + parts + <span class="hljs-string">" trackers="</span> + trackers);
        <span class="hljs-keyword">return</span>;
    }

    String carrierPackage = getCarrierAppPackageName();
    <span class="hljs-keyword">if</span> (carrierPackage != <span class="hljs-keyword">null</span>) {
        Rlog.d(TAG, <span class="hljs-string">"Found carrier package."</span>);
        MultipartSmsSender smsSender = <span class="hljs-keyword">new</span> MultipartSmsSender(parts, trackers);
        smsSender.sendSmsByCarrierApp(carrierPackage,
                <span class="hljs-keyword">new</span> MultipartSmsSenderCallback(smsSender));
    } <span class="hljs-keyword">else</span> {
        Rlog.v(TAG, <span class="hljs-string">"No carrier package."</span>);
        <span class="hljs-keyword">for</span> (SmsTracker tracker : trackers) {
            <span class="hljs-keyword">if</span> (tracker != <span class="hljs-keyword">null</span>) {
                sendSubmitPdu(tracker);
            } <span class="hljs-keyword">else</span> {
                Rlog.e(TAG, <span class="hljs-string">"Null tracker."</span>);
            }
        }
    }
}
复制代码

都调用 sendSubmitPdu(tracker);

private void sendSubmitPdu(SmsTracker tracker) {
        if (shouldBlockSmsForEcbm()) {
            Rlog.d(TAG, "Block SMS in Emergency Callback mode");
            tracker.onFailed(mContext, SmsManager.RESULT_ERROR_NO_SERVICE, 0/*errorCode*/);
        } else {
            sendRawPdu(tracker);
        }
    }

// sendRawPdu
@VisibleForTesting
public void sendRawPdu(SmsTracker tracker) {
HashMap map = tracker.getData();
byte pdu[] = (byte[]) map.get(MAP_KEY_PDU);

    <span class="hljs-keyword">if</span> (mSmsSendDisabled) {
        Rlog.e(TAG, <span class="hljs-string">"Device does not support sending sms."</span>);
        tracker.onFailed(mContext, RESULT_ERROR_NO_SERVICE, <span class="hljs-number">0</span><span class="hljs-comment">/*errorCode*/</span>);
        <span class="hljs-keyword">return</span>;
    }

    <span class="hljs-keyword">if</span> (pdu == <span class="hljs-keyword">null</span>) {
        Rlog.e(TAG, <span class="hljs-string">"Empty PDU"</span>);
        tracker.onFailed(mContext, RESULT_ERROR_NULL_PDU, <span class="hljs-number">0</span><span class="hljs-comment">/*errorCode*/</span>);
        <span class="hljs-keyword">return</span>;
    }

    <span class="hljs-comment">// Get calling app package name via UID from Binder call</span>
    PackageManager pm = mContext.getPackageManager();
    String[] packageNames = pm.getPackagesForUid(Binder.getCallingUid());

    <span class="hljs-keyword">if</span> (packageNames == <span class="hljs-keyword">null</span> || packageNames.length == <span class="hljs-number">0</span>) {
        <span class="hljs-comment">// Refuse to send SMS if we can't get the calling package name.</span>
        Rlog.e(TAG, <span class="hljs-string">"Can't get calling app package name: refusing to send SMS"</span>);
        tracker.onFailed(mContext, RESULT_ERROR_GENERIC_FAILURE, <span class="hljs-number">0</span><span class="hljs-comment">/*errorCode*/</span>);
        <span class="hljs-keyword">return</span>;
    }

    <span class="hljs-comment">// Get package info via packagemanager</span>
    PackageInfo appInfo;
    <span class="hljs-keyword">try</span> {
        <span class="hljs-comment">// XXX this is lossy- apps can share a UID</span>
        appInfo = pm.getPackageInfoAsUser(
                packageNames[<span class="hljs-number">0</span>], PackageManager.GET_SIGNATURES, tracker.mUserId);
    } <span class="hljs-keyword">catch</span> (PackageManager.NameNotFoundException e) {
        Rlog.e(TAG, <span class="hljs-string">"Can't get calling app package info: refusing to send SMS"</span>);
        tracker.onFailed(mContext, RESULT_ERROR_GENERIC_FAILURE, <span class="hljs-number">0</span><span class="hljs-comment">/*errorCode*/</span>);
        <span class="hljs-keyword">return</span>;
    }

    <span class="hljs-comment">// checkDestination() returns true if the destination is not a premium short code or the</span>
    <span class="hljs-comment">// sending app is approved to send to short codes. Otherwise, a message is sent to our</span>
    <span class="hljs-comment">// handler with the SmsTracker to request user confirmation before sending.</span>
    <span class="hljs-keyword">if</span> (checkDestination(tracker)) {
        <span class="hljs-comment">// check for excessive outgoing SMS usage by this app</span>
        <span class="hljs-keyword">if</span> (!mSmsDispatchersController.getUsageMonitor().check(
                appInfo.packageName, SINGLE_PART_SMS)) {
            sendMessage(obtainMessage(EVENT_SEND_LIMIT_REACHED_CONFIRMATION, tracker));
            <span class="hljs-keyword">return</span>;
        }
		<span class="hljs-comment">//抽象方法:</span>
        sendSms(tracker);
    }

    <span class="hljs-keyword">if</span> (PhoneNumberUtils.isLocalEmergencyNumber(mContext, tracker.mDestAddress)) {
        <span class="hljs-keyword">new</span> AsyncEmergencyContactNotifier(mContext).execute();
    }
}

// 子类实现
/**
* Send the message along to the radio.
*
* @param tracker holds the SMS message to send
*/

protected abstract void sendSms(SmsTracker tracker);

复制代码

SMSDispatcher 的子类 GsmSMSDispatcher、CdmaSMSDispatcher

/** {@inheritDoc} */
    @Override
    public void sendSms(SmsTracker tracker) {
        Rlog.d(TAG, "sendSms:"
                + "isIms()=" + isIms()
                + "mRetryCount=" + tracker.mRetryCount
                + "mImsRetry=" + tracker.mImsRetry
                + "mMessageRef=" + tracker.mMessageRef
                + "mUsesImsServiceForIms=" + tracker.mUsesImsServiceForIms
                + "SS=" + mPhone.getServiceState().getState());
    <span class="hljs-keyword">int</span> ss = mPhone.getServiceState().getState();
    <span class="hljs-comment">// if sms over IMS is not supported on data and voice is not available...</span>
    <span class="hljs-keyword">if</span> (!isIms() &amp;&amp; ss != ServiceState.STATE_IN_SERVICE) {
        tracker.onFailed(mContext, getNotInServiceError(ss), <span class="hljs-number">0</span><span class="hljs-comment">/*errorCode*/</span>);
        <span class="hljs-keyword">return</span>;
    }

    Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker);
    <span class="hljs-keyword">byte</span>[] pdu = (<span class="hljs-keyword">byte</span>[]) tracker.getData().get(<span class="hljs-string">"pdu"</span>);

    <span class="hljs-keyword">int</span> currentDataNetwork = mPhone.getServiceState().getDataNetworkType();
    <span class="hljs-keyword">boolean</span> imsSmsDisabled = (currentDataNetwork == TelephonyManager.NETWORK_TYPE_EHRPD
                || (ServiceState.isLte(currentDataNetwork)
                &amp;&amp; !mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()))
                &amp;&amp; mPhone.getServiceState().getVoiceNetworkType()
                == TelephonyManager.NETWORK_TYPE_1xRTT
                &amp;&amp; ((GsmCdmaPhone) mPhone).mCT.mState != PhoneConstants.State.IDLE;

    <span class="hljs-comment">// sms over cdma is used:</span>
    <span class="hljs-comment">//   if sms over IMS is not supported AND</span>
    <span class="hljs-comment">//   this is not a retry case after sms over IMS failed</span>
    <span class="hljs-comment">//     indicated by mImsRetry &gt; 0 OR</span>
    <span class="hljs-comment">//   SMS over IMS is disabled because of the network type OR</span>
    <span class="hljs-comment">//   SMS over IMS is being handled by the ImsSmsDispatcher implementation and has indicated</span>
    <span class="hljs-comment">//   that the message should fall back to sending over CS.</span>
    <span class="hljs-keyword">if</span> (<span class="hljs-number">0</span> == tracker.mImsRetry &amp;&amp; !isIms() || imsSmsDisabled || tracker.mUsesImsServiceForIms) {
        mCi.sendCdmaSms(pdu, reply);
    } <span class="hljs-keyword">else</span> {
        mCi.sendImsCdmaSms(pdu, tracker.mImsRetry, tracker.mMessageRef, reply);
        <span class="hljs-comment">// increment it here, so in case of SMS_FAIL_RETRY over IMS</span>
        <span class="hljs-comment">// next retry will be sent using IMS request again.</span>
        tracker.mImsRetry++;
    }
}
复制代码

Phone(CommandsInterface)

SMSDispatcher 类是通过 sendSMS 方法与 RIL 交互的,sendSMS 方法又是由子类 GSMDispatcher 或者 CDMADispatcher 具体实现的。现在分析一下 GSMDispatcher 类中该方法的逻辑实现。

mCi.sendCdmaSms(pdu, reply); 以及 mCi.sendImsCdmaSms(pdu, tracker.mImsRetry, tracker.mMessageRef, reply); 中的 mCi 是 Phone 中的 CommandInterface 接口对象。

PhoneProxy/GSMPhone/CDMAPhone

如果说 RILJ 提供了工具或管道,那么 Phone 接口的子类及 PhoneFactory 则为 packages/app/Phone 这个应用程序进程使用 RILJ 这个工具或管道提供了极大的方便,它们一个管理整个整个手机的 Telephony 功能。

GSMPhone 和 CDMAPhone 实现了 Phone 中定义的接口。接口类 Phone 定义了一套 API,这套 API 用于使用 RILJ(见后述 RIL 类)发送 AT 命令请求,也还有一套 register 和 unregister 函数;当调用者对一些内部状态感兴趣时,可以调用对应的 register 函数,当状态变化时可以得到及时通知。

PhoneBase 实现了 Phone 接口中定义的部分函数,还有一部分由其子类 GSMPhone 和 CDMAPhone 实现。PhoneProxy 是 GSMPhone 和 CDMAPhone 的代理,让使用者不用关注手机到底是 GSM 还是 CDMA,它遵守 Phone 定义的 API 接口,因此继承 Phone。

PhoneFactory 在创建 Phone 对象时,拥有的是 PhoneProxy 对象,PhoneProxy 根据实际的网络类型创建对应的 GSMPhone 或 CDMAPhone。

PhoneFactory 同样拥有 CommandInterface 的接口对象,即 RIL 的实例,该 RIL 实例将被传递给 GSMPhone 或 CDMAPhone,即 GSMPhone 或 CDMAPhone 引用它,实现与 rild 的交互。

//PhoneFactory 中 makeDefaultPhone 创建  Phone 对象,并且创建 Phone 中的 sCommandsInterfaces = new RIL[numPhones], 即对应的 RIL

public static void makeDefaultPhone(Context context) {
….
int[] networkModes = new int[numPhones];
sPhones = new Phone[numPhones];
sCommandsInterfaces = new RIL[numPhones];
sTelephonyNetworkFactories = new TelephonyNetworkFactory[numPhones];

            <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; numPhones; i++) {
                <span class="hljs-comment">// reads the system properties and makes commandsinterface</span>
                <span class="hljs-comment">// Get preferred network type.</span>
                networkModes[i] = RILConstants.PREFERRED_NETWORK_MODE;

                Rlog.i(LOG_TAG, <span class="hljs-string">"Network Mode set to "</span> + Integer.toString(networkModes[i]));
                sCommandsInterfaces[i] = <span class="hljs-keyword">new</span> RIL(context, networkModes[i],
                        cdmaSubscription, i);
            }
            Rlog.i(LOG_TAG, <span class="hljs-string">"Creating SubscriptionController"</span>);
            SubscriptionController.init(context, sCommandsInterfaces);

            <span class="hljs-comment">// Instantiate UiccController so that all other classes can just</span>
            <span class="hljs-comment">// call getInstance()</span>
            sUiccController = UiccController.make(context, sCommandsInterfaces);
....
    
    
     <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; numPhones; i++) {
                Phone phone = <span class="hljs-keyword">null</span>;
                <span class="hljs-keyword">int</span> phoneType = TelephonyManager.getPhoneType(networkModes[i]);
                <span class="hljs-keyword">if</span> (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
                    phone = <span class="hljs-keyword">new</span> GsmCdmaPhone(context,
                            sCommandsInterfaces[i], sPhoneNotifier, i,
                            PhoneConstants.PHONE_TYPE_GSM,
                            TelephonyComponentFactory.getInstance());
                } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
                    <span class="hljs-comment">//把  RIL对象给到phone</span>
                    phone = <span class="hljs-keyword">new</span> GsmCdmaPhone(context,
                            sCommandsInterfaces[i], sPhoneNotifier, i,
                            PhoneConstants.PHONE_TYPE_CDMA_LTE,
                            TelephonyComponentFactory.getInstance());
                }
                Rlog.i(LOG_TAG, <span class="hljs-string">"Creating Phone with type = "</span> + phoneType + <span class="hljs-string">" sub = "</span> + i);

                sPhones[i] = phone;
            }

}

复制代码

RIL

首先查找:package com.android.internal.telephony; 下的 RILConstants, 找到跟 SMS 相关的 Message 常量,

// 请求 
int RIL_REQUEST_CDMA_SEND_SMS = 87;
int RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE = 88;

// 接收
int RIL_UNSOL_RESPONSE_NEW_SMS = 1003;
int RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT = 1004;
int RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM = 1005;

// 在 sim 卡上写、删除 sms
int RIL_REQUEST_WRITE_SMS_TO_SIM = 63;
int RIL_REQUEST_DELETE_SMS_ON_SIM = 64;

// 发送
int RIL_REQUEST_IMS_SEND_SMS = 113;

复制代码

Framework 层:package com.android.internal.telephony; 下的 RIL.java 文件包含两个 class,class RILRequest public final class RIL extends BaseCommands implements CommandsInterface。

switch(response) {
           ....
            case RIL_UNSOL_RESPONSE_NEW_SMS: {
                if (RILJ_LOGD) unsljLog(response);
            <span class="hljs-comment">// FIXME this should move up a layer</span>
            String a[] = <span class="hljs-keyword">new</span> String[<span class="hljs-number">2</span>];

            a[<span class="hljs-number">1</span>] = (String)ret;

            SmsMessage sms;

            sms = SmsMessage.newFromCMT(a);
            <span class="hljs-keyword">if</span> (mGsmSmsRegistrant != <span class="hljs-keyword">null</span>) {
                mGsmSmsRegistrant
                    .notifyRegistrant(<span class="hljs-keyword">new</span> AsyncResult(<span class="hljs-keyword">null</span>, sms, <span class="hljs-keyword">null</span>));
            }
        <span class="hljs-keyword">break</span>;
        }
        <span class="hljs-keyword">case</span> RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT:
            <span class="hljs-keyword">if</span> (RILJ_LOGD) unsljLogRet(response, ret);
            <span class="hljs-keyword">if</span> (mSmsStatusRegistrant != <span class="hljs-keyword">null</span>) {
                mSmsStatusRegistrant.notifyRegistrant(
                        <span class="hljs-keyword">new</span> AsyncResult(<span class="hljs-keyword">null</span>, ret, <span class="hljs-keyword">null</span>));
            }
        <span class="hljs-keyword">break</span>;
        <span class="hljs-keyword">case</span> RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM:
            <span class="hljs-keyword">if</span> (RILJ_LOGD) unsljLogRet(response, ret);

            <span class="hljs-keyword">int</span>[] smsIndex = (<span class="hljs-keyword">int</span>[])ret;

            <span class="hljs-keyword">if</span>(smsIndex.length == <span class="hljs-number">1</span>) {
                <span class="hljs-keyword">if</span> (mSmsOnSimRegistrant != <span class="hljs-keyword">null</span>) {
                    mSmsOnSimRegistrant.
                            notifyRegistrant(<span class="hljs-keyword">new</span> AsyncResult(<span class="hljs-keyword">null</span>, smsIndex, <span class="hljs-keyword">null</span>));
                }
            } <span class="hljs-keyword">else</span> {
                <span class="hljs-keyword">if</span> (RILJ_LOGD) riljLog(<span class="hljs-string">" NEW_SMS_ON_SIM ERROR with wrong length "</span>
                        + smsIndex.length);
            }
        <span class="hljs-keyword">break</span>;
复制代码

RIL 中收发送短信的函数:

private void
    constructGsmSendSmsRilRequest (RILRequest rr, String smscPDU, String pdu) {
        rr.mParcel.writeInt(2);
        rr.mParcel.writeString(smscPDU);
        rr.mParcel.writeString(pdu);
    }
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span>
<span class="hljs-title">sendSMS</span> <span class="hljs-params">(String smscPDU, String pdu, Message result)</span> </span>{
    RILRequest rr
            = RILRequest.obtain(RIL_REQUEST_SEND_SMS, result);

    constructGsmSendSmsRilRequest(rr, smscPDU, pdu);

    <span class="hljs-keyword">if</span> (RILJ_LOGD) riljLog(rr.serialString() + <span class="hljs-string">"&gt; "</span> + requestToString(rr.mRequest));

    send(rr);
}

<span class="hljs-meta">@Override</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span>
<span class="hljs-title">sendSMSExpectMore</span> <span class="hljs-params">(String smscPDU, String pdu, Message result)</span> </span>{
    RILRequest rr
            = RILRequest.obtain(RIL_REQUEST_SEND_SMS_EXPECT_MORE, result);

    constructGsmSendSmsRilRequest(rr, smscPDU, pdu);

    <span class="hljs-keyword">if</span> (RILJ_LOGD) riljLog(rr.serialString() + <span class="hljs-string">"&gt; "</span> + requestToString(rr.mRequest));

    send(rr);
}

<span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span>
<span class="hljs-title">constructCdmaSendSmsRilRequest</span><span class="hljs-params">(RILRequest rr, <span class="hljs-keyword">byte</span>[] pdu)</span> </span>{
    <span class="hljs-keyword">int</span> address_nbr_of_digits;
    <span class="hljs-keyword">int</span> subaddr_nbr_of_digits;
    <span class="hljs-keyword">int</span> bearerDataLength;
    ByteArrayInputStream bais = <span class="hljs-keyword">new</span> ByteArrayInputStream(pdu);
    DataInputStream dis = <span class="hljs-keyword">new</span> DataInputStream(bais);

    <span class="hljs-keyword">try</span> {
        rr.mParcel.writeInt(dis.readInt()); <span class="hljs-comment">//teleServiceId</span>
        rr.mParcel.writeByte((<span class="hljs-keyword">byte</span>) dis.readInt()); <span class="hljs-comment">//servicePresent</span>
        rr.mParcel.writeInt(dis.readInt()); <span class="hljs-comment">//serviceCategory</span>
        rr.mParcel.writeInt(dis.read()); <span class="hljs-comment">//address_digit_mode</span>
        rr.mParcel.writeInt(dis.read()); <span class="hljs-comment">//address_nbr_mode</span>
        rr.mParcel.writeInt(dis.read()); <span class="hljs-comment">//address_ton</span>
        rr.mParcel.writeInt(dis.read()); <span class="hljs-comment">//address_nbr_plan</span>
        address_nbr_of_digits = (<span class="hljs-keyword">byte</span>) dis.read();
        rr.mParcel.writeByte((<span class="hljs-keyword">byte</span>) address_nbr_of_digits);
        <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i=<span class="hljs-number">0</span>; i &lt; address_nbr_of_digits; i++){
            rr.mParcel.writeByte(dis.readByte()); <span class="hljs-comment">// address_orig_bytes[i]</span>
        }
        rr.mParcel.writeInt(dis.read()); <span class="hljs-comment">//subaddressType</span>
        rr.mParcel.writeByte((<span class="hljs-keyword">byte</span>) dis.read()); <span class="hljs-comment">//subaddr_odd</span>
        subaddr_nbr_of_digits = (<span class="hljs-keyword">byte</span>) dis.read();
        rr.mParcel.writeByte((<span class="hljs-keyword">byte</span>) subaddr_nbr_of_digits);
        <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i=<span class="hljs-number">0</span>; i &lt; subaddr_nbr_of_digits; i++){
            rr.mParcel.writeByte(dis.readByte()); <span class="hljs-comment">//subaddr_orig_bytes[i]</span>
        }

        bearerDataLength = dis.read();
        rr.mParcel.writeInt(bearerDataLength);
        <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i=<span class="hljs-number">0</span>; i &lt; bearerDataLength; i++){
            rr.mParcel.writeByte(dis.readByte()); <span class="hljs-comment">//bearerData[i]</span>
        }
    }<span class="hljs-keyword">catch</span> (IOException ex){
        <span class="hljs-keyword">if</span> (RILJ_LOGD) riljLog(<span class="hljs-string">"sendSmsCdma: conversion from input stream to object failed: "</span>
                + ex);
    }
}

<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span>
<span class="hljs-title">sendCdmaSms</span><span class="hljs-params">(<span class="hljs-keyword">byte</span>[] pdu, Message result)</span> </span>{
    RILRequest rr
            = RILRequest.obtain(RIL_REQUEST_CDMA_SEND_SMS, result);

    constructCdmaSendSmsRilRequest(rr, pdu);

    <span class="hljs-keyword">if</span> (RILJ_LOGD) riljLog(rr.serialString() + <span class="hljs-string">"&gt; "</span> + requestToString(rr.mRequest));

    send(rr);
}

<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span>
<span class="hljs-title">sendImsGsmSms</span> <span class="hljs-params">(String smscPDU, String pdu, <span class="hljs-keyword">int</span> retry, <span class="hljs-keyword">int</span> messageRef,
        Message result)</span> </span>{
    RILRequest rr = RILRequest.obtain(RIL_REQUEST_IMS_SEND_SMS, result);

    rr.mParcel.writeInt(RILConstants.GSM_PHONE);
    rr.mParcel.writeByte((<span class="hljs-keyword">byte</span>)retry);
    rr.mParcel.writeInt(messageRef);

    constructGsmSendSmsRilRequest(rr, smscPDU, pdu);

    <span class="hljs-keyword">if</span> (RILJ_LOGD) riljLog(rr.serialString() + <span class="hljs-string">"&gt; "</span> + requestToString(rr.mRequest));

    send(rr);
}

<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span>
<span class="hljs-title">sendImsCdmaSms</span><span class="hljs-params">(<span class="hljs-keyword">byte</span>[] pdu, <span class="hljs-keyword">int</span> retry, <span class="hljs-keyword">int</span> messageRef, Message result)</span> </span>{
    RILRequest rr = RILRequest.obtain(RIL_REQUEST_IMS_SEND_SMS, result);

    rr.mParcel.writeInt(RILConstants.CDMA_PHONE);
    rr.mParcel.writeByte((<span class="hljs-keyword">byte</span>)retry);
    rr.mParcel.writeInt(messageRef);

    constructCdmaSendSmsRilRequest(rr, pdu);

    <span class="hljs-keyword">if</span> (RILJ_LOGD) riljLog(rr.serialString() + <span class="hljs-string">"&gt; "</span> + requestToString(rr.mRequest));

    send(rr);
}

<span class="hljs-meta">@Override</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">deleteSmsOnSim</span><span class="hljs-params">(<span class="hljs-keyword">int</span> index, Message response)</span> </span>{
    RILRequest rr = RILRequest.obtain(RIL_REQUEST_DELETE_SMS_ON_SIM,
            response);

    rr.mParcel.writeInt(<span class="hljs-number">1</span>);
    rr.mParcel.writeInt(index);

    <span class="hljs-keyword">if</span> (RILJ_LOGV) riljLog(rr.serialString() + <span class="hljs-string">"&gt; "</span>
            + requestToString(rr.mRequest)
            + <span class="hljs-string">" "</span> + index);

    send(rr);
}

<span class="hljs-meta">@Override</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">deleteSmsOnRuim</span><span class="hljs-params">(<span class="hljs-keyword">int</span> index, Message response)</span> </span>{
    RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM,
            response);

    rr.mParcel.writeInt(<span class="hljs-number">1</span>);
    rr.mParcel.writeInt(index);

    <span class="hljs-keyword">if</span> (RILJ_LOGV) riljLog(rr.serialString() + <span class="hljs-string">"&gt; "</span>
            + requestToString(rr.mRequest)
            + <span class="hljs-string">" "</span> + index);

    send(rr);
}

<span class="hljs-meta">@Override</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">writeSmsToSim</span><span class="hljs-params">(<span class="hljs-keyword">int</span> status, String smsc, String pdu, Message response)</span> </span>{
    status = translateStatus(status);

    RILRequest rr = RILRequest.obtain(RIL_REQUEST_WRITE_SMS_TO_SIM,
            response);

    rr.mParcel.writeInt(status);
    rr.mParcel.writeString(pdu);
    rr.mParcel.writeString(smsc);

    <span class="hljs-keyword">if</span> (RILJ_LOGV) riljLog(rr.serialString() + <span class="hljs-string">"&gt; "</span>
            + requestToString(rr.mRequest)
            + <span class="hljs-string">" "</span> + status);

    send(rr);
}

<span class="hljs-meta">@Override</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">writeSmsToRuim</span><span class="hljs-params">(<span class="hljs-keyword">int</span> status, String pdu, Message response)</span> </span>{
    status = translateStatus(status);

    RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM,
            response);

    rr.mParcel.writeInt(status);
    rr.mParcel.writeString(pdu);

    <span class="hljs-keyword">if</span> (RILJ_LOGV) riljLog(rr.serialString() + <span class="hljs-string">"&gt; "</span>
            + requestToString(rr.mRequest)
            + <span class="hljs-string">" "</span> + status);

    send(rr);
}

<span class="hljs-comment">/**
 *  Translates EF_SMS status bits to a status value compatible with
 *  SMS AT commands.  See TS 27.005 3.1.
 */</span>
<span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> <span class="hljs-title">translateStatus</span><span class="hljs-params">(<span class="hljs-keyword">int</span> status)</span> </span>{
    <span class="hljs-keyword">switch</span>(status &amp; <span class="hljs-number">0x7</span>) {
        <span class="hljs-keyword">case</span> SmsManager.STATUS_ON_ICC_READ:
            <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;
        <span class="hljs-keyword">case</span> SmsManager.STATUS_ON_ICC_UNREAD:
            <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
        <span class="hljs-keyword">case</span> SmsManager.STATUS_ON_ICC_SENT:
            <span class="hljs-keyword">return</span> <span class="hljs-number">3</span>;
        <span class="hljs-keyword">case</span> SmsManager.STATUS_ON_ICC_UNSENT:
            <span class="hljs-keyword">return</span> <span class="hljs-number">2</span>;
    }

    <span class="hljs-comment">// Default to READ.</span>
    <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;
}
复制代码

都是调用 send(RILRequest rr) 函数, 通过 Handler 来处理的

private void
    send(RILRequest rr) {
        Message msg;
    <span class="hljs-keyword">if</span> (mSocket == <span class="hljs-keyword">null</span>) {
        rr.onError(RADIO_NOT_AVAILABLE, <span class="hljs-keyword">null</span>);
        rr.release();
        <span class="hljs-keyword">return</span>;
    }

    msg = mSender.obtainMessage(EVENT_SEND, rr);

    acquireWakeLock();

    msg.sendToTarget();
}
复制代码

在 RILSender(Handler) 中处理请求:

class RILSender extends Handler implements Runnable {
        public RILSender(Looper looper) {
            super(looper);
        }
    <span class="hljs-comment">// Only allocated once</span>
    <span class="hljs-keyword">byte</span>[] dataLength = <span class="hljs-keyword">new</span> <span class="hljs-keyword">byte</span>[<span class="hljs-number">4</span>];

    <span class="hljs-comment">//***** Runnable implementation</span>
    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span>
    <span class="hljs-title">run</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-comment">//setup if needed</span>
    }

    <span class="hljs-comment">//***** Handler implementation</span>
    <span class="hljs-meta">@Override</span> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span>
    <span class="hljs-title">handleMessage</span><span class="hljs-params">(Message msg)</span> </span>{
        RILRequest rr = (RILRequest)(msg.obj);
        RILRequest req = <span class="hljs-keyword">null</span>;

        <span class="hljs-keyword">switch</span> (msg.what) {
            <span class="hljs-keyword">case</span> EVENT_SEND:
                <span class="hljs-keyword">try</span> {
                    LocalSocket s;
                    s = mSocket;
                    <span class="hljs-keyword">if</span> (s == <span class="hljs-keyword">null</span>) {
                        rr.onError(RADIO_NOT_AVAILABLE, <span class="hljs-keyword">null</span>);
                        rr.release();
                        decrementWakeLock();
                        <span class="hljs-keyword">return</span>;
                    }
                    <span class="hljs-keyword">synchronized</span> (mRequestList) {
                        mRequestList.append(rr.mSerial, rr);
                    }

                    <span class="hljs-keyword">byte</span>[] data;

                    data = rr.mParcel.marshall();
                    rr.mParcel.recycle();
                    rr.mParcel = <span class="hljs-keyword">null</span>;

                    <span class="hljs-keyword">if</span> (data.length &gt; RIL_MAX_COMMAND_BYTES) {
                        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(
                                <span class="hljs-string">"Parcel larger than max bytes allowed! "</span>
                                                      + data.length);
                    }

                    <span class="hljs-comment">// parcel length in big endian</span>
                    dataLength[<span class="hljs-number">0</span>] = dataLength[<span class="hljs-number">1</span>] = <span class="hljs-number">0</span>;
                    dataLength[<span class="hljs-number">2</span>] = (<span class="hljs-keyword">byte</span>)((data.length &gt;&gt; <span class="hljs-number">8</span>) &amp; <span class="hljs-number">0xff</span>);
                    dataLength[<span class="hljs-number">3</span>] = (<span class="hljs-keyword">byte</span>)((data.length) &amp; <span class="hljs-number">0xff</span>);

                    <span class="hljs-comment">//Rlog.v(RILJ_LOG_TAG, "writing packet: " + data.length + " bytes");</span>

                    s.getOutputStream().write(dataLength);
                    s.getOutputStream().write(data);
                } <span class="hljs-keyword">catch</span> (IOException ex) {
                    Rlog.e(RILJ_LOG_TAG, <span class="hljs-string">"IOException"</span>, ex);
                    req = findAndRemoveRequestFromList(rr.mSerial);
                    <span class="hljs-comment">// make sure this request has not already been handled,</span>
                    <span class="hljs-comment">// eg, if RILReceiver cleared the list.</span>
                    <span class="hljs-keyword">if</span> (req != <span class="hljs-keyword">null</span>) {
                        rr.onError(RADIO_NOT_AVAILABLE, <span class="hljs-keyword">null</span>);
                        rr.release();
                        decrementWakeLock();
                    }
                } <span class="hljs-keyword">catch</span> (RuntimeException exc) {
                    Rlog.e(RILJ_LOG_TAG, <span class="hljs-string">"Uncaught exception "</span>, exc);
                    req = findAndRemoveRequestFromList(rr.mSerial);
                    <span class="hljs-comment">// make sure this request has not already been handled,</span>
                    <span class="hljs-comment">// eg, if RILReceiver cleared the list.</span>
                    <span class="hljs-keyword">if</span> (req != <span class="hljs-keyword">null</span>) {
                        rr.onError(GENERIC_FAILURE, <span class="hljs-keyword">null</span>);
                        rr.release();
                        decrementWakeLock();
                    }
                }

                <span class="hljs-keyword">break</span>;

            <span class="hljs-keyword">case</span> EVENT_WAKE_LOCK_TIMEOUT:
                <span class="hljs-comment">// Haven't heard back from the last request.  Assume we're</span>
                <span class="hljs-comment">// not getting a response and  release the wake lock.</span>

                <span class="hljs-comment">// The timer of WAKE_LOCK_TIMEOUT is reset with each</span>
                <span class="hljs-comment">// new send request. So when WAKE_LOCK_TIMEOUT occurs</span>
                <span class="hljs-comment">// all requests in mRequestList already waited at</span>
                <span class="hljs-comment">// least DEFAULT_WAKE_LOCK_TIMEOUT but no response.</span>
                <span class="hljs-comment">//</span>
                <span class="hljs-comment">// Note: Keep mRequestList so that delayed response</span>
                <span class="hljs-comment">// can still be handled when response finally comes.</span>

                <span class="hljs-keyword">synchronized</span> (mRequestList) {
                    <span class="hljs-keyword">if</span> (clearWakeLock()) {
                        <span class="hljs-keyword">if</span> (RILJ_LOGD) {
                            <span class="hljs-keyword">int</span> count = mRequestList.size();
                            Rlog.d(RILJ_LOG_TAG, <span class="hljs-string">"WAKE_LOCK_TIMEOUT "</span> +
                                    <span class="hljs-string">" mRequestList="</span> + count);
                            <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; count; i++) {
                                rr = mRequestList.valueAt(i);
                                Rlog.d(RILJ_LOG_TAG, i + <span class="hljs-string">": ["</span> + rr.mSerial + <span class="hljs-string">"] "</span>
                                        + requestToString(rr.mRequest));
                            }
                        }
                    }
                }
                <span class="hljs-keyword">break</span>;
        }
    }
}
复制代码

处理 关于 Sms 的请求:

 private RILRequest findAndRemoveRequestFromList(int serial) {
        RILRequest rr = null;
        synchronized (mRequestList) {
            rr = mRequestList.get(serial);
            if (rr != null) {
                mRequestList.remove(serial);
            }
        }
        return rr;
    }
<span class="hljs-function"><span class="hljs-keyword">private</span> RILRequest
<span class="hljs-title">processSolicited</span> <span class="hljs-params">(Parcel p)</span> </span>{
    <span class="hljs-keyword">int</span> serial, error;
    <span class="hljs-keyword">boolean</span> found = <span class="hljs-keyword">false</span>;

    serial = p.readInt();
    error = p.readInt();
    RILRequest rr;
    rr = findAndRemoveRequestFromList(serial);

    <span class="hljs-keyword">if</span> (rr == <span class="hljs-keyword">null</span>) {
        Rlog.w(RILJ_LOG_TAG, <span class="hljs-string">"Unexpected solicited response! sn: "</span>
                        + serial + <span class="hljs-string">" error: "</span> + error);
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;
    }

    Object ret = <span class="hljs-keyword">null</span>;

    <span class="hljs-keyword">if</span> (error == <span class="hljs-number">0</span> || p.dataAvail() &gt; <span class="hljs-number">0</span>) {
        <span class="hljs-comment">// either command succeeds or command fails but with data payload</span>
        <span class="hljs-keyword">try</span> {<span class="hljs-keyword">switch</span> (rr.mRequest) {
        。。。。。。。       
        <span class="hljs-keyword">case</span> RIL_REQUEST_SEND_SMS: ret =  responseSMS(p); <span class="hljs-keyword">break</span>;
        <span class="hljs-keyword">case</span> RIL_REQUEST_SEND_SMS_EXPECT_MORE: ret =  responseSMS(p); <span class="hljs-keyword">break</span>;
        <span class="hljs-keyword">case</span> RIL_REQUEST_WRITE_SMS_TO_SIM: ret =  responseInts(p); <span class="hljs-keyword">break</span>;
        <span class="hljs-keyword">case</span> RIL_REQUEST_DELETE_SMS_ON_SIM: ret =  responseVoid(p); <span class="hljs-keyword">break</span>;
        <span class="hljs-keyword">case</span> RIL_REQUEST_CDMA_SEND_SMS: ret =  responseSMS(p); <span class="hljs-keyword">break</span>;
        <span class="hljs-keyword">case</span> RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE: ret =  responseVoid(p); <span class="hljs-keyword">break</span>;  
        <span class="hljs-keyword">case</span> RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM: ret =  responseInts(p); <span class="hljs-keyword">break</span>;
        <span class="hljs-keyword">case</span> RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM: ret =  responseVoid(p); <span class="hljs-keyword">break</span>;
        <span class="hljs-keyword">case</span> RIL_REQUEST_REPORT_SMS_MEMORY_STATUS: ret = responseVoid(p); <span class="hljs-keyword">break</span>;
        <span class="hljs-keyword">case</span> RIL_REQUEST_IMS_SEND_SMS: ret =  responseSMS(p); <span class="hljs-keyword">break</span>;
        ...
        <span class="hljs-comment">//break;</span>
        }} <span class="hljs-keyword">catch</span> (Throwable tr) {
            <span class="hljs-comment">// Exceptions here usually mean invalid RIL responses</span>
            Rlog.w(RILJ_LOG_TAG, rr.serialString() + <span class="hljs-string">"&lt; "</span>
                    + requestToString(rr.mRequest)
                    + <span class="hljs-string">" exception, possible invalid RIL response"</span>, tr);
            <span class="hljs-keyword">if</span> (rr.mResult != <span class="hljs-keyword">null</span>) {
                AsyncResult.forMessage(rr.mResult, <span class="hljs-keyword">null</span>, tr);
                rr.mResult.sendToTarget();
            }
            <span class="hljs-keyword">return</span> rr;
        }
    }       
    <span class="hljs-keyword">return</span> rr;
}
复制代码
private Object
responseSMS(Parcel p) {
    int messageRef, errorCode;
    String ackPDU;
    messageRef = p.readInt();
    ackPDU = p.readString();
    errorCode = p.readInt();
    SmsResponse response = new SmsResponse(messageRef, ackPDU, errorCode);
    return response;
}
复制代码
public interface CommandsInterface {
 <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">sendImsGsmSms</span> <span class="hljs-params">(String smscPDU, String pdu, <span class="hljs-keyword">int</span> retry, <span class="hljs-keyword">int</span> messageRef,
        Message response)</span></span>;
<span class="hljs-comment">/**
 * smscPDU is smsc address in PDU form GSM BCD format prefixed
 *      by a length byte (as expected by TS 27.005) or NULL for default SMSC
 * pdu is SMS in PDU format as an ASCII hex string
 *      less the SMSC address
 */</span>
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">sendSMS</span> <span class="hljs-params">(String smscPDU, String pdu, Message response)</span></span>;
 <span class="hljs-comment">/**
     * <span class="hljs-doctag">@param</span> pdu is CDMA-SMS in internal pseudo-PDU format
     * <span class="hljs-doctag">@param</span> response sent when operation completes
     */</span>
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">sendCdmaSms</span><span class="hljs-params">(<span class="hljs-keyword">byte</span>[] pdu, Message response)</span></span>;

}

复制代码

暂时不太清楚 Wear OS 中关于 SMS 的相关逻辑,倘若阉割了或者需要实现一个简化版的 (不需要或者简化彩信功能),实现方案可以参考接口扩展的方法需要实现两部分代码:

  1. 从 APP 至 RIL,发送请求;
  2. 从 RIL 至 APP,上报结果。

参考实现接口扩展:

Android Telephony分析(六) —- 接口扩展(实践篇)

  • Android

    开放手机联盟(一个由 30 多家科技公司和手机公司组成的团体)已开发出 Android,Android 是第一个完整、开放、免费的手机平台。

    293 引用
感谢    赞同    分享    收藏    关注    反对    举报    ...