1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.internal.telephony.gsm; 18 19 import static com.android.internal.telephony.SmsResponse.NO_ERROR_CODE; 20 21 import android.compat.annotation.UnsupportedAppUsage; 22 import android.os.AsyncResult; 23 import android.os.Build; 24 import android.os.Message; 25 import android.telephony.ServiceState; 26 27 import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails; 28 import com.android.internal.telephony.InboundSmsHandler; 29 import com.android.internal.telephony.Phone; 30 import com.android.internal.telephony.SMSDispatcher; 31 import com.android.internal.telephony.SmsConstants; 32 import com.android.internal.telephony.SmsController; 33 import com.android.internal.telephony.SmsDispatchersController; 34 import com.android.internal.telephony.SmsHeader; 35 import com.android.internal.telephony.SmsMessageBase; 36 import com.android.internal.telephony.uicc.IccRecords; 37 import com.android.internal.telephony.uicc.IccUtils; 38 import com.android.internal.telephony.uicc.UiccCardApplication; 39 import com.android.internal.telephony.uicc.UiccController; 40 import com.android.internal.telephony.util.SMSDispatcherUtil; 41 import com.android.telephony.Rlog; 42 43 import java.util.HashMap; 44 import java.util.concurrent.atomic.AtomicReference; 45 46 public final class GsmSMSDispatcher extends SMSDispatcher { 47 private static final String TAG = "GsmSMSDispatcher"; 48 protected UiccController mUiccController = null; 49 private AtomicReference<IccRecords> mIccRecords = new AtomicReference<IccRecords>(); 50 private AtomicReference<UiccCardApplication> mUiccApplication = 51 new AtomicReference<UiccCardApplication>(); 52 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 53 private GsmInboundSmsHandler mGsmInboundSmsHandler; 54 GsmSMSDispatcher(Phone phone, SmsDispatchersController smsDispatchersController, GsmInboundSmsHandler gsmInboundSmsHandler)55 public GsmSMSDispatcher(Phone phone, SmsDispatchersController smsDispatchersController, 56 GsmInboundSmsHandler gsmInboundSmsHandler) { 57 super(phone, smsDispatchersController); 58 mCi.setOnSmsStatus(this, EVENT_NEW_SMS_STATUS_REPORT, null); 59 mGsmInboundSmsHandler = gsmInboundSmsHandler; 60 mUiccController = UiccController.getInstance(); 61 mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null); 62 Rlog.d(TAG, "GsmSMSDispatcher created"); 63 } 64 65 @Override dispose()66 public void dispose() { 67 super.dispose(); 68 mCi.unSetOnSmsStatus(this); 69 mUiccController.unregisterForIccChanged(this); 70 } 71 72 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 73 @Override getFormat()74 protected String getFormat() { 75 return SmsConstants.FORMAT_3GPP; 76 } 77 78 /** 79 * Handles 3GPP format-specific events coming from the phone stack. 80 * Other events are handled by {@link SMSDispatcher#handleMessage}. 81 * 82 * @param msg the message to handle 83 */ 84 @Override handleMessage(Message msg)85 public void handleMessage(Message msg) { 86 switch (msg.what) { 87 case EVENT_NEW_ICC_SMS: 88 // pass to InboundSmsHandler to process 89 mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS, msg.obj); 90 break; 91 92 case EVENT_ICC_CHANGED: 93 onUpdateIccAvailability(); 94 break; 95 96 default: 97 super.handleMessage(msg); 98 } 99 } 100 101 @Override shouldBlockSmsForEcbm()102 protected boolean shouldBlockSmsForEcbm() { 103 // There is no such thing as ECBM for GSM. This only applies to CDMA. 104 return false; 105 } 106 107 @Override getSubmitPdu(String scAddr, String destAddr, String message, boolean statusReportRequested, SmsHeader smsHeader, int priority, int validityPeriod)108 protected SmsMessageBase.SubmitPduBase getSubmitPdu(String scAddr, String destAddr, 109 String message, boolean statusReportRequested, SmsHeader smsHeader, int priority, 110 int validityPeriod) { 111 return SMSDispatcherUtil.getSubmitPduGsm(scAddr, destAddr, message, statusReportRequested, 112 validityPeriod); 113 } 114 115 @Override getSubmitPdu(String scAddr, String destAddr, int destPort, byte[] message, boolean statusReportRequested)116 protected SmsMessageBase.SubmitPduBase getSubmitPdu(String scAddr, String destAddr, 117 int destPort, byte[] message, boolean statusReportRequested) { 118 return SMSDispatcherUtil.getSubmitPduGsm(scAddr, destAddr, destPort, message, 119 statusReportRequested); 120 } 121 122 @Override getSubmitPdu(String scAddr, String destAddr, String message, boolean statusReportRequested, SmsHeader smsHeader, int priority, int validityPeriod, int messageRef)123 protected SmsMessageBase.SubmitPduBase getSubmitPdu(String scAddr, String destAddr, 124 String message, boolean statusReportRequested, SmsHeader smsHeader, int priority, 125 int validityPeriod, int messageRef) { 126 return SMSDispatcherUtil.getSubmitPduGsm(scAddr, destAddr, message, statusReportRequested, 127 validityPeriod, messageRef); 128 } 129 130 @Override getSubmitPdu(String scAddr, String destAddr, int destPort, byte[] message, boolean statusReportRequested, int messageRef)131 protected SmsMessageBase.SubmitPduBase getSubmitPdu(String scAddr, String destAddr, 132 int destPort, byte[] message, boolean statusReportRequested, int messageRef) { 133 return SMSDispatcherUtil.getSubmitPduGsm(scAddr, destAddr, destPort, message, 134 statusReportRequested, messageRef); 135 } 136 137 @Override calculateLength(CharSequence messageBody, boolean use7bitOnly)138 protected TextEncodingDetails calculateLength(CharSequence messageBody, boolean use7bitOnly) { 139 return SMSDispatcherUtil.calculateLengthGsm(messageBody, use7bitOnly); 140 } 141 142 @Override handleStatusReport(Object o)143 protected void handleStatusReport(Object o) { 144 if (o instanceof AsyncResult) { 145 byte[] pdu = (byte[]) ((AsyncResult) o).result; 146 mSmsDispatchersController.handleSmsStatusReport(SmsConstants.FORMAT_3GPP, pdu); 147 mCi.acknowledgeLastIncomingGsmSms(true, 0 /* cause */, null); 148 } else { 149 Rlog.e(TAG, "handleStatusReport() called for object type " + o.getClass().getName()); 150 } 151 } 152 153 /** {@inheritDoc} */ 154 @UnsupportedAppUsage 155 @Override sendSms(SmsTracker tracker)156 protected void sendSms(SmsTracker tracker) { 157 int ss = mPhone.getServiceState().getState(); 158 159 Rlog.d(TAG, "sendSms: " 160 + " isIms()=" + isIms() 161 + " mRetryCount=" + tracker.mRetryCount 162 + " mImsRetry=" + tracker.mImsRetry 163 + " mMessageRef=" + tracker.mMessageRef 164 + " mUsesImsServiceForIms=" + tracker.mUsesImsServiceForIms 165 + " SS=" + ss 166 + " " + SmsController.formatCrossStackMessageId(tracker.mMessageId)); 167 168 // if sms over IMS is not supported on data and voice is not available... 169 if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) { 170 //In 5G case only Data Rat is reported. 171 if(mPhone.getServiceState().getRilDataRadioTechnology() 172 != ServiceState.RIL_RADIO_TECHNOLOGY_NR) { 173 tracker.onFailed(mContext, getNotInServiceError(ss), NO_ERROR_CODE); 174 notifySmsSentFailedToEmergencyStateTracker(tracker, false); 175 return; 176 } 177 } 178 179 Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker); 180 HashMap<String, Object> map = tracker.getData(); 181 byte pdu[] = (byte[]) map.get("pdu"); 182 byte smsc[] = (byte[]) map.get("smsc"); 183 if (tracker.mRetryCount > 0) { 184 // per TS 23.040 Section 9.2.3.6: If TP-MTI SMS-SUBMIT (0x01) type 185 // TP-RD (bit 2) is 1 for retry 186 // and TP-MR is set to previously failed sms TP-MR 187 if (((0x01 & pdu[0]) == 0x01)) { 188 pdu[0] |= 0x04; // TP-RD 189 pdu[1] = (byte) tracker.mMessageRef; // TP-MR 190 } 191 } 192 193 // sms over gsm is used: 194 // if sms over IMS is not supported AND 195 // this is not a retry case after sms over IMS failed 196 // indicated by mImsRetry > 0 OR 197 // this tracker uses ImsSmsDispatcher to handle SMS over IMS. This dispatcher has received 198 // this message because the ImsSmsDispatcher has indicated that the message needs to 199 // fall back to sending over CS. 200 if (0 == tracker.mImsRetry && !isIms() || tracker.mUsesImsServiceForIms) { 201 if (tracker.mRetryCount == 0 && tracker.mExpectMore) { 202 mCi.sendSMSExpectMore(IccUtils.bytesToHexString(smsc), 203 IccUtils.bytesToHexString(pdu), reply); 204 } else { 205 mCi.sendSMS(IccUtils.bytesToHexString(smsc), 206 IccUtils.bytesToHexString(pdu), reply); 207 } 208 } else { 209 mCi.sendImsGsmSms(IccUtils.bytesToHexString(smsc), 210 IccUtils.bytesToHexString(pdu), tracker.mImsRetry, 211 tracker.mMessageRef, reply); 212 // increment it here, so in case of SMS_FAIL_RETRY over IMS 213 // next retry will be sent using IMS request again. 214 tracker.mImsRetry++; 215 } 216 } 217 getUiccCardApplication()218 protected UiccCardApplication getUiccCardApplication() { 219 Rlog.d(TAG, "GsmSMSDispatcher: subId = " + mPhone.getSubId() 220 + " slotId = " + mPhone.getPhoneId()); 221 return mUiccController.getUiccCardApplication(mPhone.getPhoneId(), 222 UiccController.APP_FAM_3GPP); 223 } 224 onUpdateIccAvailability()225 private void onUpdateIccAvailability() { 226 if (mUiccController == null ) { 227 return; 228 } 229 230 UiccCardApplication newUiccApplication = getUiccCardApplication(); 231 232 UiccCardApplication app = mUiccApplication.get(); 233 if (app != newUiccApplication) { 234 if (app != null) { 235 Rlog.d(TAG, "Removing stale icc objects."); 236 if (mIccRecords.get() != null) { 237 mIccRecords.get().unregisterForNewSms(this); 238 } 239 mIccRecords.set(null); 240 mUiccApplication.set(null); 241 } 242 if (newUiccApplication != null) { 243 Rlog.d(TAG, "New Uicc application found"); 244 mUiccApplication.set(newUiccApplication); 245 mIccRecords.set(newUiccApplication.getIccRecords()); 246 if (mIccRecords.get() != null) { 247 mIccRecords.get().registerForNewSms(this, EVENT_NEW_ICC_SMS, null); 248 } 249 } 250 } 251 } 252 } 253