前言:最近須要作iot上的相關需求,設計到短信app,本文梳理了Framework層的大體流程。java
短信發送包括髮送通常的短信、彩信. 發送的請求從app層經過SmsManager對象的sendMultipartTextMessage方法調用,傳遞到了Telephony Framework層中,Telephony Framework層與RIL層交互,最終完成短信的發送請求,轉換成RIL請求,其處理流程以下所示:android
本文基於9.0的源碼,梳理的流程。按照以上流程圖,找出對應關鍵位置的源碼,方便梳理整個短信發送在Framework層的整個流程。git
//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) {
...
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);
}
}
複製代碼
IccSmsInterfaceManagerapp
//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);
}
複製代碼
轉到SmsDispatchersController,分別調用 sendData、sendText、sendMultipartTextless
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);
}
}
}
複製代碼
SMSDispatcheride
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++;
}
}
複製代碼
SMSDispatcher類是經過sendSMS方法與RIL交互的,sendSMS方法又是由子類GSMDispatcher或者CDMADispatcher具體實現的。如今分析一下GSMDispatcher類中該方法的邏輯實現。oop
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;
}
}
複製代碼
首先查找: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 and release 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的相關邏輯,假若閹割了或者須要實現一個簡化版的(不須要或者簡化彩信功能),實現方案能夠參考接口擴展的方法須要實現兩部分代碼:
參考實現接口擴展: