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