1 /* 2 * Copyright (C) 2013 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.service.carrier.CarrierMessagingService.RECEIVE_OPTIONS_SKIP_NOTIFY_WHEN_CREDENTIAL_PROTECTED_STORAGE_UNAVAILABLE; 20 import static android.telephony.TelephonyManager.PHONE_TYPE_CDMA; 21 22 import android.app.Activity; 23 import android.app.ActivityManager; 24 import android.app.AppOpsManager; 25 import android.app.BroadcastOptions; 26 import android.app.Notification; 27 import android.app.NotificationManager; 28 import android.app.PendingIntent; 29 import android.content.BroadcastReceiver; 30 import android.content.ComponentName; 31 import android.content.ContentResolver; 32 import android.content.ContentUris; 33 import android.content.ContentValues; 34 import android.content.Context; 35 import android.content.Intent; 36 import android.content.IntentFilter; 37 import android.content.pm.IPackageManager; 38 import android.content.pm.UserInfo; 39 import android.database.Cursor; 40 import android.database.SQLException; 41 import android.net.Uri; 42 import android.os.AsyncResult; 43 import android.os.Binder; 44 import android.os.Build; 45 import android.os.Bundle; 46 import android.os.IDeviceIdleController; 47 import android.os.Message; 48 import android.os.PowerManager; 49 import android.os.RemoteException; 50 import android.os.ServiceManager; 51 import android.os.UserHandle; 52 import android.os.UserManager; 53 import android.os.storage.StorageManager; 54 import android.provider.Telephony; 55 import android.provider.Telephony.Sms.Intents; 56 import android.service.carrier.CarrierMessagingService; 57 import android.telephony.Rlog; 58 import android.telephony.SmsManager; 59 import android.telephony.SmsMessage; 60 import android.telephony.SubscriptionManager; 61 import android.telephony.TelephonyManager; 62 import android.text.TextUtils; 63 64 import com.android.internal.R; 65 import com.android.internal.annotations.VisibleForTesting; 66 import com.android.internal.telephony.util.NotificationChannelController; 67 import com.android.internal.util.HexDump; 68 import com.android.internal.util.State; 69 import com.android.internal.util.StateMachine; 70 71 import java.io.ByteArrayOutputStream; 72 import java.util.Arrays; 73 import java.util.HashMap; 74 import java.util.List; 75 import java.util.Map; 76 77 /** 78 * This class broadcasts incoming SMS messages to interested apps after storing them in 79 * the SmsProvider "raw" table and ACKing them to the SMSC. After each message has been 80 * broadcast, its parts are removed from the raw table. If the device crashes after ACKing 81 * but before the broadcast completes, the pending messages will be rebroadcast on the next boot. 82 * 83 * <p>The state machine starts in {@link IdleState} state. When the {@link SMSDispatcher} receives a 84 * new SMS from the radio, it calls {@link #dispatchNormalMessage}, 85 * which sends a message to the state machine, causing the wakelock to be acquired in 86 * {@link #haltedProcessMessage}, which transitions to {@link DeliveringState} state, where the message 87 * is saved to the raw table, then acknowledged via the {@link SMSDispatcher} which called us. 88 * 89 * <p>After saving the SMS, if the message is complete (either single-part or the final segment 90 * of a multi-part SMS), we broadcast the completed PDUs as an ordered broadcast, then transition to 91 * {@link WaitingState} state to wait for the broadcast to complete. When the local 92 * {@link BroadcastReceiver} is called with the result, it sends {@link #EVENT_BROADCAST_COMPLETE} 93 * to the state machine, causing us to either broadcast the next pending message (if one has 94 * arrived while waiting for the broadcast to complete), or to transition back to the halted state 95 * after all messages are processed. Then the wakelock is released and we wait for the next SMS. 96 */ 97 public abstract class InboundSmsHandler extends StateMachine { 98 protected static final boolean DBG = true; 99 private static final boolean VDBG = false; // STOPSHIP if true, logs user data 100 101 /** Query projection for checking for duplicate message segments. */ 102 private static final String[] PDU_PROJECTION = { 103 "pdu" 104 }; 105 106 /** Query projection for combining concatenated message segments. */ 107 private static final String[] PDU_SEQUENCE_PORT_PROJECTION = { 108 "pdu", 109 "sequence", 110 "destination_port", 111 "display_originating_addr" 112 }; 113 114 /** Mapping from DB COLUMN to PDU_SEQUENCE_PORT PROJECTION index */ 115 private static final Map<Integer, Integer> PDU_SEQUENCE_PORT_PROJECTION_INDEX_MAPPING = 116 new HashMap<Integer, Integer>() {{ 117 put(PDU_COLUMN, 0); 118 put(SEQUENCE_COLUMN, 1); 119 put(DESTINATION_PORT_COLUMN, 2); 120 put(DISPLAY_ADDRESS_COLUMN, 3); 121 }}; 122 123 public static final int PDU_COLUMN = 0; 124 public static final int SEQUENCE_COLUMN = 1; 125 public static final int DESTINATION_PORT_COLUMN = 2; 126 public static final int DATE_COLUMN = 3; 127 public static final int REFERENCE_NUMBER_COLUMN = 4; 128 public static final int COUNT_COLUMN = 5; 129 public static final int ADDRESS_COLUMN = 6; 130 public static final int ID_COLUMN = 7; 131 public static final int MESSAGE_BODY_COLUMN = 8; 132 public static final int DISPLAY_ADDRESS_COLUMN = 9; 133 134 public static final String SELECT_BY_ID = "_id=?"; 135 136 /** New SMS received as an AsyncResult. */ 137 public static final int EVENT_NEW_SMS = 1; 138 139 /** Message type containing a {@link InboundSmsTracker} ready to broadcast to listeners. */ 140 public static final int EVENT_BROADCAST_SMS = 2; 141 142 /** Message from resultReceiver notifying {@link WaitingState} of a completed broadcast. */ 143 private static final int EVENT_BROADCAST_COMPLETE = 3; 144 145 /** Sent on exit from {@link WaitingState} to return to idle after sending all broadcasts. */ 146 private static final int EVENT_RETURN_TO_IDLE = 4; 147 148 /** Release wakelock after {@link #mWakeLockTimeout} when returning to idle state. */ 149 private static final int EVENT_RELEASE_WAKELOCK = 5; 150 151 /** Sent by {@link SmsBroadcastUndelivered} after cleaning the raw table. */ 152 public static final int EVENT_START_ACCEPTING_SMS = 6; 153 154 /** Update phone object */ 155 private static final int EVENT_UPDATE_PHONE_OBJECT = 7; 156 157 /** New SMS received as an AsyncResult. */ 158 public static final int EVENT_INJECT_SMS = 8; 159 160 /** Wakelock release delay when returning to idle state. */ 161 private static final int WAKELOCK_TIMEOUT = 3000; 162 163 // The notitfication tag used when showing a notification. The combination of notification tag 164 // and notification id should be unique within the phone app. 165 private static final String NOTIFICATION_TAG = "InboundSmsHandler"; 166 private static final int NOTIFICATION_ID_NEW_MESSAGE = 1; 167 168 /** URI for raw table of SMS provider. */ 169 protected static final Uri sRawUri = Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, "raw"); 170 protected static final Uri sRawUriPermanentDelete = 171 Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, "raw/permanentDelete"); 172 173 protected final Context mContext; 174 private final ContentResolver mResolver; 175 176 /** Special handler for WAP push messages. */ 177 private final WapPushOverSms mWapPush; 178 179 /** Wake lock to ensure device stays awake while dispatching the SMS intents. */ 180 private final PowerManager.WakeLock mWakeLock; 181 182 /** DefaultState throws an exception or logs an error for unhandled message types. */ 183 private final DefaultState mDefaultState = new DefaultState(); 184 185 /** Startup state. Waiting for {@link SmsBroadcastUndelivered} to complete. */ 186 private final StartupState mStartupState = new StartupState(); 187 188 /** Idle state. Waiting for messages to process. */ 189 private final IdleState mIdleState = new IdleState(); 190 191 /** Delivering state. Saves the PDU in the raw table and acknowledges to SMSC. */ 192 private final DeliveringState mDeliveringState = new DeliveringState(); 193 194 /** Broadcasting state. Waits for current broadcast to complete before delivering next. */ 195 private final WaitingState mWaitingState = new WaitingState(); 196 197 /** Helper class to check whether storage is available for incoming messages. */ 198 protected SmsStorageMonitor mStorageMonitor; 199 200 private final boolean mSmsReceiveDisabled; 201 202 protected Phone mPhone; 203 204 protected CellBroadcastHandler mCellBroadcastHandler; 205 206 private UserManager mUserManager; 207 208 IDeviceIdleController mDeviceIdleController; 209 210 // Delete permanently from raw table 211 private final int DELETE_PERMANENTLY = 1; 212 // Only mark deleted, but keep in db for message de-duping 213 private final int MARK_DELETED = 2; 214 215 private static String ACTION_OPEN_SMS_APP = 216 "com.android.internal.telephony.OPEN_DEFAULT_SMS_APP"; 217 218 /** Timeout for releasing wakelock */ 219 private int mWakeLockTimeout; 220 221 /** 222 * Create a new SMS broadcast helper. 223 * @param name the class name for logging 224 * @param context the context of the phone app 225 * @param storageMonitor the SmsStorageMonitor to check for storage availability 226 */ 227 protected InboundSmsHandler(String name, Context context, SmsStorageMonitor storageMonitor, 228 Phone phone, CellBroadcastHandler cellBroadcastHandler) { 229 super(name); 230 231 mContext = context; 232 mStorageMonitor = storageMonitor; 233 mPhone = phone; 234 mCellBroadcastHandler = cellBroadcastHandler; 235 mResolver = context.getContentResolver(); 236 mWapPush = new WapPushOverSms(context); 237 238 boolean smsCapable = mContext.getResources().getBoolean( 239 com.android.internal.R.bool.config_sms_capable); 240 mSmsReceiveDisabled = !TelephonyManager.from(mContext).getSmsReceiveCapableForPhone( 241 mPhone.getPhoneId(), smsCapable); 242 243 PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 244 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, name); 245 mWakeLock.acquire(); // wake lock released after we enter idle state 246 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 247 mDeviceIdleController = TelephonyComponentFactory.getInstance().getIDeviceIdleController(); 248 249 addState(mDefaultState); 250 addState(mStartupState, mDefaultState); 251 addState(mIdleState, mDefaultState); 252 addState(mDeliveringState, mDefaultState); 253 addState(mWaitingState, mDeliveringState); 254 255 setInitialState(mStartupState); 256 if (DBG) log("created InboundSmsHandler"); 257 } 258 259 /** 260 * Tell the state machine to quit after processing all messages. 261 */ 262 public void dispose() { 263 quit(); 264 } 265 266 /** 267 * Update the phone object when it changes. 268 */ 269 public void updatePhoneObject(Phone phone) { 270 sendMessage(EVENT_UPDATE_PHONE_OBJECT, phone); 271 } 272 273 /** 274 * Dispose of the WAP push object and release the wakelock. 275 */ 276 @Override 277 protected void onQuitting() { 278 mWapPush.dispose(); 279 280 while (mWakeLock.isHeld()) { 281 mWakeLock.release(); 282 } 283 } 284 285 // CAF_MSIM Is this used anywhere ? if not remove it 286 public Phone getPhone() { 287 return mPhone; 288 } 289 290 /** 291 * This parent state throws an exception (for debug builds) or prints an error for unhandled 292 * message types. 293 */ 294 private class DefaultState extends State { 295 @Override 296 public boolean processMessage(Message msg) { 297 switch (msg.what) { 298 case EVENT_UPDATE_PHONE_OBJECT: { 299 onUpdatePhoneObject((Phone) msg.obj); 300 break; 301 } 302 default: { 303 String errorText = "processMessage: unhandled message type " + msg.what + 304 " currState=" + getCurrentState().getName(); 305 if (Build.IS_DEBUGGABLE) { 306 loge("---- Dumping InboundSmsHandler ----"); 307 loge("Total records=" + getLogRecCount()); 308 for (int i = Math.max(getLogRecSize() - 20, 0); i < getLogRecSize(); i++) { 309 loge("Rec[%d]: %s\n" + i + getLogRec(i).toString()); 310 } 311 loge("---- Dumped InboundSmsHandler ----"); 312 313 throw new RuntimeException(errorText); 314 } else { 315 loge(errorText); 316 } 317 break; 318 } 319 } 320 return HANDLED; 321 } 322 } 323 324 /** 325 * The Startup state waits for {@link SmsBroadcastUndelivered} to process the raw table and 326 * notify the state machine to broadcast any complete PDUs that might not have been broadcast. 327 */ 328 private class StartupState extends State { 329 @Override 330 public void enter() { 331 if (DBG) log("entering Startup state"); 332 // Set wakelock timeout to 0 during startup, this will ensure that the wakelock is not 333 // held if there are no pending messages to be handled. 334 setWakeLockTimeout(0); 335 } 336 337 @Override 338 public boolean processMessage(Message msg) { 339 log("StartupState.processMessage:" + msg.what); 340 switch (msg.what) { 341 case EVENT_NEW_SMS: 342 case EVENT_INJECT_SMS: 343 case EVENT_BROADCAST_SMS: 344 deferMessage(msg); 345 return HANDLED; 346 347 case EVENT_START_ACCEPTING_SMS: 348 transitionTo(mIdleState); 349 return HANDLED; 350 351 case EVENT_BROADCAST_COMPLETE: 352 case EVENT_RETURN_TO_IDLE: 353 case EVENT_RELEASE_WAKELOCK: 354 default: 355 // let DefaultState handle these unexpected message types 356 return NOT_HANDLED; 357 } 358 } 359 } 360 361 /** 362 * In the idle state the wakelock is released until a new SM arrives, then we transition 363 * to Delivering mode to handle it, acquiring the wakelock on exit. 364 */ 365 private class IdleState extends State { 366 @Override 367 public void enter() { 368 if (DBG) log("entering Idle state"); 369 sendMessageDelayed(EVENT_RELEASE_WAKELOCK, getWakeLockTimeout()); 370 } 371 372 @Override 373 public void exit() { 374 mWakeLock.acquire(); 375 if (DBG) log("acquired wakelock, leaving Idle state"); 376 } 377 378 @Override 379 public boolean processMessage(Message msg) { 380 log("IdleState.processMessage:" + msg.what); 381 if (DBG) log("Idle state processing message type " + msg.what); 382 switch (msg.what) { 383 case EVENT_NEW_SMS: 384 case EVENT_INJECT_SMS: 385 case EVENT_BROADCAST_SMS: 386 deferMessage(msg); 387 transitionTo(mDeliveringState); 388 return HANDLED; 389 390 case EVENT_RELEASE_WAKELOCK: 391 mWakeLock.release(); 392 if (DBG) { 393 if (mWakeLock.isHeld()) { 394 // this is okay as long as we call release() for every acquire() 395 log("mWakeLock is still held after release"); 396 } else { 397 log("mWakeLock released"); 398 } 399 } 400 return HANDLED; 401 402 case EVENT_RETURN_TO_IDLE: 403 // already in idle state; ignore 404 return HANDLED; 405 406 case EVENT_BROADCAST_COMPLETE: 407 case EVENT_START_ACCEPTING_SMS: 408 default: 409 // let DefaultState handle these unexpected message types 410 return NOT_HANDLED; 411 } 412 } 413 } 414 415 /** 416 * In the delivering state, the inbound SMS is processed and stored in the raw table. 417 * The message is acknowledged before we exit this state. If there is a message to broadcast, 418 * transition to {@link WaitingState} state to send the ordered broadcast and wait for the 419 * results. When all messages have been processed, the halting state will release the wakelock. 420 */ 421 private class DeliveringState extends State { 422 @Override 423 public void enter() { 424 if (DBG) log("entering Delivering state"); 425 } 426 427 @Override 428 public void exit() { 429 if (DBG) log("leaving Delivering state"); 430 } 431 432 @Override 433 public boolean processMessage(Message msg) { 434 log("DeliveringState.processMessage:" + msg.what); 435 switch (msg.what) { 436 case EVENT_NEW_SMS: 437 // handle new SMS from RIL 438 handleNewSms((AsyncResult) msg.obj); 439 sendMessage(EVENT_RETURN_TO_IDLE); 440 return HANDLED; 441 442 case EVENT_INJECT_SMS: 443 // handle new injected SMS 444 handleInjectSms((AsyncResult) msg.obj); 445 sendMessage(EVENT_RETURN_TO_IDLE); 446 return HANDLED; 447 448 case EVENT_BROADCAST_SMS: 449 // if any broadcasts were sent, transition to waiting state 450 InboundSmsTracker inboundSmsTracker = (InboundSmsTracker) msg.obj; 451 if (processMessagePart(inboundSmsTracker)) { 452 transitionTo(mWaitingState); 453 } else { 454 // if event is sent from SmsBroadcastUndelivered.broadcastSms(), and 455 // processMessagePart() returns false, the state machine will be stuck in 456 // DeliveringState until next message is received. Send message to 457 // transition to idle to avoid that so that wakelock can be released 458 log("No broadcast sent on processing EVENT_BROADCAST_SMS in Delivering " + 459 "state. Return to Idle state"); 460 sendMessage(EVENT_RETURN_TO_IDLE); 461 } 462 return HANDLED; 463 464 case EVENT_RETURN_TO_IDLE: 465 // return to idle after processing all other messages 466 transitionTo(mIdleState); 467 return HANDLED; 468 469 case EVENT_RELEASE_WAKELOCK: 470 mWakeLock.release(); // decrement wakelock from previous entry to Idle 471 if (!mWakeLock.isHeld()) { 472 // wakelock should still be held until 3 seconds after we enter Idle 473 loge("mWakeLock released while delivering/broadcasting!"); 474 } 475 return HANDLED; 476 477 // we shouldn't get this message type in this state, log error and halt. 478 case EVENT_BROADCAST_COMPLETE: 479 case EVENT_START_ACCEPTING_SMS: 480 default: 481 // let DefaultState handle these unexpected message types 482 return NOT_HANDLED; 483 } 484 } 485 } 486 487 /** 488 * The waiting state delegates handling of new SMS to parent {@link DeliveringState}, but 489 * defers handling of the {@link #EVENT_BROADCAST_SMS} phase until after the current 490 * result receiver sends {@link #EVENT_BROADCAST_COMPLETE}. Before transitioning to 491 * {@link DeliveringState}, {@link #EVENT_RETURN_TO_IDLE} is sent to transition to 492 * {@link IdleState} after any deferred {@link #EVENT_BROADCAST_SMS} messages are handled. 493 */ 494 private class WaitingState extends State { 495 496 @Override 497 public void enter() { 498 if (DBG) log("entering Waiting state"); 499 } 500 501 @Override 502 public void exit() { 503 if (DBG) log("exiting Waiting state"); 504 // Before moving to idle state, set wakelock timeout to WAKE_LOCK_TIMEOUT milliseconds 505 // to give any receivers time to take their own wake locks 506 setWakeLockTimeout(WAKELOCK_TIMEOUT); 507 } 508 509 @Override 510 public boolean processMessage(Message msg) { 511 log("WaitingState.processMessage:" + msg.what); 512 switch (msg.what) { 513 case EVENT_BROADCAST_SMS: 514 // defer until the current broadcast completes 515 deferMessage(msg); 516 return HANDLED; 517 518 case EVENT_BROADCAST_COMPLETE: 519 // return to idle after handling all deferred messages 520 sendMessage(EVENT_RETURN_TO_IDLE); 521 transitionTo(mDeliveringState); 522 return HANDLED; 523 524 case EVENT_RETURN_TO_IDLE: 525 // not ready to return to idle; ignore 526 return HANDLED; 527 528 default: 529 // parent state handles the other message types 530 return NOT_HANDLED; 531 } 532 } 533 } 534 535 private void handleNewSms(AsyncResult ar) { 536 if (ar.exception != null) { 537 loge("Exception processing incoming SMS: " + ar.exception); 538 return; 539 } 540 541 int result; 542 try { 543 SmsMessage sms = (SmsMessage) ar.result; 544 result = dispatchMessage(sms.mWrappedSmsMessage); 545 } catch (RuntimeException ex) { 546 loge("Exception dispatching message", ex); 547 result = Intents.RESULT_SMS_GENERIC_ERROR; 548 } 549 550 // RESULT_OK means that the SMS will be acknowledged by special handling, 551 // e.g. for SMS-PP data download. Any other result, we should ack here. 552 if (result != Activity.RESULT_OK) { 553 boolean handled = (result == Intents.RESULT_SMS_HANDLED); 554 notifyAndAcknowledgeLastIncomingSms(handled, result, null); 555 } 556 } 557 558 /** 559 * This method is called when a new SMS PDU is injected into application framework. 560 * @param ar is the AsyncResult that has the SMS PDU to be injected. 561 */ 562 private void handleInjectSms(AsyncResult ar) { 563 int result; 564 SmsDispatchersController.SmsInjectionCallback callback = null; 565 try { 566 callback = (SmsDispatchersController.SmsInjectionCallback) ar.userObj; 567 SmsMessage sms = (SmsMessage) ar.result; 568 if (sms == null) { 569 result = Intents.RESULT_SMS_GENERIC_ERROR; 570 } else { 571 result = dispatchMessage(sms.mWrappedSmsMessage); 572 } 573 } catch (RuntimeException ex) { 574 loge("Exception dispatching message", ex); 575 result = Intents.RESULT_SMS_GENERIC_ERROR; 576 } 577 578 if (callback != null) { 579 callback.onSmsInjectedResult(result); 580 } 581 } 582 583 /** 584 * Process an SMS message from the RIL, calling subclass methods to handle 3GPP and 585 * 3GPP2-specific message types. 586 * 587 * @param smsb the SmsMessageBase object from the RIL 588 * @return a result code from {@link android.provider.Telephony.Sms.Intents}, 589 * or {@link Activity#RESULT_OK} for delayed acknowledgment to SMSC 590 */ 591 private int dispatchMessage(SmsMessageBase smsb) { 592 // If sms is null, there was a parsing error. 593 if (smsb == null) { 594 loge("dispatchSmsMessage: message is null"); 595 return Intents.RESULT_SMS_GENERIC_ERROR; 596 } 597 598 if (mSmsReceiveDisabled) { 599 // Device doesn't support receiving SMS, 600 log("Received short message on device which doesn't support " 601 + "receiving SMS. Ignored."); 602 return Intents.RESULT_SMS_HANDLED; 603 } 604 605 // onlyCore indicates if the device is in cryptkeeper 606 boolean onlyCore = false; 607 try { 608 onlyCore = IPackageManager.Stub.asInterface(ServiceManager.getService("package")). 609 isOnlyCoreApps(); 610 } catch (RemoteException e) { 611 } 612 if (onlyCore) { 613 // Device is unable to receive SMS in encrypted state 614 log("Received a short message in encrypted state. Rejecting."); 615 return Intents.RESULT_SMS_GENERIC_ERROR; 616 } 617 618 return dispatchMessageRadioSpecific(smsb); 619 } 620 621 /** 622 * Process voicemail notification, SMS-PP data download, CDMA CMAS, CDMA WAP push, and other 623 * 3GPP/3GPP2-specific messages. Regular SMS messages are handled by calling the shared 624 * {@link #dispatchNormalMessage} from this class. 625 * 626 * @param smsb the SmsMessageBase object from the RIL 627 * @return a result code from {@link android.provider.Telephony.Sms.Intents}, 628 * or {@link Activity#RESULT_OK} for delayed acknowledgment to SMSC 629 */ 630 protected abstract int dispatchMessageRadioSpecific(SmsMessageBase smsb); 631 632 /** 633 * Send an acknowledge message to the SMSC. 634 * @param success indicates that last message was successfully received. 635 * @param result result code indicating any error 636 * @param response callback message sent when operation completes. 637 */ 638 protected abstract void acknowledgeLastIncomingSms(boolean success, 639 int result, Message response); 640 641 /** 642 * Called when the phone changes the default method updates mPhone 643 * mStorageMonitor and mCellBroadcastHandler.updatePhoneObject. 644 * Override if different or other behavior is desired. 645 * 646 * @param phone 647 */ 648 protected void onUpdatePhoneObject(Phone phone) { 649 mPhone = phone; 650 mStorageMonitor = mPhone.mSmsStorageMonitor; 651 log("onUpdatePhoneObject: phone=" + mPhone.getClass().getSimpleName()); 652 } 653 654 /** 655 * Notify interested apps if the framework has rejected an incoming SMS, 656 * and send an acknowledge message to the network. 657 * @param success indicates that last message was successfully received. 658 * @param result result code indicating any error 659 * @param response callback message sent when operation completes. 660 */ 661 private void notifyAndAcknowledgeLastIncomingSms(boolean success, 662 int result, Message response) { 663 if (!success) { 664 // broadcast SMS_REJECTED_ACTION intent 665 Intent intent = new Intent(Intents.SMS_REJECTED_ACTION); 666 intent.putExtra("result", result); 667 // Allow registered broadcast receivers to get this intent even 668 // when they are in the background. 669 intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 670 mContext.sendBroadcast(intent, android.Manifest.permission.RECEIVE_SMS); 671 } 672 acknowledgeLastIncomingSms(success, result, response); 673 } 674 675 /** 676 * Return true if this handler is for 3GPP2 messages; false for 3GPP format. 677 * @return true for the 3GPP2 handler; false for the 3GPP handler 678 */ 679 protected abstract boolean is3gpp2(); 680 681 /** 682 * Dispatch a normal incoming SMS. This is called from {@link #dispatchMessageRadioSpecific} 683 * if no format-specific handling was required. Saves the PDU to the SMS provider raw table, 684 * creates an {@link InboundSmsTracker}, then sends it to the state machine as an 685 * {@link #EVENT_BROADCAST_SMS}. Returns {@link Intents#RESULT_SMS_HANDLED} or an error value. 686 * 687 * @param sms the message to dispatch 688 * @return {@link Intents#RESULT_SMS_HANDLED} if the message was accepted, or an error status 689 */ 690 protected int dispatchNormalMessage(SmsMessageBase sms) { 691 SmsHeader smsHeader = sms.getUserDataHeader(); 692 InboundSmsTracker tracker; 693 694 if ((smsHeader == null) || (smsHeader.concatRef == null)) { 695 // Message is not concatenated. 696 int destPort = -1; 697 if (smsHeader != null && smsHeader.portAddrs != null) { 698 // The message was sent to a port. 699 destPort = smsHeader.portAddrs.destPort; 700 if (DBG) log("destination port: " + destPort); 701 } 702 703 tracker = TelephonyComponentFactory.getInstance().makeInboundSmsTracker(sms.getPdu(), 704 sms.getTimestampMillis(), destPort, is3gpp2(), false, 705 sms.getOriginatingAddress(), sms.getDisplayOriginatingAddress(), 706 sms.getMessageBody()); 707 } else { 708 // Create a tracker for this message segment. 709 SmsHeader.ConcatRef concatRef = smsHeader.concatRef; 710 SmsHeader.PortAddrs portAddrs = smsHeader.portAddrs; 711 int destPort = (portAddrs != null ? portAddrs.destPort : -1); 712 713 tracker = TelephonyComponentFactory.getInstance().makeInboundSmsTracker(sms.getPdu(), 714 sms.getTimestampMillis(), destPort, is3gpp2(), sms.getOriginatingAddress(), 715 sms.getDisplayOriginatingAddress(), concatRef.refNumber, concatRef.seqNumber, 716 concatRef.msgCount, false, sms.getMessageBody()); 717 } 718 719 if (VDBG) log("created tracker: " + tracker); 720 721 // de-duping is done only for text messages 722 // destPort = -1 indicates text messages, otherwise it's a data sms 723 return addTrackerToRawTableAndSendMessage(tracker, 724 tracker.getDestPort() == -1 /* de-dup if text message */); 725 } 726 727 /** 728 * Helper to add the tracker to the raw table and then send a message to broadcast it, if 729 * successful. Returns the SMS intent status to return to the SMSC. 730 * @param tracker the tracker to save to the raw table and then deliver 731 * @return {@link Intents#RESULT_SMS_HANDLED} or {@link Intents#RESULT_SMS_GENERIC_ERROR} 732 * or {@link Intents#RESULT_SMS_DUPLICATED} 733 */ 734 protected int addTrackerToRawTableAndSendMessage(InboundSmsTracker tracker, boolean deDup) { 735 switch(addTrackerToRawTable(tracker, deDup)) { 736 case Intents.RESULT_SMS_HANDLED: 737 sendMessage(EVENT_BROADCAST_SMS, tracker); 738 return Intents.RESULT_SMS_HANDLED; 739 740 case Intents.RESULT_SMS_DUPLICATED: 741 return Intents.RESULT_SMS_HANDLED; 742 743 case Intents.RESULT_SMS_GENERIC_ERROR: 744 default: 745 return Intents.RESULT_SMS_GENERIC_ERROR; 746 } 747 } 748 749 /** 750 * Process the inbound SMS segment. If the message is complete, send it as an ordered 751 * broadcast to interested receivers and return true. If the message is a segment of an 752 * incomplete multi-part SMS, return false. 753 * @param tracker the tracker containing the message segment to process 754 * @return true if an ordered broadcast was sent; false if waiting for more message segments 755 */ 756 private boolean processMessagePart(InboundSmsTracker tracker) { 757 int messageCount = tracker.getMessageCount(); 758 byte[][] pdus; 759 int destPort = tracker.getDestPort(); 760 boolean block = false; 761 762 // Do not process when the message count is invalid. 763 if (messageCount <= 0) { 764 loge("processMessagePart: returning false due to invalid message count " 765 + messageCount); 766 return false; 767 } 768 769 if (messageCount == 1) { 770 // single-part message 771 pdus = new byte[][]{tracker.getPdu()}; 772 block = BlockChecker.isBlocked(mContext, tracker.getDisplayAddress(), null); 773 } else { 774 // multi-part message 775 Cursor cursor = null; 776 try { 777 // used by several query selection arguments 778 String address = tracker.getAddress(); 779 String refNumber = Integer.toString(tracker.getReferenceNumber()); 780 String count = Integer.toString(tracker.getMessageCount()); 781 782 // query for all segments and broadcast message if we have all the parts 783 String[] whereArgs = {address, refNumber, count}; 784 cursor = mResolver.query(sRawUri, PDU_SEQUENCE_PORT_PROJECTION, 785 tracker.getQueryForSegments(), whereArgs, null); 786 787 int cursorCount = cursor.getCount(); 788 if (cursorCount < messageCount) { 789 // Wait for the other message parts to arrive. It's also possible for the last 790 // segment to arrive before processing the EVENT_BROADCAST_SMS for one of the 791 // earlier segments. In that case, the broadcast will be sent as soon as all 792 // segments are in the table, and any later EVENT_BROADCAST_SMS messages will 793 // get a row count of 0 and return. 794 return false; 795 } 796 797 // All the parts are in place, deal with them 798 pdus = new byte[messageCount][]; 799 while (cursor.moveToNext()) { 800 // subtract offset to convert sequence to 0-based array index 801 int index = cursor.getInt(PDU_SEQUENCE_PORT_PROJECTION_INDEX_MAPPING 802 .get(SEQUENCE_COLUMN)) - tracker.getIndexOffset(); 803 804 // The invalid PDUs can be received and stored in the raw table. The range 805 // check ensures the process not crash even if the seqNumber in the 806 // UserDataHeader is invalid. 807 if (index >= pdus.length || index < 0) { 808 loge(String.format( 809 "processMessagePart: invalid seqNumber = %d, messageCount = %d", 810 index + tracker.getIndexOffset(), 811 messageCount)); 812 continue; 813 } 814 815 pdus[index] = HexDump.hexStringToByteArray(cursor.getString( 816 PDU_SEQUENCE_PORT_PROJECTION_INDEX_MAPPING.get(PDU_COLUMN))); 817 818 // Read the destination port from the first segment (needed for CDMA WAP PDU). 819 // It's not a bad idea to prefer the port from the first segment in other cases. 820 if (index == 0 && !cursor.isNull(PDU_SEQUENCE_PORT_PROJECTION_INDEX_MAPPING 821 .get(DESTINATION_PORT_COLUMN))) { 822 int port = cursor.getInt(PDU_SEQUENCE_PORT_PROJECTION_INDEX_MAPPING 823 .get(DESTINATION_PORT_COLUMN)); 824 // strip format flags and convert to real port number, or -1 825 port = InboundSmsTracker.getRealDestPort(port); 826 if (port != -1) { 827 destPort = port; 828 } 829 } 830 // check if display address should be blocked or not 831 if (!block) { 832 // Depending on the nature of the gateway, the display origination address 833 // is either derived from the content of the SMS TP-OA field, or the TP-OA 834 // field contains a generic gateway address and the from address is added 835 // at the beginning in the message body. In that case only the first SMS 836 // (part of Multi-SMS) comes with the display originating address which 837 // could be used for block checking purpose. 838 block = BlockChecker.isBlocked(mContext, 839 cursor.getString(PDU_SEQUENCE_PORT_PROJECTION_INDEX_MAPPING 840 .get(DISPLAY_ADDRESS_COLUMN)), null); 841 } 842 } 843 } catch (SQLException e) { 844 loge("Can't access multipart SMS database", e); 845 return false; 846 } finally { 847 if (cursor != null) { 848 cursor.close(); 849 } 850 } 851 } 852 853 // Do not process null pdu(s). Check for that and return false in that case. 854 List<byte[]> pduList = Arrays.asList(pdus); 855 if (pduList.size() == 0 || pduList.contains(null)) { 856 loge("processMessagePart: returning false due to " + 857 (pduList.size() == 0 ? "pduList.size() == 0" : "pduList.contains(null)")); 858 return false; 859 } 860 861 SmsBroadcastReceiver resultReceiver = new SmsBroadcastReceiver(tracker); 862 863 if (!mUserManager.isUserUnlocked()) { 864 return processMessagePartWithUserLocked(tracker, pdus, destPort, resultReceiver); 865 } 866 867 if (destPort == SmsHeader.PORT_WAP_PUSH) { 868 // Build up the data stream 869 ByteArrayOutputStream output = new ByteArrayOutputStream(); 870 for (byte[] pdu : pdus) { 871 // 3GPP needs to extract the User Data from the PDU; 3GPP2 has already done this 872 if (!tracker.is3gpp2()) { 873 SmsMessage msg = SmsMessage.createFromPdu(pdu, SmsConstants.FORMAT_3GPP); 874 if (msg != null) { 875 pdu = msg.getUserData(); 876 } else { 877 loge("processMessagePart: SmsMessage.createFromPdu returned null"); 878 return false; 879 } 880 } 881 output.write(pdu, 0, pdu.length); 882 } 883 int result = mWapPush.dispatchWapPdu(output.toByteArray(), resultReceiver, this); 884 if (DBG) log("dispatchWapPdu() returned " + result); 885 // result is Activity.RESULT_OK if an ordered broadcast was sent 886 if (result == Activity.RESULT_OK) { 887 return true; 888 } else { 889 deleteFromRawTable(tracker.getDeleteWhere(), tracker.getDeleteWhereArgs(), 890 MARK_DELETED); 891 return false; 892 } 893 } 894 895 if (block) { 896 deleteFromRawTable(tracker.getDeleteWhere(), tracker.getDeleteWhereArgs(), 897 DELETE_PERMANENTLY); 898 return false; 899 } 900 901 boolean filterInvoked = filterSms( 902 pdus, destPort, tracker, resultReceiver, true /* userUnlocked */); 903 904 if (!filterInvoked) { 905 dispatchSmsDeliveryIntent(pdus, tracker.getFormat(), destPort, resultReceiver); 906 } 907 908 return true; 909 } 910 911 /** 912 * Processes the message part while the credential-encrypted storage is still locked. 913 * 914 * <p>If the message is a regular MMS, show a new message notification. If the message is a 915 * SMS, ask the carrier app to filter it and show the new message notification if the carrier 916 * app asks to keep the message. 917 * 918 * @return true if an ordered broadcast was sent to the carrier app; false otherwise. 919 */ 920 private boolean processMessagePartWithUserLocked(InboundSmsTracker tracker, 921 byte[][] pdus, int destPort, SmsBroadcastReceiver resultReceiver) { 922 log("Credential-encrypted storage not available. Port: " + destPort); 923 if (destPort == SmsHeader.PORT_WAP_PUSH && mWapPush.isWapPushForMms(pdus[0], this)) { 924 showNewMessageNotification(); 925 return false; 926 } 927 if (destPort == -1) { 928 // This is a regular SMS - hand it to the carrier or system app for filtering. 929 boolean filterInvoked = filterSms( 930 pdus, destPort, tracker, resultReceiver, false /* userUnlocked */); 931 if (filterInvoked) { 932 // filter invoked, wait for it to return the result. 933 return true; 934 } else { 935 // filter not invoked, show the notification and do nothing further. 936 showNewMessageNotification(); 937 return false; 938 } 939 } 940 return false; 941 } 942 943 private void showNewMessageNotification() { 944 // Do not show the notification on non-FBE devices. 945 if (!StorageManager.isFileEncryptedNativeOrEmulated()) { 946 return; 947 } 948 log("Show new message notification."); 949 PendingIntent intent = PendingIntent.getBroadcast( 950 mContext, 951 0, 952 new Intent(ACTION_OPEN_SMS_APP), 953 PendingIntent.FLAG_ONE_SHOT); 954 Notification.Builder mBuilder = new Notification.Builder(mContext) 955 .setSmallIcon(com.android.internal.R.drawable.sym_action_chat) 956 .setAutoCancel(true) 957 .setVisibility(Notification.VISIBILITY_PUBLIC) 958 .setDefaults(Notification.DEFAULT_ALL) 959 .setContentTitle(mContext.getString(R.string.new_sms_notification_title)) 960 .setContentText(mContext.getString(R.string.new_sms_notification_content)) 961 .setContentIntent(intent) 962 .setChannelId(NotificationChannelController.CHANNEL_ID_SMS); 963 NotificationManager mNotificationManager = 964 (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); 965 mNotificationManager.notify( 966 NOTIFICATION_TAG, NOTIFICATION_ID_NEW_MESSAGE, mBuilder.build()); 967 } 968 969 static void cancelNewMessageNotification(Context context) { 970 NotificationManager mNotificationManager = 971 (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); 972 mNotificationManager.cancel(InboundSmsHandler.NOTIFICATION_TAG, 973 InboundSmsHandler.NOTIFICATION_ID_NEW_MESSAGE); 974 } 975 976 /** 977 * Filters the SMS. 978 * 979 * <p>currently 3 filters exists: the carrier package, the system package, and the 980 * VisualVoicemailSmsFilter. 981 * 982 * <p>The filtering process is: 983 * 984 * <p>If the carrier package exists, the SMS will be filtered with it first. If the carrier 985 * package did not drop the SMS, then the VisualVoicemailSmsFilter will filter it in the 986 * callback. 987 * 988 * <p>If the carrier package does not exists, we will let the VisualVoicemailSmsFilter filter 989 * it. If the SMS passed the filter, then we will try to find the system package to do the 990 * filtering. 991 * 992 * @return true if a filter is invoked and the SMS processing flow is diverted, false otherwise. 993 */ 994 private boolean filterSms(byte[][] pdus, int destPort, 995 InboundSmsTracker tracker, SmsBroadcastReceiver resultReceiver, boolean userUnlocked) { 996 CarrierServicesSmsFilterCallback filterCallback = 997 new CarrierServicesSmsFilterCallback( 998 pdus, destPort, tracker.getFormat(), resultReceiver, userUnlocked); 999 CarrierServicesSmsFilter carrierServicesFilter = new CarrierServicesSmsFilter( 1000 mContext, mPhone, pdus, destPort, tracker.getFormat(), filterCallback, getName()); 1001 if (carrierServicesFilter.filter()) { 1002 return true; 1003 } 1004 1005 if (VisualVoicemailSmsFilter.filter( 1006 mContext, pdus, tracker.getFormat(), destPort, mPhone.getSubId())) { 1007 log("Visual voicemail SMS dropped"); 1008 dropSms(resultReceiver); 1009 return true; 1010 } 1011 1012 return false; 1013 } 1014 1015 /** 1016 * Dispatch the intent with the specified permission, appOp, and result receiver, using 1017 * this state machine's handler thread to run the result receiver. 1018 * 1019 * @param intent the intent to broadcast 1020 * @param permission receivers are required to have this permission 1021 * @param appOp app op that is being performed when dispatching to a receiver 1022 * @param user user to deliver the intent to 1023 */ 1024 public void dispatchIntent(Intent intent, String permission, int appOp, 1025 Bundle opts, BroadcastReceiver resultReceiver, UserHandle user) { 1026 intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT); 1027 final String action = intent.getAction(); 1028 if (Intents.SMS_DELIVER_ACTION.equals(action) 1029 || Intents.SMS_RECEIVED_ACTION.equals(action) 1030 || Intents.WAP_PUSH_DELIVER_ACTION.equals(action) 1031 || Intents.WAP_PUSH_RECEIVED_ACTION.equals(action)) { 1032 // Some intents need to be delivered with high priority: 1033 // SMS_DELIVER, SMS_RECEIVED, WAP_PUSH_DELIVER, WAP_PUSH_RECEIVED 1034 // In some situations, like after boot up or system under load, normal 1035 // intent delivery could take a long time. 1036 // This flag should only be set for intents for visible, timely operations 1037 // which is true for the intents above. 1038 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); 1039 } 1040 SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId()); 1041 if (user.equals(UserHandle.ALL)) { 1042 // Get a list of currently started users. 1043 int[] users = null; 1044 try { 1045 users = ActivityManager.getService().getRunningUserIds(); 1046 } catch (RemoteException re) { 1047 } 1048 if (users == null) { 1049 users = new int[] {user.getIdentifier()}; 1050 } 1051 // Deliver the broadcast only to those running users that are permitted 1052 // by user policy. 1053 for (int i = users.length - 1; i >= 0; i--) { 1054 UserHandle targetUser = new UserHandle(users[i]); 1055 if (users[i] != UserHandle.USER_SYSTEM) { 1056 // Is the user not allowed to use SMS? 1057 if (mUserManager.hasUserRestriction(UserManager.DISALLOW_SMS, targetUser)) { 1058 continue; 1059 } 1060 // Skip unknown users and managed profiles as well 1061 UserInfo info = mUserManager.getUserInfo(users[i]); 1062 if (info == null || info.isManagedProfile()) { 1063 continue; 1064 } 1065 } 1066 // Only pass in the resultReceiver when the USER_SYSTEM is processed. 1067 mContext.sendOrderedBroadcastAsUser(intent, targetUser, permission, appOp, opts, 1068 users[i] == UserHandle.USER_SYSTEM ? resultReceiver : null, 1069 getHandler(), Activity.RESULT_OK, null, null); 1070 } 1071 } else { 1072 mContext.sendOrderedBroadcastAsUser(intent, user, permission, appOp, opts, 1073 resultReceiver, getHandler(), Activity.RESULT_OK, null, null); 1074 } 1075 } 1076 1077 /** 1078 * Helper for {@link SmsBroadcastUndelivered} to delete an old message in the raw table. 1079 */ 1080 private void deleteFromRawTable(String deleteWhere, String[] deleteWhereArgs, 1081 int deleteType) { 1082 Uri uri = deleteType == DELETE_PERMANENTLY ? sRawUriPermanentDelete : sRawUri; 1083 int rows = mResolver.delete(uri, deleteWhere, deleteWhereArgs); 1084 if (rows == 0) { 1085 loge("No rows were deleted from raw table!"); 1086 } else if (DBG) { 1087 log("Deleted " + rows + " rows from raw table."); 1088 } 1089 } 1090 1091 private Bundle handleSmsWhitelisting(ComponentName target) { 1092 String pkgName; 1093 String reason; 1094 if (target != null) { 1095 pkgName = target.getPackageName(); 1096 reason = "sms-app"; 1097 } else { 1098 pkgName = mContext.getPackageName(); 1099 reason = "sms-broadcast"; 1100 } 1101 try { 1102 long duration = mDeviceIdleController.addPowerSaveTempWhitelistAppForSms( 1103 pkgName, 0, reason); 1104 BroadcastOptions bopts = BroadcastOptions.makeBasic(); 1105 bopts.setTemporaryAppWhitelistDuration(duration); 1106 return bopts.toBundle(); 1107 } catch (RemoteException e) { 1108 } 1109 1110 return null; 1111 } 1112 1113 /** 1114 * Creates and dispatches the intent to the default SMS app, appropriate port or via the {@link 1115 * AppSmsManager}. 1116 * 1117 * @param pdus message pdus 1118 * @param format the message format, typically "3gpp" or "3gpp2" 1119 * @param destPort the destination port 1120 * @param resultReceiver the receiver handling the delivery result 1121 */ 1122 private void dispatchSmsDeliveryIntent(byte[][] pdus, String format, int destPort, 1123 SmsBroadcastReceiver resultReceiver) { 1124 Intent intent = new Intent(); 1125 intent.putExtra("pdus", pdus); 1126 intent.putExtra("format", format); 1127 1128 if (destPort == -1) { 1129 intent.setAction(Intents.SMS_DELIVER_ACTION); 1130 // Direct the intent to only the default SMS app. If we can't find a default SMS app 1131 // then sent it to all broadcast receivers. 1132 // We are deliberately delivering to the primary user's default SMS App. 1133 ComponentName componentName = SmsApplication.getDefaultSmsApplication(mContext, true); 1134 if (componentName != null) { 1135 // Deliver SMS message only to this receiver. 1136 intent.setComponent(componentName); 1137 log("Delivering SMS to: " + componentName.getPackageName() + 1138 " " + componentName.getClassName()); 1139 } else { 1140 intent.setComponent(null); 1141 } 1142 1143 // TODO: Validate that this is the right place to store the SMS. 1144 if (SmsManager.getDefault().getAutoPersisting()) { 1145 final Uri uri = writeInboxMessage(intent); 1146 if (uri != null) { 1147 // Pass this to SMS apps so that they know where it is stored 1148 intent.putExtra("uri", uri.toString()); 1149 } 1150 } 1151 1152 // Handle app specific sms messages. 1153 AppSmsManager appManager = mPhone.getAppSmsManager(); 1154 if (appManager.handleSmsReceivedIntent(intent)) { 1155 // The AppSmsManager handled this intent, we're done. 1156 dropSms(resultReceiver); 1157 return; 1158 } 1159 } else { 1160 intent.setAction(Intents.DATA_SMS_RECEIVED_ACTION); 1161 Uri uri = Uri.parse("sms://localhost:" + destPort); 1162 intent.setData(uri); 1163 intent.setComponent(null); 1164 // Allow registered broadcast receivers to get this intent even 1165 // when they are in the background. 1166 intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 1167 } 1168 1169 Bundle options = handleSmsWhitelisting(intent.getComponent()); 1170 dispatchIntent(intent, android.Manifest.permission.RECEIVE_SMS, 1171 AppOpsManager.OP_RECEIVE_SMS, options, resultReceiver, UserHandle.SYSTEM); 1172 } 1173 1174 /** 1175 * Function to check if message should be dropped because same message has already been 1176 * received. In certain cases it checks for similar messages instead of exact same (cases where 1177 * keeping both messages in db can cause ambiguity) 1178 * @return true if duplicate exists, false otherwise 1179 */ 1180 private boolean duplicateExists(InboundSmsTracker tracker) throws SQLException { 1181 String address = tracker.getAddress(); 1182 // convert to strings for query 1183 String refNumber = Integer.toString(tracker.getReferenceNumber()); 1184 String count = Integer.toString(tracker.getMessageCount()); 1185 // sequence numbers are 1-based except for CDMA WAP, which is 0-based 1186 int sequence = tracker.getSequenceNumber(); 1187 String seqNumber = Integer.toString(sequence); 1188 String date = Long.toString(tracker.getTimestamp()); 1189 String messageBody = tracker.getMessageBody(); 1190 String where; 1191 if (tracker.getMessageCount() == 1) { 1192 where = "address=? AND reference_number=? AND count=? AND sequence=? AND " + 1193 "date=? AND message_body=?"; 1194 } else { 1195 // for multi-part messages, deduping should also be done against undeleted 1196 // segments that can cause ambiguity when contacenating the segments, that is, 1197 // segments with same address, reference_number, count, sequence and message type. 1198 where = tracker.getQueryForMultiPartDuplicates(); 1199 } 1200 1201 Cursor cursor = null; 1202 try { 1203 // Check for duplicate message segments 1204 cursor = mResolver.query(sRawUri, PDU_PROJECTION, where, 1205 new String[]{address, refNumber, count, seqNumber, date, messageBody}, 1206 null); 1207 1208 // moveToNext() returns false if no duplicates were found 1209 if (cursor != null && cursor.moveToNext()) { 1210 loge("Discarding duplicate message segment, refNumber=" + refNumber 1211 + " seqNumber=" + seqNumber + " count=" + count); 1212 if (VDBG) { 1213 loge("address=" + address + " date=" + date + " messageBody=" + 1214 messageBody); 1215 } 1216 String oldPduString = cursor.getString(PDU_COLUMN); 1217 byte[] pdu = tracker.getPdu(); 1218 byte[] oldPdu = HexDump.hexStringToByteArray(oldPduString); 1219 if (!Arrays.equals(oldPdu, tracker.getPdu())) { 1220 loge("Warning: dup message segment PDU of length " + pdu.length 1221 + " is different from existing PDU of length " + oldPdu.length); 1222 } 1223 return true; // reject message 1224 } 1225 } finally { 1226 if (cursor != null) { 1227 cursor.close(); 1228 } 1229 } 1230 1231 return false; 1232 } 1233 1234 /** 1235 * Insert a message PDU into the raw table so we can acknowledge it immediately. 1236 * If the device crashes before the broadcast to listeners completes, it will be delivered 1237 * from the raw table on the next device boot. For single-part messages, the deleteWhere 1238 * and deleteWhereArgs fields of the tracker will be set to delete the correct row after 1239 * the ordered broadcast completes. 1240 * 1241 * @param tracker the tracker to add to the raw table 1242 * @return true on success; false on failure to write to database 1243 */ 1244 private int addTrackerToRawTable(InboundSmsTracker tracker, boolean deDup) { 1245 if (deDup) { 1246 try { 1247 if (duplicateExists(tracker)) { 1248 return Intents.RESULT_SMS_DUPLICATED; // reject message 1249 } 1250 } catch (SQLException e) { 1251 loge("Can't access SMS database", e); 1252 return Intents.RESULT_SMS_GENERIC_ERROR; // reject message 1253 } 1254 } else { 1255 logd("Skipped message de-duping logic"); 1256 } 1257 1258 String address = tracker.getAddress(); 1259 String refNumber = Integer.toString(tracker.getReferenceNumber()); 1260 String count = Integer.toString(tracker.getMessageCount()); 1261 ContentValues values = tracker.getContentValues(); 1262 1263 if (VDBG) log("adding content values to raw table: " + values.toString()); 1264 Uri newUri = mResolver.insert(sRawUri, values); 1265 if (DBG) log("URI of new row -> " + newUri); 1266 1267 try { 1268 long rowId = ContentUris.parseId(newUri); 1269 if (tracker.getMessageCount() == 1) { 1270 // set the delete selection args for single-part message 1271 tracker.setDeleteWhere(SELECT_BY_ID, new String[]{Long.toString(rowId)}); 1272 } else { 1273 // set the delete selection args for multi-part message 1274 String[] deleteWhereArgs = {address, refNumber, count}; 1275 tracker.setDeleteWhere(tracker.getQueryForSegments(), deleteWhereArgs); 1276 } 1277 return Intents.RESULT_SMS_HANDLED; 1278 } catch (Exception e) { 1279 loge("error parsing URI for new row: " + newUri, e); 1280 return Intents.RESULT_SMS_GENERIC_ERROR; 1281 } 1282 } 1283 1284 /** 1285 * Returns whether the default message format for the current radio technology is 3GPP2. 1286 * @return true if the radio technology uses 3GPP2 format by default, false for 3GPP format 1287 */ 1288 static boolean isCurrentFormat3gpp2() { 1289 int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(); 1290 return (PHONE_TYPE_CDMA == activePhone); 1291 } 1292 1293 /** 1294 * Handler for an {@link InboundSmsTracker} broadcast. Deletes PDUs from the raw table and 1295 * logs the broadcast duration (as an error if the other receivers were especially slow). 1296 */ 1297 private final class SmsBroadcastReceiver extends BroadcastReceiver { 1298 private final String mDeleteWhere; 1299 private final String[] mDeleteWhereArgs; 1300 private long mBroadcastTimeNano; 1301 1302 SmsBroadcastReceiver(InboundSmsTracker tracker) { 1303 mDeleteWhere = tracker.getDeleteWhere(); 1304 mDeleteWhereArgs = tracker.getDeleteWhereArgs(); 1305 mBroadcastTimeNano = System.nanoTime(); 1306 } 1307 1308 @Override 1309 public void onReceive(Context context, Intent intent) { 1310 String action = intent.getAction(); 1311 if (action.equals(Intents.SMS_DELIVER_ACTION)) { 1312 // Now dispatch the notification only intent 1313 intent.setAction(Intents.SMS_RECEIVED_ACTION); 1314 // Allow registered broadcast receivers to get this intent even 1315 // when they are in the background. 1316 intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 1317 intent.setComponent(null); 1318 // All running users will be notified of the received sms. 1319 Bundle options = handleSmsWhitelisting(null); 1320 1321 dispatchIntent(intent, android.Manifest.permission.RECEIVE_SMS, 1322 AppOpsManager.OP_RECEIVE_SMS, 1323 options, this, UserHandle.ALL); 1324 } else if (action.equals(Intents.WAP_PUSH_DELIVER_ACTION)) { 1325 // Now dispatch the notification only intent 1326 intent.setAction(Intents.WAP_PUSH_RECEIVED_ACTION); 1327 intent.setComponent(null); 1328 // Allow registered broadcast receivers to get this intent even 1329 // when they are in the background. 1330 intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 1331 // Only the primary user will receive notification of incoming mms. 1332 // That app will do the actual downloading of the mms. 1333 Bundle options = null; 1334 try { 1335 long duration = mDeviceIdleController.addPowerSaveTempWhitelistAppForMms( 1336 mContext.getPackageName(), 0, "mms-broadcast"); 1337 BroadcastOptions bopts = BroadcastOptions.makeBasic(); 1338 bopts.setTemporaryAppWhitelistDuration(duration); 1339 options = bopts.toBundle(); 1340 } catch (RemoteException e) { 1341 } 1342 1343 String mimeType = intent.getType(); 1344 dispatchIntent(intent, WapPushOverSms.getPermissionForType(mimeType), 1345 WapPushOverSms.getAppOpsPermissionForIntent(mimeType), options, this, 1346 UserHandle.SYSTEM); 1347 } else { 1348 // Now that the intents have been deleted we can clean up the PDU data. 1349 if (!Intents.DATA_SMS_RECEIVED_ACTION.equals(action) 1350 && !Intents.SMS_RECEIVED_ACTION.equals(action) 1351 && !Intents.DATA_SMS_RECEIVED_ACTION.equals(action) 1352 && !Intents.WAP_PUSH_RECEIVED_ACTION.equals(action)) { 1353 loge("unexpected BroadcastReceiver action: " + action); 1354 } 1355 1356 int rc = getResultCode(); 1357 if ((rc != Activity.RESULT_OK) && (rc != Intents.RESULT_SMS_HANDLED)) { 1358 loge("a broadcast receiver set the result code to " + rc 1359 + ", deleting from raw table anyway!"); 1360 } else if (DBG) { 1361 log("successful broadcast, deleting from raw table."); 1362 } 1363 1364 deleteFromRawTable(mDeleteWhere, mDeleteWhereArgs, MARK_DELETED); 1365 sendMessage(EVENT_BROADCAST_COMPLETE); 1366 1367 int durationMillis = (int) ((System.nanoTime() - mBroadcastTimeNano) / 1000000); 1368 if (durationMillis >= 5000) { 1369 loge("Slow ordered broadcast completion time: " + durationMillis + " ms"); 1370 } else if (DBG) { 1371 log("ordered broadcast completed in: " + durationMillis + " ms"); 1372 } 1373 } 1374 } 1375 } 1376 1377 /** 1378 * Callback that handles filtering results by carrier services. 1379 */ 1380 private final class CarrierServicesSmsFilterCallback implements 1381 CarrierServicesSmsFilter.CarrierServicesSmsFilterCallbackInterface { 1382 private final byte[][] mPdus; 1383 private final int mDestPort; 1384 private final String mSmsFormat; 1385 private final SmsBroadcastReceiver mSmsBroadcastReceiver; 1386 private final boolean mUserUnlocked; 1387 1388 CarrierServicesSmsFilterCallback(byte[][] pdus, int destPort, String smsFormat, 1389 SmsBroadcastReceiver smsBroadcastReceiver, boolean userUnlocked) { 1390 mPdus = pdus; 1391 mDestPort = destPort; 1392 mSmsFormat = smsFormat; 1393 mSmsBroadcastReceiver = smsBroadcastReceiver; 1394 mUserUnlocked = userUnlocked; 1395 } 1396 1397 @Override 1398 public void onFilterComplete(int result) { 1399 logv("onFilterComplete: result is " + result); 1400 if ((result & CarrierMessagingService.RECEIVE_OPTIONS_DROP) == 0) { 1401 if (VisualVoicemailSmsFilter.filter(mContext, mPdus, 1402 mSmsFormat, mDestPort, mPhone.getSubId())) { 1403 log("Visual voicemail SMS dropped"); 1404 dropSms(mSmsBroadcastReceiver); 1405 return; 1406 } 1407 1408 if (mUserUnlocked) { 1409 dispatchSmsDeliveryIntent( 1410 mPdus, mSmsFormat, mDestPort, mSmsBroadcastReceiver); 1411 } else { 1412 // Don't do anything further, leave the message in the raw table if the 1413 // credential-encrypted storage is still locked and show the new message 1414 // notification if the message is visible to the user. 1415 if (!isSkipNotifyFlagSet(result)) { 1416 showNewMessageNotification(); 1417 } 1418 sendMessage(EVENT_BROADCAST_COMPLETE); 1419 } 1420 } else { 1421 // Drop this SMS. 1422 dropSms(mSmsBroadcastReceiver); 1423 } 1424 } 1425 } 1426 1427 private void dropSms(SmsBroadcastReceiver receiver) { 1428 // Needs phone package permissions. 1429 deleteFromRawTable(receiver.mDeleteWhere, receiver.mDeleteWhereArgs, MARK_DELETED); 1430 sendMessage(EVENT_BROADCAST_COMPLETE); 1431 } 1432 1433 /** Checks whether the flag to skip new message notification is set in the bitmask returned 1434 * from the carrier app. 1435 */ 1436 private boolean isSkipNotifyFlagSet(int callbackResult) { 1437 return (callbackResult 1438 & RECEIVE_OPTIONS_SKIP_NOTIFY_WHEN_CREDENTIAL_PROTECTED_STORAGE_UNAVAILABLE) > 0; 1439 } 1440 1441 /** 1442 * Log with debug level. 1443 * @param s the string to log 1444 */ 1445 @Override 1446 protected void log(String s) { 1447 Rlog.d(getName(), s); 1448 } 1449 1450 /** 1451 * Log with error level. 1452 * @param s the string to log 1453 */ 1454 @Override 1455 protected void loge(String s) { 1456 Rlog.e(getName(), s); 1457 } 1458 1459 /** 1460 * Log with error level. 1461 * @param s the string to log 1462 * @param e is a Throwable which logs additional information. 1463 */ 1464 @Override 1465 protected void loge(String s, Throwable e) { 1466 Rlog.e(getName(), s, e); 1467 } 1468 1469 /** 1470 * Store a received SMS into Telephony provider 1471 * 1472 * @param intent The intent containing the received SMS 1473 * @return The URI of written message 1474 */ 1475 private Uri writeInboxMessage(Intent intent) { 1476 final SmsMessage[] messages = Telephony.Sms.Intents.getMessagesFromIntent(intent); 1477 if (messages == null || messages.length < 1) { 1478 loge("Failed to parse SMS pdu"); 1479 return null; 1480 } 1481 // Sometimes, SmsMessage.mWrappedSmsMessage is null causing NPE when we access 1482 // the methods on it although the SmsMessage itself is not null. So do this check 1483 // before we do anything on the parsed SmsMessages. 1484 for (final SmsMessage sms : messages) { 1485 try { 1486 sms.getDisplayMessageBody(); 1487 } catch (NullPointerException e) { 1488 loge("NPE inside SmsMessage"); 1489 return null; 1490 } 1491 } 1492 final ContentValues values = parseSmsMessage(messages); 1493 final long identity = Binder.clearCallingIdentity(); 1494 try { 1495 return mContext.getContentResolver().insert(Telephony.Sms.Inbox.CONTENT_URI, values); 1496 } catch (Exception e) { 1497 loge("Failed to persist inbox message", e); 1498 } finally { 1499 Binder.restoreCallingIdentity(identity); 1500 } 1501 return null; 1502 } 1503 1504 /** 1505 * Convert SmsMessage[] into SMS database schema columns 1506 * 1507 * @param msgs The SmsMessage array of the received SMS 1508 * @return ContentValues representing the columns of parsed SMS 1509 */ 1510 private static ContentValues parseSmsMessage(SmsMessage[] msgs) { 1511 final SmsMessage sms = msgs[0]; 1512 final ContentValues values = new ContentValues(); 1513 values.put(Telephony.Sms.Inbox.ADDRESS, sms.getDisplayOriginatingAddress()); 1514 values.put(Telephony.Sms.Inbox.BODY, buildMessageBodyFromPdus(msgs)); 1515 values.put(Telephony.Sms.Inbox.DATE_SENT, sms.getTimestampMillis()); 1516 values.put(Telephony.Sms.Inbox.DATE, System.currentTimeMillis()); 1517 values.put(Telephony.Sms.Inbox.PROTOCOL, sms.getProtocolIdentifier()); 1518 values.put(Telephony.Sms.Inbox.SEEN, 0); 1519 values.put(Telephony.Sms.Inbox.READ, 0); 1520 final String subject = sms.getPseudoSubject(); 1521 if (!TextUtils.isEmpty(subject)) { 1522 values.put(Telephony.Sms.Inbox.SUBJECT, subject); 1523 } 1524 values.put(Telephony.Sms.Inbox.REPLY_PATH_PRESENT, sms.isReplyPathPresent() ? 1 : 0); 1525 values.put(Telephony.Sms.Inbox.SERVICE_CENTER, sms.getServiceCenterAddress()); 1526 return values; 1527 } 1528 1529 /** 1530 * Build up the SMS message body from the SmsMessage array of received SMS 1531 * 1532 * @param msgs The SmsMessage array of the received SMS 1533 * @return The text message body 1534 */ 1535 private static String buildMessageBodyFromPdus(SmsMessage[] msgs) { 1536 if (msgs.length == 1) { 1537 // There is only one part, so grab the body directly. 1538 return replaceFormFeeds(msgs[0].getDisplayMessageBody()); 1539 } else { 1540 // Build up the body from the parts. 1541 StringBuilder body = new StringBuilder(); 1542 for (SmsMessage msg: msgs) { 1543 // getDisplayMessageBody() can NPE if mWrappedMessage inside is null. 1544 body.append(msg.getDisplayMessageBody()); 1545 } 1546 return replaceFormFeeds(body.toString()); 1547 } 1548 } 1549 1550 // Some providers send formfeeds in their messages. Convert those formfeeds to newlines. 1551 private static String replaceFormFeeds(String s) { 1552 return s == null ? "" : s.replace('\f', '\n'); 1553 } 1554 1555 @VisibleForTesting 1556 public PowerManager.WakeLock getWakeLock() { 1557 return mWakeLock; 1558 } 1559 1560 @VisibleForTesting 1561 public int getWakeLockTimeout() { 1562 return mWakeLockTimeout; 1563 } 1564 1565 /** 1566 * Sets the wakelock timeout to {@link timeOut} milliseconds 1567 */ 1568 private void setWakeLockTimeout(int timeOut) { 1569 mWakeLockTimeout = timeOut; 1570 } 1571 1572 /** 1573 * Handler for the broadcast sent when the new message notification is clicked. It launches the 1574 * default SMS app. 1575 */ 1576 private static class NewMessageNotificationActionReceiver extends BroadcastReceiver { 1577 @Override 1578 public void onReceive(Context context, Intent intent) { 1579 if (ACTION_OPEN_SMS_APP.equals(intent.getAction())) { 1580 context.startActivity(context.getPackageManager().getLaunchIntentForPackage( 1581 Telephony.Sms.getDefaultSmsPackage(context))); 1582 } 1583 } 1584 } 1585 1586 /** 1587 * Registers the broadcast receiver to launch the default SMS app when the user clicks the 1588 * new message notification. 1589 */ 1590 static void registerNewMessageNotificationActionHandler(Context context) { 1591 IntentFilter userFilter = new IntentFilter(); 1592 userFilter.addAction(ACTION_OPEN_SMS_APP); 1593 context.registerReceiver(new NewMessageNotificationActionReceiver(), userFilter); 1594 } 1595 } 1596