1 /* 2 * Copyright (C) 2008 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; 18 19 import static android.telephony.SmsManager.STATUS_ON_ICC_FREE; 20 import static android.telephony.SmsManager.STATUS_ON_ICC_READ; 21 import static android.telephony.SmsManager.STATUS_ON_ICC_UNREAD; 22 23 import android.Manifest; 24 import android.app.AppOpsManager; 25 import android.app.PendingIntent; 26 import android.compat.annotation.UnsupportedAppUsage; 27 import android.content.BroadcastReceiver; 28 import android.content.ContentResolver; 29 import android.content.Context; 30 import android.content.Intent; 31 import android.content.IntentFilter; 32 import android.content.pm.PackageManager; 33 import android.database.Cursor; 34 import android.database.sqlite.SQLiteException; 35 import android.net.Uri; 36 import android.os.AsyncResult; 37 import android.os.Binder; 38 import android.os.Handler; 39 import android.os.Looper; 40 import android.os.Message; 41 import android.provider.Telephony; 42 import android.telephony.CarrierConfigManager; 43 import android.telephony.SmsCbMessage; 44 import android.telephony.SmsManager; 45 import android.telephony.SmsMessage; 46 import android.telephony.SubscriptionManager; 47 import android.telephony.emergency.EmergencyNumber; 48 import android.util.LocalLog; 49 import android.util.Log; 50 51 import com.android.internal.annotations.VisibleForTesting; 52 import com.android.internal.telephony.cdma.CdmaSmsBroadcastConfigInfo; 53 import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo; 54 import com.android.internal.telephony.uicc.IccConstants; 55 import com.android.internal.telephony.uicc.IccFileHandler; 56 import com.android.internal.telephony.uicc.IccUtils; 57 import com.android.internal.telephony.uicc.UiccController; 58 import com.android.internal.telephony.uicc.UiccProfile; 59 import com.android.internal.util.HexDump; 60 import com.android.telephony.Rlog; 61 62 import java.io.FileDescriptor; 63 import java.io.PrintWriter; 64 import java.util.ArrayList; 65 import java.util.Arrays; 66 import java.util.List; 67 68 /** 69 * IccSmsInterfaceManager to provide an inter-process communication to 70 * access Sms in Icc. 71 */ 72 public class IccSmsInterfaceManager { 73 static final String LOG_TAG = "IccSmsInterfaceManager"; 74 static final boolean DBG = true; 75 76 @UnsupportedAppUsage 77 protected final Object mLock = new Object(); 78 @UnsupportedAppUsage 79 protected boolean mSuccess; 80 @UnsupportedAppUsage 81 private List<SmsRawData> mSms; 82 83 private String mSmsc; 84 85 @UnsupportedAppUsage 86 private CellBroadcastRangeManager mCellBroadcastRangeManager = 87 new CellBroadcastRangeManager(); 88 private CdmaBroadcastRangeManager mCdmaBroadcastRangeManager = 89 new CdmaBroadcastRangeManager(); 90 91 private static final int EVENT_LOAD_DONE = 1; 92 private static final int EVENT_UPDATE_DONE = 2; 93 protected static final int EVENT_SET_BROADCAST_ACTIVATION_DONE = 3; 94 protected static final int EVENT_SET_BROADCAST_CONFIG_DONE = 4; 95 private static final int EVENT_GET_SMSC_DONE = 5; 96 private static final int EVENT_SET_SMSC_DONE = 6; 97 private static final int SMS_CB_CODE_SCHEME_MIN = 0; 98 private static final int SMS_CB_CODE_SCHEME_MAX = 255; 99 public static final int SMS_MESSAGE_PRIORITY_NOT_SPECIFIED = -1; 100 public static final int SMS_MESSAGE_PERIOD_NOT_SPECIFIED = -1; 101 102 @UnsupportedAppUsage 103 protected Phone mPhone; 104 @UnsupportedAppUsage 105 final protected Context mContext; 106 @UnsupportedAppUsage 107 final protected AppOpsManager mAppOps; 108 @VisibleForTesting 109 public SmsDispatchersController mDispatchersController; 110 private SmsPermissions mSmsPermissions; 111 112 private final LocalLog mCellBroadcastLocalLog = new LocalLog(100); 113 114 @UnsupportedAppUsage 115 protected Handler mHandler = new Handler() { 116 @Override 117 public void handleMessage(Message msg) { 118 AsyncResult ar; 119 120 switch (msg.what) { 121 case EVENT_UPDATE_DONE: 122 ar = (AsyncResult) msg.obj; 123 synchronized (mLock) { 124 mSuccess = (ar.exception == null); 125 mLock.notifyAll(); 126 } 127 break; 128 case EVENT_LOAD_DONE: 129 ar = (AsyncResult)msg.obj; 130 synchronized (mLock) { 131 if (ar.exception == null) { 132 mSms = buildValidRawData((ArrayList<byte[]>) ar.result); 133 //Mark SMS as read after importing it from card. 134 markMessagesAsRead((ArrayList<byte[]>) ar.result); 135 } else { 136 if (Rlog.isLoggable("SMS", Log.DEBUG)) { 137 loge("Cannot load Sms records"); 138 } 139 mSms = null; 140 } 141 mLock.notifyAll(); 142 } 143 break; 144 case EVENT_SET_BROADCAST_ACTIVATION_DONE: 145 case EVENT_SET_BROADCAST_CONFIG_DONE: 146 ar = (AsyncResult) msg.obj; 147 synchronized (mLock) { 148 mSuccess = (ar.exception == null); 149 mLock.notifyAll(); 150 } 151 break; 152 case EVENT_GET_SMSC_DONE: 153 ar = (AsyncResult) msg.obj; 154 synchronized (mLock) { 155 if (ar.exception == null) { 156 mSmsc = (String) ar.result; 157 } else { 158 loge("Cannot read SMSC"); 159 mSmsc = null; 160 } 161 mLock.notifyAll(); 162 } 163 break; 164 case EVENT_SET_SMSC_DONE: 165 ar = (AsyncResult) msg.obj; 166 synchronized (mLock) { 167 mSuccess = (ar.exception == null); 168 mLock.notifyAll(); 169 } 170 break; 171 } 172 } 173 }; 174 IccSmsInterfaceManager(Phone phone)175 protected IccSmsInterfaceManager(Phone phone) { 176 mPhone = phone; 177 mContext = phone.getContext(); 178 mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); 179 mDispatchersController = 180 new SmsDispatchersController( 181 phone, phone.mSmsStorageMonitor, phone.mSmsUsageMonitor); 182 mSmsPermissions = new SmsPermissions(phone, mContext, mAppOps); 183 184 mContext.registerReceiver( 185 new BroadcastReceiver() { 186 @Override 187 public void onReceive(Context context, Intent intent) { 188 if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED 189 .equals(intent.getAction())) { 190 if (mPhone.getPhoneId() == intent.getIntExtra( 191 CarrierConfigManager.EXTRA_SLOT_INDEX, 192 SubscriptionManager.INVALID_SIM_SLOT_INDEX)) { 193 new Thread(() -> { 194 log("Carrier config changed. Update ranges."); 195 mCellBroadcastRangeManager.updateRanges(); 196 }).start(); 197 } 198 } 199 } 200 }, new IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)); 201 } 202 enforceNotOnHandlerThread(String methodName)203 private void enforceNotOnHandlerThread(String methodName) { 204 if (Looper.myLooper() == mHandler.getLooper()) { 205 throw new RuntimeException("This method " + methodName + " will deadlock if called from" 206 + " the handler's thread."); 207 } 208 } 209 markMessagesAsRead(ArrayList<byte[]> messages)210 protected void markMessagesAsRead(ArrayList<byte[]> messages) { 211 if (messages == null) { 212 return; 213 } 214 215 //IccFileHandler can be null, if icc card is absent. 216 IccFileHandler fh = mPhone.getIccFileHandler(); 217 if (fh == null) { 218 //shouldn't really happen, as messages are marked as read, only 219 //after importing it from icc. 220 if (Rlog.isLoggable("SMS", Log.DEBUG)) { 221 loge("markMessagesAsRead - aborting, no icc card present."); 222 } 223 return; 224 } 225 226 int count = messages.size(); 227 228 for (int i = 0; i < count; i++) { 229 byte[] ba = messages.get(i); 230 if ((ba[0] & 0x07) == STATUS_ON_ICC_UNREAD) { 231 int n = ba.length; 232 byte[] nba = new byte[n - 1]; 233 System.arraycopy(ba, 1, nba, 0, n - 1); 234 byte[] record = makeSmsRecordData(STATUS_ON_ICC_READ, nba); 235 fh.updateEFLinearFixed(IccConstants.EF_SMS, i + 1, record, null, null); 236 if (Rlog.isLoggable("SMS", Log.DEBUG)) { 237 log("SMS " + (i + 1) + " marked as read"); 238 } 239 } 240 } 241 } 242 243 @UnsupportedAppUsage enforceReceiveAndSend(String message)244 protected void enforceReceiveAndSend(String message) { 245 mContext.enforceCallingOrSelfPermission( 246 Manifest.permission.RECEIVE_SMS, message); 247 mContext.enforceCallingOrSelfPermission( 248 Manifest.permission.SEND_SMS, message); 249 } 250 251 /** 252 * Update the specified message on the Icc. 253 * 254 * @param index record index of message to update 255 * @param status new message status (STATUS_ON_ICC_READ, 256 * STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT, 257 * STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE) 258 * @param pdu the raw PDU to store 259 * @return success or not 260 * 261 */ 262 263 @UnsupportedAppUsage 264 public boolean updateMessageOnIccEf(String callingPackage, int index, int status, byte[] pdu)265 updateMessageOnIccEf(String callingPackage, int index, int status, byte[] pdu) { 266 if (DBG) log("updateMessageOnIccEf: index=" + index + 267 " status=" + status + " ==> " + 268 "("+ Arrays.toString(pdu) + ")"); 269 enforceReceiveAndSend("Updating message on Icc"); 270 enforceNotOnHandlerThread("updateMessageOnIccEf"); 271 if (mAppOps.noteOp(AppOpsManager.OPSTR_WRITE_ICC_SMS, Binder.getCallingUid(), 272 callingPackage) != AppOpsManager.MODE_ALLOWED) { 273 return false; 274 } 275 synchronized(mLock) { 276 mSuccess = false; 277 Message response = mHandler.obtainMessage(EVENT_UPDATE_DONE); 278 279 if ((status & 0x01) == STATUS_ON_ICC_FREE) { 280 // RIL_REQUEST_DELETE_SMS_ON_SIM vs RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM 281 // Special case FREE: call deleteSmsOnSim/Ruim instead of 282 // manipulating the record 283 // Will eventually fail if icc card is not present. 284 if (PhoneConstants.PHONE_TYPE_GSM == mPhone.getPhoneType()) { 285 mPhone.mCi.deleteSmsOnSim(index, response); 286 } else { 287 mPhone.mCi.deleteSmsOnRuim(index, response); 288 } 289 } else { 290 //IccFilehandler can be null if ICC card is not present. 291 IccFileHandler fh = mPhone.getIccFileHandler(); 292 if (fh == null) { 293 response.recycle(); 294 return mSuccess; /* is false */ 295 } 296 byte[] record = makeSmsRecordData(status, pdu); 297 fh.updateEFLinearFixed( 298 IccConstants.EF_SMS, 299 index, record, null, response); 300 } 301 try { 302 mLock.wait(); 303 } catch (InterruptedException e) { 304 loge("interrupted while trying to update by index"); 305 } 306 } 307 return mSuccess; 308 } 309 310 /** 311 * Copies a raw SMS PDU to the ICC. 312 * 313 * @param callingPackage the package name of the calling app. 314 * @param status message status. One of these status: 315 * <code>STATUS_ON_ICC_READ</code> 316 * <code>STATUS_ON_ICC_UNREAD</code> 317 * <code>STATUS_ON_ICC_SENT</code> 318 * <code>STATUS_ON_ICC_UNSENT</code> 319 * @param pdu the raw PDU to store. 320 * @param smsc the SMSC for this message. Null means use default. 321 * @return true for success. Otherwise false. 322 */ 323 @UnsupportedAppUsage copyMessageToIccEf(String callingPackage, int status, byte[] pdu, byte[] smsc)324 public boolean copyMessageToIccEf(String callingPackage, int status, byte[] pdu, byte[] smsc) { 325 //NOTE smsc not used in RUIM 326 if (DBG) log("copyMessageToIccEf: status=" + status + " ==> " + 327 "pdu=("+ Arrays.toString(pdu) + 328 "), smsc=(" + Arrays.toString(smsc) +")"); 329 enforceReceiveAndSend("Copying message to Icc"); 330 enforceNotOnHandlerThread("copyMessageToIccEf"); 331 if (mAppOps.noteOp(AppOpsManager.OPSTR_WRITE_ICC_SMS, Binder.getCallingUid(), 332 callingPackage) != AppOpsManager.MODE_ALLOWED) { 333 return false; 334 } 335 synchronized(mLock) { 336 mSuccess = false; 337 Message response = mHandler.obtainMessage(EVENT_UPDATE_DONE); 338 339 //RIL_REQUEST_WRITE_SMS_TO_SIM vs RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM 340 if (PhoneConstants.PHONE_TYPE_GSM == mPhone.getPhoneType()) { 341 mPhone.mCi.writeSmsToSim(status, IccUtils.bytesToHexString(smsc), 342 IccUtils.bytesToHexString(pdu), response); 343 } else { 344 mPhone.mCi.writeSmsToRuim(status, pdu, response); 345 } 346 347 try { 348 mLock.wait(); 349 } catch (InterruptedException e) { 350 loge("interrupted while trying to update by index"); 351 } 352 } 353 return mSuccess; 354 } 355 356 /** 357 * Retrieves all messages currently stored on Icc. 358 * 359 * @return list of SmsRawData of all sms on Icc 360 */ 361 362 @UnsupportedAppUsage getAllMessagesFromIccEf(String callingPackage)363 public List<SmsRawData> getAllMessagesFromIccEf(String callingPackage) { 364 if (DBG) log("getAllMessagesFromEF"); 365 366 mContext.enforceCallingOrSelfPermission( 367 Manifest.permission.RECEIVE_SMS, 368 "Reading messages from Icc"); 369 enforceNotOnHandlerThread("getAllMessagesFromIccEf"); 370 if (mAppOps.noteOp(AppOpsManager.OPSTR_READ_ICC_SMS, Binder.getCallingUid(), 371 callingPackage) != AppOpsManager.MODE_ALLOWED) { 372 return new ArrayList<SmsRawData>(); 373 } 374 synchronized(mLock) { 375 376 IccFileHandler fh = mPhone.getIccFileHandler(); 377 if (fh == null) { 378 loge("Cannot load Sms records. No icc card?"); 379 mSms = null; 380 return mSms; 381 } 382 383 Message response = mHandler.obtainMessage(EVENT_LOAD_DONE); 384 fh.loadEFLinearFixedAll(IccConstants.EF_SMS, response); 385 386 try { 387 mLock.wait(); 388 } catch (InterruptedException e) { 389 loge("interrupted while trying to load from the Icc"); 390 } 391 } 392 return mSms; 393 } 394 395 /** 396 * A permissions check before passing to {@link IccSmsInterfaceManager#sendDataInternal}. 397 * This method checks if the calling package or itself has the permission to send the data sms. 398 */ sendDataWithSelfPermissions(String callingPackage, String callingAttributionTag, String destAddr, String scAddr, int destPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean isForVvm)399 public void sendDataWithSelfPermissions(String callingPackage, String callingAttributionTag, 400 String destAddr, String scAddr, int destPort, byte[] data, PendingIntent sentIntent, 401 PendingIntent deliveryIntent, boolean isForVvm) { 402 if (!mSmsPermissions.checkCallingOrSelfCanSendSms(callingPackage, callingAttributionTag, 403 "Sending SMS message")) { 404 returnUnspecifiedFailure(sentIntent); 405 return; 406 } 407 sendDataInternal(callingPackage, destAddr, scAddr, destPort, data, sentIntent, 408 deliveryIntent, isForVvm); 409 } 410 411 /** 412 * @deprecated Use {@link #sendData(String, String, String, String, int, byte[], PendingIntent, 413 * PendingIntent)} instead. 414 */ 415 @Deprecated 416 @UnsupportedAppUsage sendData(String callingPackage, String destAddr, String scAddr, int destPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent)417 public void sendData(String callingPackage, String destAddr, String scAddr, int destPort, 418 byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) { 419 sendData(callingPackage, null, destAddr, scAddr, destPort, data, 420 sentIntent, deliveryIntent); 421 } 422 423 /** 424 * A permissions check before passing to {@link IccSmsInterfaceManager#sendDataInternal}. 425 * This method checks only if the calling package has the permission to send the data sms. 426 */ sendData(String callingPackage, String callingAttributionTag, String destAddr, String scAddr, int destPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent)427 public void sendData(String callingPackage, String callingAttributionTag, 428 String destAddr, String scAddr, int destPort, byte[] data, PendingIntent sentIntent, 429 PendingIntent deliveryIntent) { 430 if (!mSmsPermissions.checkCallingCanSendSms(callingPackage, callingAttributionTag, 431 "Sending SMS message")) { 432 returnUnspecifiedFailure(sentIntent); 433 return; 434 } 435 sendDataInternal(callingPackage, destAddr, scAddr, destPort, data, sentIntent, 436 deliveryIntent, false /* isForVvm */); 437 } 438 439 /** 440 * Send a data based SMS to a specific application port. 441 * 442 * @param callingPackage the package name of the calling app 443 * @param destAddr the address to send the message to 444 * @param scAddr is the service center address or null to use 445 * the current default SMSC 446 * @param destPort the port to deliver the message to 447 * @param data the body of the message to send 448 * @param sentIntent if not NULL this <code>PendingIntent</code> is 449 * broadcast when the message is successfully sent, or failed. 450 * The result code will be <code>Activity.RESULT_OK<code> for success, 451 * or one of these errors:<br> 452 * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> 453 * <code>RESULT_ERROR_RADIO_OFF</code><br> 454 * <code>RESULT_ERROR_NULL_PDU</code><br> 455 * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include 456 * the extra "errorCode" containing a radio technology specific value, 457 * generally only useful for troubleshooting.<br> 458 * The per-application based SMS control checks sentIntent. If sentIntent 459 * is NULL the caller will be checked against all unknown applications, 460 * which cause smaller number of SMS to be sent in checking period. 461 * @param deliveryIntent if not NULL this <code>PendingIntent</code> is 462 * broadcast when the message is delivered to the recipient. The 463 * raw pdu of the status report is in the extended data ("pdu"). 464 */ 465 sendDataInternal(String callingPackage, String destAddr, String scAddr, int destPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean isForVvm)466 private void sendDataInternal(String callingPackage, String destAddr, String scAddr, 467 int destPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent, 468 boolean isForVvm) { 469 if (Rlog.isLoggable("SMS", Log.VERBOSE)) { 470 log("sendData: destAddr=" + destAddr + " scAddr=" + scAddr + " destPort=" 471 + destPort + " data='" + HexDump.toHexString(data) + "' sentIntent=" 472 + sentIntent + " deliveryIntent=" + deliveryIntent + " isForVVM=" + isForVvm); 473 } 474 destAddr = filterDestAddress(destAddr); 475 mDispatchersController.sendData(callingPackage, destAddr, scAddr, destPort, data, 476 sentIntent, deliveryIntent, isForVvm); 477 } 478 479 /** 480 * A permissions check before passing to {@link IccSmsInterfaceManager#sendTextInternal}. 481 * This method checks only if the calling package has the permission to send the sms. 482 * Note: SEND_SMS permission should be checked by the caller of this method 483 */ sendText(String callingPackage, String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean persistMessageForNonDefaultSmsApp)484 public void sendText(String callingPackage, String destAddr, String scAddr, 485 String text, PendingIntent sentIntent, PendingIntent deliveryIntent, 486 boolean persistMessageForNonDefaultSmsApp) { 487 sendTextInternal(callingPackage, destAddr, scAddr, text, sentIntent, deliveryIntent, 488 persistMessageForNonDefaultSmsApp, SMS_MESSAGE_PRIORITY_NOT_SPECIFIED, 489 false /* expectMore */, SMS_MESSAGE_PERIOD_NOT_SPECIFIED, false /* isForVvm */); 490 } 491 492 /** 493 * A permissions check before passing to {@link IccSmsInterfaceManager#sendTextInternal}. 494 * This method checks if the calling package or itself has the permission to send the sms. 495 */ sendTextWithSelfPermissions(String callingPackage, String callingAttributeTag, String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean persistMessage, boolean isForVvm)496 public void sendTextWithSelfPermissions(String callingPackage, String callingAttributeTag, 497 String destAddr, String scAddr, String text, PendingIntent sentIntent, 498 PendingIntent deliveryIntent, boolean persistMessage, boolean isForVvm) { 499 if (!mSmsPermissions.checkCallingOrSelfCanSendSms(callingPackage, callingAttributeTag, 500 "Sending SMS message")) { 501 returnUnspecifiedFailure(sentIntent); 502 return; 503 } 504 sendTextInternal(callingPackage, destAddr, scAddr, text, sentIntent, deliveryIntent, 505 persistMessage, SMS_MESSAGE_PRIORITY_NOT_SPECIFIED, false /* expectMore */, 506 SMS_MESSAGE_PERIOD_NOT_SPECIFIED, isForVvm); 507 } 508 509 /** 510 * Send a text based SMS. 511 * 512 * @param destAddr the address to send the message to 513 * @param scAddr is the service center address or null to use 514 * the current default SMSC 515 * @param text the body of the message to send 516 * @param sentIntent if not NULL this <code>PendingIntent</code> is 517 * broadcast when the message is successfully sent, or failed. 518 * The result code will be <code>Activity.RESULT_OK<code> for success, 519 * or one of these errors:<br> 520 * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> 521 * <code>RESULT_ERROR_RADIO_OFF</code><br> 522 * <code>RESULT_ERROR_NULL_PDU</code><br> 523 * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include 524 * the extra "errorCode" containing a radio technology specific value, 525 * generally only useful for troubleshooting.<br> 526 * The per-application based SMS control checks sentIntent. If sentIntent 527 * is NULL the caller will be checked against all unknown applications, 528 * which cause smaller number of SMS to be sent in checking period. 529 * @param deliveryIntent if not NULL this <code>PendingIntent</code> is 530 * broadcast when the message is delivered to the recipient. The 531 * raw pdu of the status report is in the extended data ("pdu"). 532 * @param persistMessageForNonDefaultSmsApp whether the sent message should 533 * be automatically persisted in the SMS db. It only affects messages sent 534 * by a non-default SMS app. Currently only the carrier app can set this 535 * parameter to false to skip auto message persistence. 536 * @param priority Priority level of the message 537 * Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1 538 * --------------------------------- 539 * PRIORITY | Level of Priority 540 * --------------------------------- 541 * '00' | Normal 542 * '01' | Interactive 543 * '10' | Urgent 544 * '11' | Emergency 545 * ---------------------------------- 546 * Any Other values including negative considered as Invalid Priority Indicator of the message. 547 * @param expectMore is a boolean to indicate the sending messages through same link or not. 548 * @param validityPeriod Validity Period of the message in mins. 549 * Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1. 550 * Validity Period(Minimum) -> 5 mins 551 * Validity Period(Maximum) -> 635040 mins(i.e.63 weeks). 552 * Any Other values including negative considered as Invalid Validity Period of the message. 553 */ 554 sendTextInternal(String callingPackage, String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean persistMessageForNonDefaultSmsApp, int priority, boolean expectMore, int validityPeriod, boolean isForVvm)555 private void sendTextInternal(String callingPackage, String destAddr, String scAddr, 556 String text, PendingIntent sentIntent, PendingIntent deliveryIntent, 557 boolean persistMessageForNonDefaultSmsApp, int priority, boolean expectMore, 558 int validityPeriod, boolean isForVvm) { 559 if (Rlog.isLoggable("SMS", Log.VERBOSE)) { 560 log("sendText: destAddr=" + destAddr + " scAddr=" + scAddr 561 + " text='" + text + "' sentIntent=" + sentIntent + " deliveryIntent=" 562 + deliveryIntent + " priority=" + priority + " expectMore=" + expectMore 563 + " validityPeriod=" + validityPeriod + " isForVVM=" + isForVvm); 564 } 565 notifyIfOutgoingEmergencySms(destAddr); 566 destAddr = filterDestAddress(destAddr); 567 mDispatchersController.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent, 568 null/*messageUri*/, callingPackage, persistMessageForNonDefaultSmsApp, 569 priority, expectMore, validityPeriod, isForVvm); 570 } 571 572 /** 573 * Send a text based SMS with Messaging Options. 574 * 575 * @param destAddr the address to send the message to 576 * @param scAddr is the service center address or null to use 577 * the current default SMSC 578 * @param text the body of the message to send 579 * @param sentIntent if not NULL this <code>PendingIntent</code> is 580 * broadcast when the message is successfully sent, or failed. 581 * The result code will be <code>Activity.RESULT_OK<code> for success, 582 * or one of these errors:<br> 583 * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> 584 * <code>RESULT_ERROR_RADIO_OFF</code><br> 585 * <code>RESULT_ERROR_NULL_PDU</code><br> 586 * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include 587 * the extra "errorCode" containing a radio technology specific value, 588 * generally only useful for troubleshooting.<br> 589 * The per-application based SMS control checks sentIntent. If sentIntent 590 * is NULL the caller will be checked against all unknown applications, 591 * which cause smaller number of SMS to be sent in checking period. 592 * @param deliveryIntent if not NULL this <code>PendingIntent</code> is 593 * broadcast when the message is delivered to the recipient. The 594 * raw pdu of the status report is in the extended data ("pdu"). 595 * @param persistMessageForNonDefaultSmsApp whether the sent message should 596 * be automatically persisted in the SMS db. It only affects messages sent 597 * by a non-default SMS app. Currently only the carrier app can set this 598 * parameter to false to skip auto message persistence. 599 * @param priority Priority level of the message 600 * Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1 601 * --------------------------------- 602 * PRIORITY | Level of Priority 603 * --------------------------------- 604 * '00' | Normal 605 * '01' | Interactive 606 * '10' | Urgent 607 * '11' | Emergency 608 * ---------------------------------- 609 * Any Other values including negative considered as Invalid Priority Indicator of the message. 610 * @param expectMore is a boolean to indicate the sending messages through same link or not. 611 * @param validityPeriod Validity Period of the message in mins. 612 * Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1. 613 * Validity Period(Minimum) -> 5 mins 614 * Validity Period(Maximum) -> 635040 mins(i.e.63 weeks). 615 * Any Other values including negative considered as Invalid Validity Period of the message. 616 */ 617 sendTextWithOptions(String callingPackage, String callingAttributionTag, String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean persistMessageForNonDefaultSmsApp, int priority, boolean expectMore, int validityPeriod)618 public void sendTextWithOptions(String callingPackage, String callingAttributionTag, 619 String destAddr, String scAddr, String text, PendingIntent sentIntent, 620 PendingIntent deliveryIntent, boolean persistMessageForNonDefaultSmsApp, int priority, 621 boolean expectMore, int validityPeriod) { 622 if (!mSmsPermissions.checkCallingOrSelfCanSendSms(callingPackage, callingAttributionTag, 623 "Sending SMS message")) { 624 returnUnspecifiedFailure(sentIntent); 625 return; 626 } 627 sendTextInternal(callingPackage, destAddr, scAddr, text, sentIntent, deliveryIntent, 628 persistMessageForNonDefaultSmsApp, priority, expectMore, validityPeriod, 629 false /* isForVvm */); 630 } 631 632 /** 633 * Inject an SMS PDU into the android application framework. 634 * 635 * @param pdu is the byte array of pdu to be injected into android application framework 636 * @param format is the format of SMS pdu (3gpp or 3gpp2) 637 * @param receivedIntent if not NULL this <code>PendingIntent</code> is 638 * broadcast when the message is successfully received by the 639 * android application framework. This intent is broadcasted at 640 * the same time an SMS received from radio is acknowledged back. 641 */ 642 @UnsupportedAppUsage injectSmsPdu(byte[] pdu, String format, PendingIntent receivedIntent)643 public void injectSmsPdu(byte[] pdu, String format, PendingIntent receivedIntent) { 644 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE) 645 != PackageManager.PERMISSION_GRANTED) { 646 mSmsPermissions.enforceCallerIsImsAppOrCarrierApp("injectSmsPdu"); 647 } 648 649 if (Rlog.isLoggable("SMS", Log.VERBOSE)) { 650 log("pdu: " + pdu + 651 "\n format=" + format + 652 "\n receivedIntent=" + receivedIntent); 653 } 654 mDispatchersController.injectSmsPdu(pdu, format, 655 result -> { 656 if (receivedIntent != null) { 657 try { 658 receivedIntent.send(result); 659 } catch (PendingIntent.CanceledException e) { 660 loge("receivedIntent cancelled."); 661 } 662 } 663 } 664 ); 665 } 666 667 /** 668 * Send a multi-part text based SMS. 669 * 670 * @param destAddr the address to send the message to 671 * @param scAddr is the service center address or null to use 672 * the current default SMSC 673 * @param parts an <code>ArrayList</code> of strings that, in order, 674 * comprise the original message 675 * @param sentIntents if not null, an <code>ArrayList</code> of 676 * <code>PendingIntent</code>s (one for each message part) that is 677 * broadcast when the corresponding message part has been sent. 678 * The result code will be <code>Activity.RESULT_OK<code> for success, 679 * or one of these errors: 680 * <code>RESULT_ERROR_GENERIC_FAILURE</code> 681 * <code>RESULT_ERROR_RADIO_OFF</code> 682 * <code>RESULT_ERROR_NULL_PDU</code>. 683 * The per-application based SMS control checks sentIntent. If sentIntent 684 * is NULL the caller will be checked against all unknown applications, 685 * which cause smaller number of SMS to be sent in checking period. 686 * @param deliveryIntents if not null, an <code>ArrayList</code> of 687 * <code>PendingIntent</code>s (one for each message part) that is 688 * broadcast when the corresponding message part has been delivered 689 * to the recipient. The raw pdu of the status report is in the 690 * extended data ("pdu"). 691 */ 692 sendMultipartText(String callingPackage, String callingAttributionTag, String destAddr, String scAddr, List<String> parts, List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents, boolean persistMessageForNonDefaultSmsApp)693 public void sendMultipartText(String callingPackage, String callingAttributionTag, 694 String destAddr, String scAddr, List<String> parts, List<PendingIntent> sentIntents, 695 List<PendingIntent> deliveryIntents, boolean persistMessageForNonDefaultSmsApp) { 696 sendMultipartTextWithOptions(callingPackage, callingAttributionTag, destAddr, scAddr, parts, 697 sentIntents, deliveryIntents, persistMessageForNonDefaultSmsApp, 698 SMS_MESSAGE_PRIORITY_NOT_SPECIFIED, false /* expectMore */, 699 SMS_MESSAGE_PERIOD_NOT_SPECIFIED); 700 } 701 702 /** 703 * Send a multi-part text based SMS with Messaging Options. 704 * 705 * @param destAddr the address to send the message to 706 * @param scAddr is the service center address or null to use 707 * the current default SMSC 708 * @param parts an <code>ArrayList</code> of strings that, in order, 709 * comprise the original message 710 * @param sentIntents if not null, an <code>ArrayList</code> of 711 * <code>PendingIntent</code>s (one for each message part) that is 712 * broadcast when the corresponding message part has been sent. 713 * The result code will be <code>Activity.RESULT_OK<code> for success, 714 * or one of these errors: 715 * <code>RESULT_ERROR_GENERIC_FAILURE</code> 716 * <code>RESULT_ERROR_RADIO_OFF</code> 717 * <code>RESULT_ERROR_NULL_PDU</code>. 718 * The per-application based SMS control checks sentIntent. If sentIntent 719 * is NULL the caller will be checked against all unknown applications, 720 * which cause smaller number of SMS to be sent in checking period. 721 * @param deliveryIntents if not null, an <code>ArrayList</code> of 722 * <code>PendingIntent</code>s (one for each message part) that is 723 * broadcast when the corresponding message part has been delivered 724 * to the recipient. The raw pdu of the status report is in the 725 * extended data ("pdu"). 726 * @param persistMessageForNonDefaultSmsApp whether the sent message should 727 * be automatically persisted in the SMS db. It only affects messages sent 728 * by a non-default SMS app. Currently only the carrier app can set this 729 * parameter to false to skip auto message persistence. 730 * @param priority Priority level of the message 731 * Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1 732 * --------------------------------- 733 * PRIORITY | Level of Priority 734 * --------------------------------- 735 * '00' | Normal 736 * '01' | Interactive 737 * '10' | Urgent 738 * '11' | Emergency 739 * ---------------------------------- 740 * Any Other values including negative considered as Invalid Priority Indicator of the message. 741 * @param expectMore is a boolean to indicate the sending messages through same link or not. 742 * @param validityPeriod Validity Period of the message in mins. 743 * Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1. 744 * Validity Period(Minimum) -> 5 mins 745 * Validity Period(Maximum) -> 635040 mins(i.e.63 weeks). 746 * Any Other values including negative considered as Invalid Validity Period of the message. 747 */ 748 sendMultipartTextWithOptions(String callingPackage, String callingAttributionTag, String destAddr, String scAddr, List<String> parts, List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents, boolean persistMessageForNonDefaultSmsApp, int priority, boolean expectMore, int validityPeriod)749 public void sendMultipartTextWithOptions(String callingPackage, String callingAttributionTag, 750 String destAddr, String scAddr, List<String> parts, List<PendingIntent> sentIntents, 751 List<PendingIntent> deliveryIntents, boolean persistMessageForNonDefaultSmsApp, 752 int priority, boolean expectMore, int validityPeriod) { 753 if (!mSmsPermissions.checkCallingCanSendText(persistMessageForNonDefaultSmsApp, 754 callingPackage, callingAttributionTag, "Sending SMS message")) { 755 returnUnspecifiedFailure(sentIntents); 756 return; 757 } 758 if (Rlog.isLoggable("SMS", Log.VERBOSE)) { 759 int i = 0; 760 for (String part : parts) { 761 log("sendMultipartTextWithOptions: destAddr=" + destAddr + ", srAddr=" + scAddr + 762 ", part[" + (i++) + "]=" + part); 763 } 764 } 765 notifyIfOutgoingEmergencySms(destAddr); 766 destAddr = filterDestAddress(destAddr); 767 768 if (parts.size() > 1 && parts.size() < 10 && !SmsMessage.hasEmsSupport()) { 769 for (int i = 0; i < parts.size(); i++) { 770 // If EMS is not supported, we have to break down EMS into single segment SMS 771 // and add page info " x/y". 772 String singlePart = parts.get(i); 773 if (SmsMessage.shouldAppendPageNumberAsPrefix()) { 774 singlePart = String.valueOf(i + 1) + '/' + parts.size() + ' ' + singlePart; 775 } else { 776 singlePart = singlePart.concat(' ' + String.valueOf(i + 1) + '/' 777 + parts.size()); 778 } 779 780 PendingIntent singleSentIntent = null; 781 if (sentIntents != null && sentIntents.size() > i) { 782 singleSentIntent = sentIntents.get(i); 783 } 784 785 PendingIntent singleDeliveryIntent = null; 786 if (deliveryIntents != null && deliveryIntents.size() > i) { 787 singleDeliveryIntent = deliveryIntents.get(i); 788 } 789 790 mDispatchersController.sendText(destAddr, scAddr, singlePart, singleSentIntent, 791 singleDeliveryIntent, null /* messageUri */, callingPackage, 792 persistMessageForNonDefaultSmsApp, priority, expectMore, validityPeriod, 793 false /* isForVvm */); 794 } 795 return; 796 } 797 798 mDispatchersController.sendMultipartText(destAddr, 799 scAddr, 800 (ArrayList<String>) parts, 801 (ArrayList<PendingIntent>) sentIntents, 802 (ArrayList<PendingIntent>) deliveryIntents, 803 null, callingPackage, persistMessageForNonDefaultSmsApp, 804 priority, expectMore, validityPeriod); 805 806 } 807 808 @UnsupportedAppUsage getPremiumSmsPermission(String packageName)809 public int getPremiumSmsPermission(String packageName) { 810 return mDispatchersController.getPremiumSmsPermission(packageName); 811 } 812 813 814 @UnsupportedAppUsage setPremiumSmsPermission(String packageName, int permission)815 public void setPremiumSmsPermission(String packageName, int permission) { 816 mDispatchersController.setPremiumSmsPermission(packageName, permission); 817 } 818 819 /** 820 * create SmsRawData lists from all sms record byte[] 821 * Use null to indicate "free" record 822 * 823 * @param messages List of message records from EF_SMS. 824 * @return SmsRawData list of all in-used records 825 */ buildValidRawData(ArrayList<byte[]> messages)826 protected ArrayList<SmsRawData> buildValidRawData(ArrayList<byte[]> messages) { 827 int count = messages.size(); 828 ArrayList<SmsRawData> ret; 829 830 ret = new ArrayList<SmsRawData>(count); 831 832 for (int i = 0; i < count; i++) { 833 byte[] ba = messages.get(i); 834 if ((ba[0] & 0x01) == STATUS_ON_ICC_FREE) { 835 ret.add(null); 836 } else { 837 ret.add(new SmsRawData(messages.get(i))); 838 } 839 } 840 841 return ret; 842 } 843 844 /** 845 * Generates an EF_SMS record from status and raw PDU. 846 * 847 * @param status Message status. See TS 51.011 10.5.3. 848 * @param pdu Raw message PDU. 849 * @return byte array for the record. 850 */ makeSmsRecordData(int status, byte[] pdu)851 protected byte[] makeSmsRecordData(int status, byte[] pdu) { 852 byte[] data; 853 if (PhoneConstants.PHONE_TYPE_GSM == mPhone.getPhoneType()) { 854 data = new byte[SmsManager.SMS_RECORD_LENGTH]; 855 } else { 856 data = new byte[SmsManager.CDMA_SMS_RECORD_LENGTH]; 857 } 858 859 // Status bits for this record. See TS 51.011 10.5.3 860 data[0] = (byte) (status & 0x07); 861 862 System.arraycopy(pdu, 0, data, 1, pdu.length); 863 864 // Pad out with 0xFF's. 865 for (int j = pdu.length+1; j < data.length; j++) { 866 data[j] = -1; 867 } 868 869 return data; 870 } 871 872 /** 873 * Gets the SMSC address from (U)SIM. 874 * 875 * @return the SMSC address string, null if failed. 876 */ getSmscAddressFromIccEf(String callingPackage)877 public String getSmscAddressFromIccEf(String callingPackage) { 878 if (!mSmsPermissions.checkCallingOrSelfCanGetSmscAddress( 879 callingPackage, "getSmscAddressFromIccEf")) { 880 return null; 881 } 882 enforceNotOnHandlerThread("getSmscAddressFromIccEf"); 883 synchronized (mLock) { 884 mSmsc = null; 885 Message response = mHandler.obtainMessage(EVENT_GET_SMSC_DONE); 886 mPhone.mCi.getSmscAddress(response); 887 try { 888 mLock.wait(); 889 } catch (InterruptedException e) { 890 loge("interrupted while trying to read SMSC"); 891 } 892 } 893 return mSmsc; 894 } 895 896 /** 897 * Sets the SMSC address on (U)SIM. 898 * 899 * @param smsc the SMSC address string. 900 * @return true for success, false otherwise. 901 */ setSmscAddressOnIccEf(String callingPackage, String smsc)902 public boolean setSmscAddressOnIccEf(String callingPackage, String smsc) { 903 if (!mSmsPermissions.checkCallingOrSelfCanSetSmscAddress( 904 callingPackage, "setSmscAddressOnIccEf")) { 905 return false; 906 } 907 synchronized (mLock) { 908 mSuccess = false; 909 Message response = mHandler.obtainMessage(EVENT_SET_SMSC_DONE); 910 mPhone.mCi.setSmscAddress(smsc, response); 911 try { 912 mLock.wait(); 913 } catch (InterruptedException e) { 914 loge("interrupted while trying to write SMSC"); 915 } 916 } 917 return mSuccess; 918 } 919 enableCellBroadcast(int messageIdentifier, int ranType)920 public boolean enableCellBroadcast(int messageIdentifier, int ranType) { 921 return enableCellBroadcastRange(messageIdentifier, messageIdentifier, ranType); 922 } 923 disableCellBroadcast(int messageIdentifier, int ranType)924 public boolean disableCellBroadcast(int messageIdentifier, int ranType) { 925 return disableCellBroadcastRange(messageIdentifier, messageIdentifier, ranType); 926 } 927 enableCellBroadcastRange(int startMessageId, int endMessageId, int ranType)928 public boolean enableCellBroadcastRange(int startMessageId, int endMessageId, int ranType) { 929 mContext.enforceCallingPermission("android.permission.RECEIVE_EMERGENCY_BROADCAST", 930 "enabling cell broadcast range [" + startMessageId + "-" + endMessageId + "]. " 931 + "ranType=" + ranType); 932 if (ranType == SmsCbMessage.MESSAGE_FORMAT_3GPP) { 933 return enableGsmBroadcastRange(startMessageId, endMessageId); 934 } else if (ranType == SmsCbMessage.MESSAGE_FORMAT_3GPP2) { 935 return enableCdmaBroadcastRange(startMessageId, endMessageId); 936 } else { 937 throw new IllegalArgumentException("Not a supported RAN Type"); 938 } 939 } 940 disableCellBroadcastRange(int startMessageId, int endMessageId, int ranType)941 public boolean disableCellBroadcastRange(int startMessageId, int endMessageId, int ranType) { 942 mContext.enforceCallingPermission("android.permission.RECEIVE_EMERGENCY_BROADCAST", 943 "disabling cell broadcast range [" + startMessageId + "-" + endMessageId 944 + "]. ranType=" + ranType); 945 if (ranType == SmsCbMessage.MESSAGE_FORMAT_3GPP) { 946 return disableGsmBroadcastRange(startMessageId, endMessageId); 947 } else if (ranType == SmsCbMessage.MESSAGE_FORMAT_3GPP2) { 948 return disableCdmaBroadcastRange(startMessageId, endMessageId); 949 } else { 950 throw new IllegalArgumentException("Not a supported RAN Type"); 951 } 952 } 953 954 @UnsupportedAppUsage enableGsmBroadcastRange(int startMessageId, int endMessageId)955 synchronized public boolean enableGsmBroadcastRange(int startMessageId, int endMessageId) { 956 957 mContext.enforceCallingPermission( 958 "android.permission.RECEIVE_SMS", 959 "Enabling cell broadcast SMS"); 960 961 String client = mContext.getPackageManager().getNameForUid( 962 Binder.getCallingUid()); 963 964 String msg; 965 if (!mCellBroadcastRangeManager.enableRange(startMessageId, endMessageId, client)) { 966 msg = "Failed to add GSM cell broadcast channels range " + startMessageId 967 + " to " + endMessageId; 968 log(msg); 969 mCellBroadcastLocalLog.log(msg); 970 return false; 971 } 972 973 if (DBG) { 974 msg = "Added GSM cell broadcast channels range " + startMessageId 975 + " to " + endMessageId; 976 log(msg); 977 mCellBroadcastLocalLog.log(msg); 978 } 979 980 setCellBroadcastActivation(!mCellBroadcastRangeManager.isEmpty()); 981 982 return true; 983 } 984 985 @UnsupportedAppUsage disableGsmBroadcastRange(int startMessageId, int endMessageId)986 synchronized public boolean disableGsmBroadcastRange(int startMessageId, int endMessageId) { 987 988 mContext.enforceCallingPermission( 989 "android.permission.RECEIVE_SMS", 990 "Disabling cell broadcast SMS"); 991 992 String client = mContext.getPackageManager().getNameForUid( 993 Binder.getCallingUid()); 994 995 String msg; 996 if (!mCellBroadcastRangeManager.disableRange(startMessageId, endMessageId, client)) { 997 msg = "Failed to remove GSM cell broadcast channels range " + startMessageId 998 + " to " + endMessageId; 999 log(msg); 1000 mCellBroadcastLocalLog.log(msg); 1001 return false; 1002 } 1003 1004 if (DBG) { 1005 msg = "Removed GSM cell broadcast channels range " + startMessageId 1006 + " to " + endMessageId; 1007 log(msg); 1008 mCellBroadcastLocalLog.log(msg); 1009 } 1010 1011 setCellBroadcastActivation(!mCellBroadcastRangeManager.isEmpty()); 1012 1013 return true; 1014 } 1015 1016 @UnsupportedAppUsage enableCdmaBroadcastRange(int startMessageId, int endMessageId)1017 synchronized public boolean enableCdmaBroadcastRange(int startMessageId, int endMessageId) { 1018 1019 mContext.enforceCallingPermission( 1020 "android.permission.RECEIVE_SMS", 1021 "Enabling cdma broadcast SMS"); 1022 1023 String client = mContext.getPackageManager().getNameForUid( 1024 Binder.getCallingUid()); 1025 1026 String msg; 1027 if (!mCdmaBroadcastRangeManager.enableRange(startMessageId, endMessageId, client)) { 1028 msg = "Failed to add cdma broadcast channels range " + startMessageId + " to " 1029 + endMessageId; 1030 log(msg); 1031 mCellBroadcastLocalLog.log(msg); 1032 return false; 1033 } 1034 1035 if (DBG) { 1036 msg = "Added cdma broadcast channels range " + startMessageId + " to " + endMessageId; 1037 log(msg); 1038 mCellBroadcastLocalLog.log(msg); 1039 } 1040 1041 setCdmaBroadcastActivation(!mCdmaBroadcastRangeManager.isEmpty()); 1042 1043 return true; 1044 } 1045 1046 @UnsupportedAppUsage disableCdmaBroadcastRange(int startMessageId, int endMessageId)1047 synchronized public boolean disableCdmaBroadcastRange(int startMessageId, int endMessageId) { 1048 1049 mContext.enforceCallingPermission( 1050 "android.permission.RECEIVE_SMS", 1051 "Disabling cell broadcast SMS"); 1052 1053 String client = mContext.getPackageManager().getNameForUid( 1054 Binder.getCallingUid()); 1055 1056 String msg; 1057 if (!mCdmaBroadcastRangeManager.disableRange(startMessageId, endMessageId, client)) { 1058 msg = "Failed to remove cdma broadcast channels range " + startMessageId + " to " 1059 + endMessageId; 1060 log(msg); 1061 mCellBroadcastLocalLog.log(msg); 1062 return false; 1063 } 1064 1065 if (DBG) { 1066 msg = "Removed cdma broadcast channels range " + startMessageId + " to " + endMessageId; 1067 log(msg); 1068 mCellBroadcastLocalLog.log(msg); 1069 } 1070 1071 setCdmaBroadcastActivation(!mCdmaBroadcastRangeManager.isEmpty()); 1072 1073 return true; 1074 } 1075 1076 class CellBroadcastRangeManager extends IntRangeManager { 1077 private ArrayList<SmsBroadcastConfigInfo> mConfigList = 1078 new ArrayList<SmsBroadcastConfigInfo>(); 1079 1080 /** 1081 * Called when the list of enabled ranges has changed. This will be 1082 * followed by zero or more calls to {@link #addRange} followed by 1083 * a call to {@link #finishUpdate}. 1084 */ startUpdate()1085 protected void startUpdate() { 1086 mConfigList.clear(); 1087 } 1088 1089 /** 1090 * Called after {@link #startUpdate} to indicate a range of enabled 1091 * values. 1092 * @param startId the first id included in the range 1093 * @param endId the last id included in the range 1094 */ addRange(int startId, int endId, boolean selected)1095 protected void addRange(int startId, int endId, boolean selected) { 1096 mConfigList.add(new SmsBroadcastConfigInfo(startId, endId, 1097 SMS_CB_CODE_SCHEME_MIN, SMS_CB_CODE_SCHEME_MAX, selected)); 1098 } 1099 1100 /** 1101 * Called to indicate the end of a range update started by the 1102 * previous call to {@link #startUpdate}. 1103 * @return true if successful, false otherwise 1104 */ finishUpdate()1105 protected boolean finishUpdate() { 1106 if (mConfigList.isEmpty()) { 1107 return true; 1108 } else { 1109 SmsBroadcastConfigInfo[] configs = 1110 mConfigList.toArray(new SmsBroadcastConfigInfo[mConfigList.size()]); 1111 return setCellBroadcastConfig(configs); 1112 } 1113 } 1114 } 1115 1116 class CdmaBroadcastRangeManager extends IntRangeManager { 1117 private ArrayList<CdmaSmsBroadcastConfigInfo> mConfigList = 1118 new ArrayList<CdmaSmsBroadcastConfigInfo>(); 1119 1120 /** 1121 * Called when the list of enabled ranges has changed. This will be 1122 * followed by zero or more calls to {@link #addRange} followed by a 1123 * call to {@link #finishUpdate}. 1124 */ startUpdate()1125 protected void startUpdate() { 1126 mConfigList.clear(); 1127 } 1128 1129 /** 1130 * Called after {@link #startUpdate} to indicate a range of enabled 1131 * values. 1132 * @param startId the first id included in the range 1133 * @param endId the last id included in the range 1134 */ addRange(int startId, int endId, boolean selected)1135 protected void addRange(int startId, int endId, boolean selected) { 1136 mConfigList.add(new CdmaSmsBroadcastConfigInfo(startId, endId, 1137 1, selected)); 1138 } 1139 1140 /** 1141 * Called to indicate the end of a range update started by the previous 1142 * call to {@link #startUpdate}. 1143 * @return true if successful, false otherwise 1144 */ finishUpdate()1145 protected boolean finishUpdate() { 1146 if (mConfigList.isEmpty()) { 1147 return true; 1148 } else { 1149 CdmaSmsBroadcastConfigInfo[] configs = 1150 mConfigList.toArray(new CdmaSmsBroadcastConfigInfo[mConfigList.size()]); 1151 return setCdmaBroadcastConfig(configs); 1152 } 1153 } 1154 } 1155 1156 @UnsupportedAppUsage setCellBroadcastConfig(SmsBroadcastConfigInfo[] configs)1157 private boolean setCellBroadcastConfig(SmsBroadcastConfigInfo[] configs) { 1158 if (DBG) { 1159 log("Calling setGsmBroadcastConfig with " + configs.length + " configurations"); 1160 } 1161 enforceNotOnHandlerThread("setCellBroadcastConfig"); 1162 synchronized (mLock) { 1163 Message response = mHandler.obtainMessage(EVENT_SET_BROADCAST_CONFIG_DONE); 1164 1165 mSuccess = false; 1166 mPhone.mCi.setGsmBroadcastConfig(configs, response); 1167 1168 try { 1169 mLock.wait(); 1170 } catch (InterruptedException e) { 1171 loge("interrupted while trying to set cell broadcast config"); 1172 } 1173 } 1174 1175 return mSuccess; 1176 } 1177 setCellBroadcastActivation(boolean activate)1178 private boolean setCellBroadcastActivation(boolean activate) { 1179 if (DBG) { 1180 log("Calling setCellBroadcastActivation(" + activate + ')'); 1181 } 1182 1183 enforceNotOnHandlerThread("setCellBroadcastConfig"); 1184 synchronized (mLock) { 1185 Message response = mHandler.obtainMessage(EVENT_SET_BROADCAST_ACTIVATION_DONE); 1186 1187 mSuccess = false; 1188 mPhone.mCi.setGsmBroadcastActivation(activate, response); 1189 1190 try { 1191 mLock.wait(); 1192 } catch (InterruptedException e) { 1193 loge("interrupted while trying to set cell broadcast activation"); 1194 } 1195 } 1196 1197 return mSuccess; 1198 } 1199 1200 @UnsupportedAppUsage setCdmaBroadcastConfig(CdmaSmsBroadcastConfigInfo[] configs)1201 private boolean setCdmaBroadcastConfig(CdmaSmsBroadcastConfigInfo[] configs) { 1202 if (DBG) { 1203 log("Calling setCdmaBroadcastConfig with " + configs.length + " configurations"); 1204 } 1205 1206 enforceNotOnHandlerThread("setCdmaBroadcastConfig"); 1207 synchronized (mLock) { 1208 Message response = mHandler.obtainMessage(EVENT_SET_BROADCAST_CONFIG_DONE); 1209 1210 mSuccess = false; 1211 mPhone.mCi.setCdmaBroadcastConfig(configs, response); 1212 1213 try { 1214 mLock.wait(); 1215 } catch (InterruptedException e) { 1216 loge("interrupted while trying to set cdma broadcast config"); 1217 } 1218 } 1219 1220 return mSuccess; 1221 } 1222 setCdmaBroadcastActivation(boolean activate)1223 private boolean setCdmaBroadcastActivation(boolean activate) { 1224 if (DBG) { 1225 log("Calling setCdmaBroadcastActivation(" + activate + ")"); 1226 } 1227 1228 enforceNotOnHandlerThread("setCdmaBroadcastActivation"); 1229 synchronized (mLock) { 1230 Message response = mHandler.obtainMessage(EVENT_SET_BROADCAST_ACTIVATION_DONE); 1231 1232 mSuccess = false; 1233 mPhone.mCi.setCdmaBroadcastActivation(activate, response); 1234 1235 try { 1236 mLock.wait(); 1237 } catch (InterruptedException e) { 1238 loge("interrupted while trying to set cdma broadcast activation"); 1239 } 1240 } 1241 1242 return mSuccess; 1243 } 1244 1245 @UnsupportedAppUsage log(String msg)1246 protected void log(String msg) { 1247 Rlog.d(LOG_TAG, msg); 1248 } 1249 loge(String msg)1250 protected void loge(String msg) { 1251 Rlog.e(LOG_TAG, msg); 1252 } 1253 loge(String msg, Throwable e)1254 protected void loge(String msg, Throwable e) { 1255 Rlog.e(LOG_TAG, msg, e); 1256 } 1257 1258 @UnsupportedAppUsage isImsSmsSupported()1259 public boolean isImsSmsSupported() { 1260 return mDispatchersController.isIms(); 1261 } 1262 1263 @UnsupportedAppUsage getImsSmsFormat()1264 public String getImsSmsFormat() { 1265 return mDispatchersController.getImsSmsFormat(); 1266 } 1267 1268 /** 1269 * @deprecated Use {@link #sendStoredText(String, String, Uri, String, PendingIntent, 1270 * PendingIntent)} instead 1271 */ 1272 @Deprecated 1273 @UnsupportedAppUsage sendStoredText(String callingPkg, Uri messageUri, String scAddress, PendingIntent sentIntent, PendingIntent deliveryIntent)1274 public void sendStoredText(String callingPkg, Uri messageUri, String scAddress, 1275 PendingIntent sentIntent, PendingIntent deliveryIntent) { 1276 sendStoredText(callingPkg, null, messageUri, scAddress, sentIntent, deliveryIntent); 1277 } 1278 sendStoredText(String callingPkg, String callingAttributionTag, Uri messageUri, String scAddress, PendingIntent sentIntent, PendingIntent deliveryIntent)1279 public void sendStoredText(String callingPkg, String callingAttributionTag, 1280 Uri messageUri, String scAddress, PendingIntent sentIntent, 1281 PendingIntent deliveryIntent) { 1282 if (!mSmsPermissions.checkCallingCanSendSms(callingPkg, callingAttributionTag, 1283 "Sending SMS message")) { 1284 returnUnspecifiedFailure(sentIntent); 1285 return; 1286 } 1287 if (Rlog.isLoggable("SMS", Log.VERBOSE)) { 1288 log("sendStoredText: scAddr=" + scAddress + " messageUri=" + messageUri 1289 + " sentIntent=" + sentIntent + " deliveryIntent=" + deliveryIntent); 1290 } 1291 final ContentResolver resolver = mContext.getContentResolver(); 1292 if (!isFailedOrDraft(resolver, messageUri)) { 1293 loge("sendStoredText: not FAILED or DRAFT message"); 1294 returnUnspecifiedFailure(sentIntent); 1295 return; 1296 } 1297 final String[] textAndAddress = loadTextAndAddress(resolver, messageUri); 1298 if (textAndAddress == null) { 1299 loge("sendStoredText: can not load text"); 1300 returnUnspecifiedFailure(sentIntent); 1301 return; 1302 } 1303 notifyIfOutgoingEmergencySms(textAndAddress[1]); 1304 textAndAddress[1] = filterDestAddress(textAndAddress[1]); 1305 mDispatchersController.sendText(textAndAddress[1], scAddress, textAndAddress[0], 1306 sentIntent, deliveryIntent, messageUri, callingPkg, 1307 true /* persistMessageForNonDefaultSmsApp */, SMS_MESSAGE_PRIORITY_NOT_SPECIFIED, 1308 false /* expectMore */, SMS_MESSAGE_PERIOD_NOT_SPECIFIED, false /* isForVvm */); 1309 } 1310 1311 /** 1312 * @deprecated Use {@link #sendStoredMultipartText(String, String, Uri, String, List, List)} 1313 * instead 1314 */ 1315 @Deprecated 1316 @UnsupportedAppUsage sendStoredMultipartText(String callingPkg, Uri messageUri, String scAddress, List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents)1317 public void sendStoredMultipartText(String callingPkg, Uri messageUri, String scAddress, 1318 List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) { 1319 sendStoredMultipartText(callingPkg, null, messageUri, scAddress, sentIntents, 1320 deliveryIntents); 1321 } 1322 sendStoredMultipartText(String callingPkg, String callingAttributionTag, Uri messageUri, String scAddress, List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents)1323 public void sendStoredMultipartText(String callingPkg, 1324 String callingAttributionTag, Uri messageUri, String scAddress, 1325 List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) { 1326 if (!mSmsPermissions.checkCallingCanSendSms(callingPkg, callingAttributionTag, 1327 "Sending SMS message")) { 1328 returnUnspecifiedFailure(sentIntents); 1329 return; 1330 } 1331 final ContentResolver resolver = mContext.getContentResolver(); 1332 if (!isFailedOrDraft(resolver, messageUri)) { 1333 loge("sendStoredMultipartText: not FAILED or DRAFT message"); 1334 returnUnspecifiedFailure(sentIntents); 1335 return; 1336 } 1337 final String[] textAndAddress = loadTextAndAddress(resolver, messageUri); 1338 if (textAndAddress == null) { 1339 loge("sendStoredMultipartText: can not load text"); 1340 returnUnspecifiedFailure(sentIntents); 1341 return; 1342 } 1343 final ArrayList<String> parts = SmsManager.getDefault().divideMessage(textAndAddress[0]); 1344 if (parts == null || parts.size() < 1) { 1345 loge("sendStoredMultipartText: can not divide text"); 1346 returnUnspecifiedFailure(sentIntents); 1347 return; 1348 } 1349 notifyIfOutgoingEmergencySms(textAndAddress[1]); 1350 textAndAddress[1] = filterDestAddress(textAndAddress[1]); 1351 1352 if (parts.size() > 1 && parts.size() < 10 && !SmsMessage.hasEmsSupport()) { 1353 for (int i = 0; i < parts.size(); i++) { 1354 // If EMS is not supported, we have to break down EMS into single segment SMS 1355 // and add page info " x/y". 1356 String singlePart = parts.get(i); 1357 if (SmsMessage.shouldAppendPageNumberAsPrefix()) { 1358 singlePart = String.valueOf(i + 1) + '/' + parts.size() + ' ' + singlePart; 1359 } else { 1360 singlePart = singlePart.concat(' ' + String.valueOf(i + 1) + '/' 1361 + parts.size()); 1362 } 1363 1364 PendingIntent singleSentIntent = null; 1365 if (sentIntents != null && sentIntents.size() > i) { 1366 singleSentIntent = sentIntents.get(i); 1367 } 1368 1369 PendingIntent singleDeliveryIntent = null; 1370 if (deliveryIntents != null && deliveryIntents.size() > i) { 1371 singleDeliveryIntent = deliveryIntents.get(i); 1372 } 1373 1374 mDispatchersController.sendText(textAndAddress[1], scAddress, singlePart, 1375 singleSentIntent, singleDeliveryIntent, messageUri, callingPkg, 1376 true /* persistMessageForNonDefaultSmsApp */, 1377 SMS_MESSAGE_PRIORITY_NOT_SPECIFIED, 1378 false /* expectMore */, SMS_MESSAGE_PERIOD_NOT_SPECIFIED, 1379 false /* isForVvm */); 1380 } 1381 return; 1382 } 1383 1384 mDispatchersController.sendMultipartText( 1385 textAndAddress[1], // destAddress 1386 scAddress, 1387 parts, 1388 (ArrayList<PendingIntent>) sentIntents, 1389 (ArrayList<PendingIntent>) deliveryIntents, 1390 messageUri, 1391 callingPkg, 1392 true /* persistMessageForNonDefaultSmsApp */, 1393 SMS_MESSAGE_PRIORITY_NOT_SPECIFIED, 1394 false /* expectMore */, 1395 SMS_MESSAGE_PERIOD_NOT_SPECIFIED); 1396 } 1397 getSmsCapacityOnIcc()1398 public int getSmsCapacityOnIcc() { 1399 mContext.enforceCallingOrSelfPermission( 1400 android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, 1401 "getSmsCapacityOnIcc"); 1402 1403 int numberOnIcc = 0; 1404 if (mPhone.getIccRecordsLoaded()) { 1405 final UiccProfile uiccProfile = UiccController.getInstance() 1406 .getUiccProfileForPhone(mPhone.getPhoneId()); 1407 if(uiccProfile != null) { 1408 numberOnIcc = uiccProfile.getIccRecords().getSmsCapacityOnIcc(); 1409 } else { 1410 loge("uiccProfile is null"); 1411 } 1412 } else { 1413 loge("getSmsCapacityOnIcc - aborting, no icc card present."); 1414 } 1415 1416 log("getSmsCapacityOnIcc().numberOnIcc = " + numberOnIcc); 1417 return numberOnIcc; 1418 } 1419 isFailedOrDraft(ContentResolver resolver, Uri messageUri)1420 private boolean isFailedOrDraft(ContentResolver resolver, Uri messageUri) { 1421 // Clear the calling identity and query the database using the phone user id 1422 // Otherwise the AppOps check in TelephonyProvider would complain about mismatch 1423 // between the calling uid and the package uid 1424 final long identity = Binder.clearCallingIdentity(); 1425 Cursor cursor = null; 1426 try { 1427 cursor = resolver.query( 1428 messageUri, 1429 new String[]{ Telephony.Sms.TYPE }, 1430 null/*selection*/, 1431 null/*selectionArgs*/, 1432 null/*sortOrder*/); 1433 if (cursor != null && cursor.moveToFirst()) { 1434 final int type = cursor.getInt(0); 1435 return type == Telephony.Sms.MESSAGE_TYPE_DRAFT 1436 || type == Telephony.Sms.MESSAGE_TYPE_FAILED; 1437 } 1438 } catch (SQLiteException e) { 1439 loge("isFailedOrDraft: query message type failed", e); 1440 } finally { 1441 if (cursor != null) { 1442 cursor.close(); 1443 } 1444 Binder.restoreCallingIdentity(identity); 1445 } 1446 return false; 1447 } 1448 1449 // Return an array including both the SMS text (0) and address (1) loadTextAndAddress(ContentResolver resolver, Uri messageUri)1450 private String[] loadTextAndAddress(ContentResolver resolver, Uri messageUri) { 1451 // Clear the calling identity and query the database using the phone user id 1452 // Otherwise the AppOps check in TelephonyProvider would complain about mismatch 1453 // between the calling uid and the package uid 1454 final long identity = Binder.clearCallingIdentity(); 1455 Cursor cursor = null; 1456 try { 1457 cursor = resolver.query( 1458 messageUri, 1459 new String[]{ 1460 Telephony.Sms.BODY, 1461 Telephony.Sms.ADDRESS 1462 }, 1463 null/*selection*/, 1464 null/*selectionArgs*/, 1465 null/*sortOrder*/); 1466 if (cursor != null && cursor.moveToFirst()) { 1467 return new String[]{ cursor.getString(0), cursor.getString(1) }; 1468 } 1469 } catch (SQLiteException e) { 1470 loge("loadText: query message text failed", e); 1471 } finally { 1472 if (cursor != null) { 1473 cursor.close(); 1474 } 1475 Binder.restoreCallingIdentity(identity); 1476 } 1477 return null; 1478 } 1479 notifyIfOutgoingEmergencySms(String destAddr)1480 private void notifyIfOutgoingEmergencySms(String destAddr) { 1481 EmergencyNumber emergencyNumber = mPhone.getEmergencyNumberTracker().getEmergencyNumber( 1482 destAddr); 1483 if (emergencyNumber != null) { 1484 mPhone.notifyOutgoingEmergencySms(emergencyNumber); 1485 } 1486 } 1487 returnUnspecifiedFailure(PendingIntent pi)1488 private void returnUnspecifiedFailure(PendingIntent pi) { 1489 if (pi != null) { 1490 try { 1491 pi.send(SmsManager.RESULT_ERROR_GENERIC_FAILURE); 1492 } catch (PendingIntent.CanceledException e) { 1493 // ignore 1494 } 1495 } 1496 } 1497 returnUnspecifiedFailure(List<PendingIntent> pis)1498 private void returnUnspecifiedFailure(List<PendingIntent> pis) { 1499 if (pis == null) { 1500 return; 1501 } 1502 for (PendingIntent pi : pis) { 1503 returnUnspecifiedFailure(pi); 1504 } 1505 } 1506 1507 @UnsupportedAppUsage filterDestAddress(String destAddr)1508 private String filterDestAddress(String destAddr) { 1509 String result = SmsNumberUtils.filterDestAddr(mContext, mPhone.getSubId(), destAddr); 1510 return result != null ? result : destAddr; 1511 } 1512 dump(FileDescriptor fd, PrintWriter pw, String[] args)1513 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1514 pw.println("Enabled GSM channels: " + mCellBroadcastRangeManager); 1515 pw.println("Enabled CDMA channels: " + mCdmaBroadcastRangeManager); 1516 pw.println("CellBroadcast log:"); 1517 mCellBroadcastLocalLog.dump(fd, pw, args); 1518 pw.println("SMS dispatcher controller log:"); 1519 mDispatchersController.dump(fd, pw, args); 1520 pw.flush(); 1521 } 1522 } 1523