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