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