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