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