Framework層SMS傳送
前言:最近需要做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"); } if (TextUtils.isEmpty(text)) { throw new IllegalArgumentException("Invalid message body"); } if (priority < 0x00 || priority > 0x03) { throw new IllegalArgumentException("Invalid priority"); } if (validityPeriod < 0x05 || validityPeriod > 0x09b0a0) { throw new IllegalArgumentException("Invalid validity period"); } try { //AIDL 呼叫 ISms iccISms = getISmsServiceOrThrow(); if (iccISms != null) { // 搜尋sendTextForSubscriberWithOptions,在UiccSmsController iccISms.sendTextForSubscriberWithOptions(getSubscriptionId(), ActivityThread.currentPackageName(), destinationAddress, scAddress, text, sentIntent, deliveryIntent, persistMessage,priority, expectMore, validityPeriod); } } catch (RemoteException ex) { // ignore it } } 複製程式碼
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); if (parts.size() > 1 && parts.size() < 10 && !SmsMessage.hasEmsSupport()) { for (int i = 0; i < parts.size(); i++) { // If EMS is not supported, we have to break down EMS into single segment SMS // and add page info " x/y". String singlePart = parts.get(i); if (SmsMessage.shouldAppendPageNumberAsPrefix()) { singlePart = String.valueOf(i + 1) + '/' + parts.size() + ' ' + singlePart; } else { singlePart = singlePart.concat(' ' + String.valueOf(i + 1) + '/' + parts.size()); } PendingIntent singleSentIntent = null; if (sentIntents != null && sentIntents.size() > i) { singleSentIntent = sentIntents.get(i); } PendingIntent singleDeliveryIntent = null; if (deliveryIntents != null && deliveryIntents.size() > i) { singleDeliveryIntent = deliveryIntents.get(i); } mDispatchersController.sendText(destAddr, scAddr, singlePart, singleSentIntent, singleDeliveryIntent, null/*messageUri*/, callingPackage, persistMessageForNonDefaultSmsApp, priority, expectMore, validityPeriod); } return; } //轉移到 mDispatchersController mDispatchersController.sendMultipartText(destAddr, scAddr, (ArrayList<String>) parts, (ArrayList<PendingIntent>) sentIntents, (ArrayList<PendingIntent>) deliveryIntents, null, 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*/); if (!sendSmsByCarrierApp(true /* isDataSms */, tracker)) { sendSubmitPdu(tracker); } } else { Rlog.e(TAG, "SMSDispatcher.sendData(): getSubmitPdu() returned null"); 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 = new TextEncodingDetails[msgCount]; for (int i = 0; i < msgCount; i++) { TextEncodingDetails details = calculateLength(parts.get(i), false); if (encoding != details.codeUnitSize && (encoding == SmsConstants.ENCODING_UNKNOWN || encoding == SmsConstants.ENCODING_7BIT)) { encoding = details.codeUnitSize; } encodingForParts[i] = details; } SmsTracker[] trackers = new SmsTracker[msgCount]; // States to track at the message level (for all parts) final AtomicInteger unsentPartCount = new AtomicInteger(msgCount); final AtomicBoolean anyPartFailed = new AtomicBoolean(false); for (int i = 0; i < msgCount; i++) { SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef(); concatRef.refNumber = refNumber; concatRef.seqNumber = i + 1;// 1-based sequence concatRef.msgCount = msgCount; // TODO: We currently set this to true since our messaging app will never // send more than 255 parts (it converts the message to MMS well before that). // However, we should support 3rd party messaging apps that might need 16-bit // references // Note:It's not sufficient to just flip this bit to true; it will have // ripple effects (several calculations assume 8-bit ref). concatRef.isEightBits = true; SmsHeader smsHeader = new SmsHeader(); smsHeader.concatRef = concatRef; // Set the national language tables for 3GPP 7-bit encoding, if enabled. if (encoding == SmsConstants.ENCODING_7BIT) { smsHeader.languageTable = encodingForParts[i].languageTable; smsHeader.languageShiftTable = encodingForParts[i].languageShiftTable; } PendingIntent sentIntent = null; if (sentIntents != null && sentIntents.size() > i) { sentIntent = sentIntents.get(i); } PendingIntent deliveryIntent = null; if (deliveryIntents != null && deliveryIntents.size() > i) { deliveryIntent = deliveryIntents.get(i); } trackers[i] = getNewSubmitPduTracker(destAddr, scAddr, parts.get(i), smsHeader, encoding, sentIntent, deliveryIntent, (i == (msgCount - 1)), unsentPartCount, anyPartFailed, messageUri, fullMessageText, priority, expectMore, validityPeriod); trackers[i].mPersistMessage = persistMessage; } if (parts == null || trackers == null || trackers.length == 0 || trackers[0] == null) { Rlog.e(TAG, "Cannot send multipart text. parts=" + parts + " trackers=" + trackers); return; } String carrierPackage = getCarrierAppPackageName(); if (carrierPackage != null) { Rlog.d(TAG, "Found carrier package."); MultipartSmsSender smsSender = new MultipartSmsSender(parts, trackers); smsSender.sendSmsByCarrierApp(carrierPackage, new MultipartSmsSenderCallback(smsSender)); } else { Rlog.v(TAG, "No carrier package."); for (SmsTracker tracker : trackers) { if (tracker != null) { sendSubmitPdu(tracker); } else { Rlog.e(TAG, "Null tracker."); } } } } 複製程式碼
都呼叫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); if (mSmsSendDisabled) { Rlog.e(TAG, "Device does not support sending sms."); tracker.onFailed(mContext, RESULT_ERROR_NO_SERVICE, 0/*errorCode*/); return; } if (pdu == null) { Rlog.e(TAG, "Empty PDU"); tracker.onFailed(mContext, RESULT_ERROR_NULL_PDU, 0/*errorCode*/); return; } // 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. Rlog.e(TAG, "Can't get calling app package name: refusing to send SMS"); tracker.onFailed(mContext, RESULT_ERROR_GENERIC_FAILURE, 0/*errorCode*/); return; } // Get package info via packagemanager PackageInfo appInfo; try { // XXX this is lossy- apps can share a UID appInfo = pm.getPackageInfoAsUser( packageNames[0], PackageManager.GET_SIGNATURES, tracker.mUserId); } catch (PackageManager.NameNotFoundException e) { Rlog.e(TAG, "Can't get calling app package info: refusing to send SMS"); tracker.onFailed(mContext, RESULT_ERROR_GENERIC_FAILURE, 0/*errorCode*/); return; } // checkDestination() returns true if the destination is not a premium short code or the // sending app is approved to send to short codes. Otherwise, a message is sent to our // handler with the SmsTracker to request user confirmation before sending. if (checkDestination(tracker)) { // check for excessive outgoing SMS usage by this app if (!mSmsDispatchersController.getUsageMonitor().check( appInfo.packageName, SINGLE_PART_SMS)) { sendMessage(obtainMessage(EVENT_SEND_LIMIT_REACHED_CONFIRMATION, tracker)); return; } //抽象方法: sendSms(tracker); } if (PhoneNumberUtils.isLocalEmergencyNumber(mContext, tracker.mDestAddress)) { new 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()); int ss = mPhone.getServiceState().getState(); // if sms over IMS is not supported on data and voice is not available... if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) { tracker.onFailed(mContext, getNotInServiceError(ss), 0/*errorCode*/); return; } Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker); byte[] pdu = (byte[]) tracker.getData().get("pdu"); int currentDataNetwork = mPhone.getServiceState().getDataNetworkType(); boolean imsSmsDisabled = (currentDataNetwork == TelephonyManager.NETWORK_TYPE_EHRPD || (ServiceState.isLte(currentDataNetwork) && !mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed())) && mPhone.getServiceState().getVoiceNetworkType() == TelephonyManager.NETWORK_TYPE_1xRTT && ((GsmCdmaPhone) mPhone).mCT.mState != PhoneConstants.State.IDLE; // sms over cdma is used: //if sms over IMS is not supported AND //this is not a retry case after sms over IMS failed //indicated by mImsRetry > 0 OR //SMS over IMS is disabled because of the network type OR //SMS over IMS is being handled by the ImsSmsDispatcher implementation and has indicated //that the message should fall back to sending over CS. if (0 == tracker.mImsRetry && !isIms() || imsSmsDisabled || tracker.mUsesImsServiceForIms) { mCi.sendCdmaSms(pdu, reply); } else { mCi.sendImsCdmaSms(pdu, tracker.mImsRetry, tracker.mMessageRef, reply); // increment it here, so in case of SMS_FAIL_RETRY over IMS // next retry will be sent using IMS request again. 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]; for (int i = 0; i < numPhones; i++) { // reads the system properties and makes commandsinterface // Get preferred network type. networkModes[i] = RILConstants.PREFERRED_NETWORK_MODE; Rlog.i(LOG_TAG, "Network Mode set to " + Integer.toString(networkModes[i])); sCommandsInterfaces[i] = new RIL(context, networkModes[i], cdmaSubscription, i); } Rlog.i(LOG_TAG, "Creating SubscriptionController"); SubscriptionController.init(context, sCommandsInterfaces); // Instantiate UiccController so that all other classes can just // call getInstance() sUiccController = UiccController.make(context, sCommandsInterfaces); .... for (int i = 0; i < numPhones; i++) { Phone phone = null; int phoneType = TelephonyManager.getPhoneType(networkModes[i]); if (phoneType == PhoneConstants.PHONE_TYPE_GSM) { phone = new GsmCdmaPhone(context, sCommandsInterfaces[i], sPhoneNotifier, i, PhoneConstants.PHONE_TYPE_GSM, TelephonyComponentFactory.getInstance()); } else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) { //把RIL物件給到phone phone = new GsmCdmaPhone(context, sCommandsInterfaces[i], sPhoneNotifier, i, PhoneConstants.PHONE_TYPE_CDMA_LTE, TelephonyComponentFactory.getInstance()); } Rlog.i(LOG_TAG, "Creating Phone with type = " + phoneType + " sub = " + 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); // FIXME this should move up a layer String a[] = new String[2]; a[1] = (String)ret; SmsMessage sms; sms = SmsMessage.newFromCMT(a); if (mGsmSmsRegistrant != null) { mGsmSmsRegistrant .notifyRegistrant(new AsyncResult(null, sms, null)); } break; } case RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT: if (RILJ_LOGD) unsljLogRet(response, ret); if (mSmsStatusRegistrant != null) { mSmsStatusRegistrant.notifyRegistrant( new AsyncResult(null, ret, null)); } break; case RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM: if (RILJ_LOGD) unsljLogRet(response, ret); int[] smsIndex = (int[])ret; if(smsIndex.length == 1) { if (mSmsOnSimRegistrant != null) { mSmsOnSimRegistrant. notifyRegistrant(new AsyncResult(null, smsIndex, null)); } } else { if (RILJ_LOGD) riljLog(" NEW_SMS_ON_SIM ERROR with wrong length " + smsIndex.length); } break; 複製程式碼
RIL中收發送簡訊的函式:
private void constructGsmSendSmsRilRequest (RILRequest rr, String smscPDU, String pdu) { rr.mParcel.writeInt(2); rr.mParcel.writeString(smscPDU); rr.mParcel.writeString(pdu); } public void sendSMS (String smscPDU, String pdu, Message result) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_SEND_SMS, result); constructGsmSendSmsRilRequest(rr, smscPDU, pdu); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } @Override public void sendSMSExpectMore (String smscPDU, String pdu, Message result) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_SEND_SMS_EXPECT_MORE, result); constructGsmSendSmsRilRequest(rr, smscPDU, pdu); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } private void constructCdmaSendSmsRilRequest(RILRequest rr, byte[] pdu) { int address_nbr_of_digits; int subaddr_nbr_of_digits; int bearerDataLength; ByteArrayInputStream bais = new ByteArrayInputStream(pdu); DataInputStream dis = new DataInputStream(bais); try { rr.mParcel.writeInt(dis.readInt()); //teleServiceId rr.mParcel.writeByte((byte) dis.readInt()); //servicePresent rr.mParcel.writeInt(dis.readInt()); //serviceCategory rr.mParcel.writeInt(dis.read()); //address_digit_mode rr.mParcel.writeInt(dis.read()); //address_nbr_mode rr.mParcel.writeInt(dis.read()); //address_ton rr.mParcel.writeInt(dis.read()); //address_nbr_plan address_nbr_of_digits = (byte) dis.read(); rr.mParcel.writeByte((byte) address_nbr_of_digits); for(int i=0; i < address_nbr_of_digits; i++){ rr.mParcel.writeByte(dis.readByte()); // address_orig_bytes[i] } rr.mParcel.writeInt(dis.read()); //subaddressType rr.mParcel.writeByte((byte) dis.read()); //subaddr_odd subaddr_nbr_of_digits = (byte) dis.read(); rr.mParcel.writeByte((byte) subaddr_nbr_of_digits); for(int i=0; i < subaddr_nbr_of_digits; i++){ rr.mParcel.writeByte(dis.readByte()); //subaddr_orig_bytes[i] } bearerDataLength = dis.read(); rr.mParcel.writeInt(bearerDataLength); for(int i=0; i < bearerDataLength; i++){ rr.mParcel.writeByte(dis.readByte()); //bearerData[i] } }catch (IOException ex){ if (RILJ_LOGD) riljLog("sendSmsCdma: conversion from input stream to object failed: " + ex); } } public void sendCdmaSms(byte[] pdu, Message result) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_SEND_SMS, result); constructCdmaSendSmsRilRequest(rr, pdu); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } public void sendImsGsmSms (String smscPDU, String pdu, int retry, int messageRef, Message result) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_IMS_SEND_SMS, result); rr.mParcel.writeInt(RILConstants.GSM_PHONE); rr.mParcel.writeByte((byte)retry); rr.mParcel.writeInt(messageRef); constructGsmSendSmsRilRequest(rr, smscPDU, pdu); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } public void sendImsCdmaSms(byte[] pdu, int retry, int messageRef, Message result) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_IMS_SEND_SMS, result); rr.mParcel.writeInt(RILConstants.CDMA_PHONE); rr.mParcel.writeByte((byte)retry); rr.mParcel.writeInt(messageRef); constructCdmaSendSmsRilRequest(rr, pdu); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } @Override public void deleteSmsOnSim(int index, Message response) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_DELETE_SMS_ON_SIM, response); rr.mParcel.writeInt(1); rr.mParcel.writeInt(index); if (RILJ_LOGV) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + index); send(rr); } @Override public void deleteSmsOnRuim(int index, Message response) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM, response); rr.mParcel.writeInt(1); rr.mParcel.writeInt(index); if (RILJ_LOGV) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + index); send(rr); } @Override public void writeSmsToSim(int status, String smsc, String pdu, Message response) { 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); if (RILJ_LOGV) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + status); send(rr); } @Override public void writeSmsToRuim(int status, String pdu, Message response) { status = translateStatus(status); RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM, response); rr.mParcel.writeInt(status); rr.mParcel.writeString(pdu); if (RILJ_LOGV) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + status); send(rr); } /** *Translates EF_SMS status bits to a status value compatible with *SMS AT commands.See TS 27.005 3.1. */ private int translateStatus(int status) { switch(status & 0x7) { case SmsManager.STATUS_ON_ICC_READ: return 1; case SmsManager.STATUS_ON_ICC_UNREAD: return 0; case SmsManager.STATUS_ON_ICC_SENT: return 3; case SmsManager.STATUS_ON_ICC_UNSENT: return 2; } // Default to READ. return 1; } 複製程式碼
都是呼叫 send(RILRequest rr)函式, 通過Handler來處理的
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(); } 複製程式碼
在RILSender(Handler)中處理請求:
class RILSender extends Handler implements Runnable { public RILSender(Looper looper) { super(looper); } // Only allocated once byte[] dataLength = new byte[4]; //***** Runnable implementation @Override public void run() { //setup if needed } //***** Handler implementation @Override public void handleMessage(Message msg) { RILRequest rr = (RILRequest)(msg.obj); RILRequest req = null; switch (msg.what) { case EVENT_SEND: try { LocalSocket s; s = mSocket; if (s == null) { rr.onError(RADIO_NOT_AVAILABLE, null); rr.release(); decrementWakeLock(); return; } synchronized (mRequestList) { mRequestList.append(rr.mSerial, rr); } byte[] data; data = rr.mParcel.marshall(); rr.mParcel.recycle(); rr.mParcel = 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); //Rlog.v(RILJ_LOG_TAG, "writing packet: " + data.length + " bytes"); s.getOutputStream().write(dataLength); s.getOutputStream().write(data); } catch (IOException ex) { Rlog.e(RILJ_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) { rr.onError(RADIO_NOT_AVAILABLE, null); rr.release(); decrementWakeLock(); } } catch (RuntimeException exc) { Rlog.e(RILJ_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) { rr.onError(GENERIC_FAILURE, null); rr.release(); decrementWakeLock(); } } break; case EVENT_WAKE_LOCK_TIMEOUT: // Haven't heard back from the last request.Assume we're // not getting a response andrelease the wake lock. // The timer of WAKE_LOCK_TIMEOUT is reset with each // new send request. So when WAKE_LOCK_TIMEOUT occurs // all requests in mRequestList already waited at // least DEFAULT_WAKE_LOCK_TIMEOUT but no response. // // Note: Keep mRequestList so that delayed response // can still be handled when response finally comes. synchronized (mRequestList) { if (clearWakeLock()) { if (RILJ_LOGD) { int count = mRequestList.size(); Rlog.d(RILJ_LOG_TAG, "WAKE_LOCK_TIMEOUT " + " mRequestList=" + count); for (int i = 0; i < count; i++) { rr = mRequestList.valueAt(i); Rlog.d(RILJ_LOG_TAG, i + ": [" + rr.mSerial + "] " + requestToString(rr.mRequest)); } } } } break; } } } 複製程式碼
處理 關於 Sms的請求:
private RILRequest findAndRemoveRequestFromList(int serial) { RILRequest rr = null; synchronized (mRequestList) { rr = mRequestList.get(serial); if (rr != null) { mRequestList.remove(serial); } } return rr; } private RILRequest processSolicited (Parcel p) { int serial, error; boolean found = false; serial = p.readInt(); error = p.readInt(); RILRequest rr; rr = findAndRemoveRequestFromList(serial); if (rr == null) { Rlog.w(RILJ_LOG_TAG, "Unexpected solicited response! sn: " + serial + " error: " + error); return null; } Object ret = null; if (error == 0 || p.dataAvail() > 0) { // either command succeeds or command fails but with data payload try {switch (rr.mRequest) { 。。。。。。。 case RIL_REQUEST_SEND_SMS: ret =responseSMS(p); break; case RIL_REQUEST_SEND_SMS_EXPECT_MORE: ret =responseSMS(p); break; case RIL_REQUEST_WRITE_SMS_TO_SIM: ret =responseInts(p); break; case RIL_REQUEST_DELETE_SMS_ON_SIM: ret =responseVoid(p); break; case RIL_REQUEST_CDMA_SEND_SMS: ret =responseSMS(p); break; case RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE: ret =responseVoid(p); break; case RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM: ret =responseInts(p); break; case RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM: ret =responseVoid(p); break; case RIL_REQUEST_REPORT_SMS_MEMORY_STATUS: ret = responseVoid(p); break; case RIL_REQUEST_IMS_SEND_SMS: ret =responseSMS(p); break; ... //break; }} catch (Throwable tr) { // Exceptions here usually mean invalid RIL responses Rlog.w(RILJ_LOG_TAG, rr.serialString() + "< " + requestToString(rr.mRequest) + " exception, possible invalid RIL response", tr); if (rr.mResult != null) { AsyncResult.forMessage(rr.mResult, null, tr); rr.mResult.sendToTarget(); } return rr; } } return 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 { void sendImsGsmSms (String smscPDU, String pdu, int retry, int messageRef, Message response); /** * 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 */ void sendSMS (String smscPDU, String pdu, Message response); /** * @param pdu is CDMA-SMS in internal pseudo-PDU format * @param response sent when operation completes */ void sendCdmaSms(byte[] pdu, Message response); } 複製程式碼
暫時不太清楚Wear OS中關於SMS的相關邏輯,倘若閹割了或者需要實現一個簡化版的(不需要或者簡化彩信功能),實現方案可以參考介面擴充套件的方法需要實現兩部分程式碼:
- 從APP至RIL,傳送請求;
- 從RIL至APP,上報結果。

參考實現介面擴充套件: