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.annotation.UnsupportedAppUsage; 23 import android.app.Activity; 24 import android.app.ActivityManager; 25 import android.app.AppOpsManager; 26 import android.app.BroadcastOptions; 27 import android.app.Notification; 28 import android.app.NotificationManager; 29 import android.app.PendingIntent; 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.UserInfo; 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.Build; 46 import android.os.Bundle; 47 import android.os.IDeviceIdleController; 48 import android.os.Message; 49 import android.os.PowerManager; 50 import android.os.RemoteException; 51 import android.os.ServiceManager; 52 import android.os.UserHandle; 53 import android.os.UserManager; 54 import android.os.storage.StorageManager; 55 import android.provider.Telephony; 56 import android.provider.Telephony.Sms.Intents; 57 import android.service.carrier.CarrierMessagingService; 58 import android.telephony.Rlog; 59 import android.telephony.SmsManager; 60 import android.telephony.SmsMessage; 61 import android.telephony.SubscriptionManager; 62 import android.telephony.TelephonyManager; 63 import android.text.TextUtils; 64 import android.util.LocalLog; 65 import android.util.Pair; 66 67 import com.android.internal.R; 68 import com.android.internal.annotations.VisibleForTesting; 69 import com.android.internal.telephony.SmsConstants.MessageClass; 70 import com.android.internal.telephony.metrics.TelephonyMetrics; 71 import com.android.internal.telephony.util.NotificationChannelController; 72 import com.android.internal.util.HexDump; 73 import com.android.internal.util.State; 74 import com.android.internal.util.StateMachine; 75 76 import java.io.ByteArrayOutputStream; 77 import java.io.FileDescriptor; 78 import java.io.PrintWriter; 79 import java.util.Arrays; 80 import java.util.HashMap; 81 import java.util.List; 82 import java.util.Map; 83 84 /** 85 * This class broadcasts incoming SMS messages to interested apps after storing them in 86 * the SmsProvider "raw" table and ACKing them to the SMSC. After each message has been 87 * broadcast, its parts are removed from the raw table. If the device crashes after ACKing 88 * but before the broadcast completes, the pending messages will be rebroadcast on the next boot. 89 * 90 * <p>The state machine starts in {@link IdleState} state. When the {@link SMSDispatcher} receives a 91 * new SMS from the radio, it calls {@link #dispatchNormalMessage}, 92 * which sends a message to the state machine, causing the wakelock to be acquired in 93 * {@link #haltedProcessMessage}, which transitions to {@link DeliveringState} state, where the message 94 * is saved to the raw table, then acknowledged via the {@link SMSDispatcher} which called us. 95 * 96 * <p>After saving the SMS, if the message is complete (either single-part or the final segment 97 * of a multi-part SMS), we broadcast the completed PDUs as an ordered broadcast, then transition to 98 * {@link WaitingState} state to wait for the broadcast to complete. When the local 99 * {@link BroadcastReceiver} is called with the result, it sends {@link #EVENT_BROADCAST_COMPLETE} 100 * to the state machine, causing us to either broadcast the next pending message (if one has 101 * arrived while waiting for the broadcast to complete), or to transition back to the halted state 102 * after all messages are processed. Then the wakelock is released and we wait for the next SMS. 103 */ 104 public abstract class InboundSmsHandler extends StateMachine { 105 protected static final boolean DBG = true; 106 protected static final boolean VDBG = false; // STOPSHIP if true, logs user data 107 108 /** Query projection for checking for duplicate message segments. */ 109 private static final String[] PDU_DELETED_FLAG_PROJECTION = { 110 "pdu", 111 "deleted" 112 }; 113 114 /** Mapping from DB COLUMN to PDU_SEQUENCE_PORT PROJECTION index */ 115 private static final Map<Integer, Integer> PDU_DELETED_FLAG_PROJECTION_INDEX_MAPPING = 116 new HashMap<Integer, Integer>() {{ 117 put(PDU_COLUMN, 0); 118 put(DELETED_FLAG_COLUMN, 1); 119 }}; 120 121 /** Query projection for combining concatenated message segments. */ 122 private static final String[] PDU_SEQUENCE_PORT_PROJECTION = { 123 "pdu", 124 "sequence", 125 "destination_port", 126 "display_originating_addr", 127 "date" 128 }; 129 130 /** Mapping from DB COLUMN to PDU_SEQUENCE_PORT PROJECTION index */ 131 private static final Map<Integer, Integer> PDU_SEQUENCE_PORT_PROJECTION_INDEX_MAPPING = 132 new HashMap<Integer, Integer>() {{ 133 put(PDU_COLUMN, 0); 134 put(SEQUENCE_COLUMN, 1); 135 put(DESTINATION_PORT_COLUMN, 2); 136 put(DISPLAY_ADDRESS_COLUMN, 3); 137 put(DATE_COLUMN, 4); 138 }}; 139 140 public static final int PDU_COLUMN = 0; 141 public static final int SEQUENCE_COLUMN = 1; 142 public static final int DESTINATION_PORT_COLUMN = 2; 143 public static final int DATE_COLUMN = 3; 144 public static final int REFERENCE_NUMBER_COLUMN = 4; 145 public static final int COUNT_COLUMN = 5; 146 public static final int ADDRESS_COLUMN = 6; 147 public static final int ID_COLUMN = 7; 148 public static final int MESSAGE_BODY_COLUMN = 8; 149 public static final int DISPLAY_ADDRESS_COLUMN = 9; 150 public static final int DELETED_FLAG_COLUMN = 10; 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 protected CellBroadcastHandler mCellBroadcastHandler; 232 233 @UnsupportedAppUsage 234 private UserManager mUserManager; 235 236 protected TelephonyMetrics mMetrics = TelephonyMetrics.getInstance(); 237 238 private LocalLog mLocalLog = new LocalLog(64); 239 240 @UnsupportedAppUsage 241 IDeviceIdleController mDeviceIdleController; 242 243 // Delete permanently from raw table 244 private final int DELETE_PERMANENTLY = 1; 245 // Only mark deleted, but keep in db for message de-duping 246 private final int MARK_DELETED = 2; 247 248 private static String ACTION_OPEN_SMS_APP = 249 "com.android.internal.telephony.OPEN_DEFAULT_SMS_APP"; 250 251 /** Timeout for releasing wakelock */ 252 private int mWakeLockTimeout; 253 254 /** Indicates if last SMS was injected. This is used to recognize SMS received over IMS from 255 others in order to update metrics. */ 256 private boolean mLastSmsWasInjected = false; 257 258 /** 259 * Create a new SMS broadcast helper. 260 * @param name the class name for logging 261 * @param context the context of the phone app 262 * @param storageMonitor the SmsStorageMonitor to check for storage availability 263 */ InboundSmsHandler(String name, Context context, SmsStorageMonitor storageMonitor, Phone phone, CellBroadcastHandler cellBroadcastHandler)264 protected InboundSmsHandler(String name, Context context, SmsStorageMonitor storageMonitor, 265 Phone phone, CellBroadcastHandler cellBroadcastHandler) { 266 super(name); 267 268 mContext = context; 269 mStorageMonitor = storageMonitor; 270 mPhone = phone; 271 mCellBroadcastHandler = cellBroadcastHandler; 272 mResolver = context.getContentResolver(); 273 mWapPush = new WapPushOverSms(context); 274 275 boolean smsCapable = mContext.getResources().getBoolean( 276 com.android.internal.R.bool.config_sms_capable); 277 mSmsReceiveDisabled = !TelephonyManager.from(mContext).getSmsReceiveCapableForPhone( 278 mPhone.getPhoneId(), smsCapable); 279 280 PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 281 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, name); 282 mWakeLock.acquire(); // wake lock released after we enter idle state 283 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 284 mDeviceIdleController = TelephonyComponentFactory.getInstance() 285 .inject(IDeviceIdleController.class.getName()).getIDeviceIdleController(); 286 287 addState(mDefaultState); 288 addState(mStartupState, mDefaultState); 289 addState(mIdleState, mDefaultState); 290 addState(mDeliveringState, mDefaultState); 291 addState(mWaitingState, mDeliveringState); 292 293 setInitialState(mStartupState); 294 if (DBG) log("created InboundSmsHandler"); 295 } 296 297 /** 298 * Tell the state machine to quit after processing all messages. 299 */ dispose()300 public void dispose() { 301 quit(); 302 } 303 304 /** 305 * Dispose of the WAP push object and release the wakelock. 306 */ 307 @Override onQuitting()308 protected void onQuitting() { 309 mWapPush.dispose(); 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 (Build.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 // Allow registered broadcast receivers to get this intent even 721 // when they are in the background. 722 intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 723 mContext.sendBroadcast(intent, android.Manifest.permission.RECEIVE_SMS); 724 } 725 acknowledgeLastIncomingSms(success, result, response); 726 } 727 728 /** 729 * Return true if this handler is for 3GPP2 messages; false for 3GPP format. 730 * @return true for the 3GPP2 handler; false for the 3GPP handler 731 */ is3gpp2()732 protected abstract boolean is3gpp2(); 733 734 /** 735 * Dispatch a normal incoming SMS. This is called from {@link #dispatchMessageRadioSpecific} 736 * if no format-specific handling was required. Saves the PDU to the SMS provider raw table, 737 * creates an {@link InboundSmsTracker}, then sends it to the state machine as an 738 * {@link #EVENT_BROADCAST_SMS}. Returns {@link Intents#RESULT_SMS_HANDLED} or an error value. 739 * 740 * @param sms the message to dispatch 741 * @return {@link Intents#RESULT_SMS_HANDLED} if the message was accepted, or an error status 742 */ 743 @UnsupportedAppUsage dispatchNormalMessage(SmsMessageBase sms)744 protected int dispatchNormalMessage(SmsMessageBase sms) { 745 SmsHeader smsHeader = sms.getUserDataHeader(); 746 InboundSmsTracker tracker; 747 748 if ((smsHeader == null) || (smsHeader.concatRef == null)) { 749 // Message is not concatenated. 750 int destPort = -1; 751 if (smsHeader != null && smsHeader.portAddrs != null) { 752 // The message was sent to a port. 753 destPort = smsHeader.portAddrs.destPort; 754 if (DBG) log("destination port: " + destPort); 755 } 756 tracker = TelephonyComponentFactory.getInstance() 757 .inject(InboundSmsTracker.class.getName()) 758 .makeInboundSmsTracker(sms.getPdu(), 759 sms.getTimestampMillis(), destPort, is3gpp2(), false, 760 sms.getOriginatingAddress(), sms.getDisplayOriginatingAddress(), 761 sms.getMessageBody(), sms.getMessageClass() == MessageClass.CLASS_0); 762 } else { 763 // Create a tracker for this message segment. 764 SmsHeader.ConcatRef concatRef = smsHeader.concatRef; 765 SmsHeader.PortAddrs portAddrs = smsHeader.portAddrs; 766 int destPort = (portAddrs != null ? portAddrs.destPort : -1); 767 tracker = TelephonyComponentFactory.getInstance() 768 .inject(InboundSmsTracker.class.getName()) 769 .makeInboundSmsTracker(sms.getPdu(), 770 sms.getTimestampMillis(), destPort, is3gpp2(), sms.getOriginatingAddress(), 771 sms.getDisplayOriginatingAddress(), concatRef.refNumber, concatRef.seqNumber, 772 concatRef.msgCount, false, sms.getMessageBody(), 773 sms.getMessageClass() == MessageClass.CLASS_0); 774 } 775 776 if (VDBG) log("created tracker: " + tracker); 777 778 // de-duping is done only for text messages 779 // destPort = -1 indicates text messages, otherwise it's a data sms 780 return addTrackerToRawTableAndSendMessage(tracker, 781 tracker.getDestPort() == -1 /* de-dup if text message */); 782 } 783 784 /** 785 * Helper to add the tracker to the raw table and then send a message to broadcast it, if 786 * successful. Returns the SMS intent status to return to the SMSC. 787 * @param tracker the tracker to save to the raw table and then deliver 788 * @return {@link Intents#RESULT_SMS_HANDLED} or {@link Intents#RESULT_SMS_GENERIC_ERROR} 789 * or {@link Intents#RESULT_SMS_DUPLICATED} 790 */ addTrackerToRawTableAndSendMessage(InboundSmsTracker tracker, boolean deDup)791 protected int addTrackerToRawTableAndSendMessage(InboundSmsTracker tracker, boolean deDup) { 792 switch(addTrackerToRawTable(tracker, deDup)) { 793 case Intents.RESULT_SMS_HANDLED: 794 sendMessage(EVENT_BROADCAST_SMS, tracker); 795 return Intents.RESULT_SMS_HANDLED; 796 797 case Intents.RESULT_SMS_DUPLICATED: 798 return Intents.RESULT_SMS_HANDLED; 799 800 case Intents.RESULT_SMS_GENERIC_ERROR: 801 default: 802 return Intents.RESULT_SMS_GENERIC_ERROR; 803 } 804 } 805 806 /** 807 * Process the inbound SMS segment. If the message is complete, send it as an ordered 808 * broadcast to interested receivers and return true. If the message is a segment of an 809 * incomplete multi-part SMS, return false. 810 * @param tracker the tracker containing the message segment to process 811 * @return true if an ordered broadcast was sent; false if waiting for more message segments 812 */ 813 @UnsupportedAppUsage processMessagePart(InboundSmsTracker tracker)814 private boolean processMessagePart(InboundSmsTracker tracker) { 815 int messageCount = tracker.getMessageCount(); 816 byte[][] pdus; 817 long[] timestamps; 818 int destPort = tracker.getDestPort(); 819 boolean block = false; 820 String address = tracker.getAddress(); 821 822 // Do not process when the message count is invalid. 823 if (messageCount <= 0) { 824 loge("processMessagePart: returning false due to invalid message count " 825 + messageCount); 826 return false; 827 } 828 829 if (messageCount == 1) { 830 // single-part message 831 pdus = new byte[][]{tracker.getPdu()}; 832 timestamps = new long[]{tracker.getTimestamp()}; 833 block = BlockChecker.isBlocked(mContext, tracker.getDisplayAddress(), null); 834 } else { 835 // multi-part message 836 Cursor cursor = null; 837 try { 838 // used by several query selection arguments 839 String refNumber = Integer.toString(tracker.getReferenceNumber()); 840 String count = Integer.toString(tracker.getMessageCount()); 841 842 // query for all segments and broadcast message if we have all the parts 843 String[] whereArgs = {address, refNumber, count}; 844 cursor = mResolver.query(sRawUri, PDU_SEQUENCE_PORT_PROJECTION, 845 tracker.getQueryForSegments(), whereArgs, null); 846 847 int cursorCount = cursor.getCount(); 848 if (cursorCount < messageCount) { 849 // Wait for the other message parts to arrive. It's also possible for the last 850 // segment to arrive before processing the EVENT_BROADCAST_SMS for one of the 851 // earlier segments. In that case, the broadcast will be sent as soon as all 852 // segments are in the table, and any later EVENT_BROADCAST_SMS messages will 853 // get a row count of 0 and return. 854 return false; 855 } 856 857 // All the parts are in place, deal with them 858 pdus = new byte[messageCount][]; 859 timestamps = new long[messageCount]; 860 while (cursor.moveToNext()) { 861 // subtract offset to convert sequence to 0-based array index 862 int index = cursor.getInt(PDU_SEQUENCE_PORT_PROJECTION_INDEX_MAPPING 863 .get(SEQUENCE_COLUMN)) - tracker.getIndexOffset(); 864 865 // The invalid PDUs can be received and stored in the raw table. The range 866 // check ensures the process not crash even if the seqNumber in the 867 // UserDataHeader is invalid. 868 if (index >= pdus.length || index < 0) { 869 loge(String.format( 870 "processMessagePart: invalid seqNumber = %d, messageCount = %d", 871 index + tracker.getIndexOffset(), 872 messageCount)); 873 continue; 874 } 875 876 pdus[index] = HexDump.hexStringToByteArray(cursor.getString( 877 PDU_SEQUENCE_PORT_PROJECTION_INDEX_MAPPING.get(PDU_COLUMN))); 878 879 // Read the destination port from the first segment (needed for CDMA WAP PDU). 880 // It's not a bad idea to prefer the port from the first segment in other cases. 881 if (index == 0 && !cursor.isNull(PDU_SEQUENCE_PORT_PROJECTION_INDEX_MAPPING 882 .get(DESTINATION_PORT_COLUMN))) { 883 int port = cursor.getInt(PDU_SEQUENCE_PORT_PROJECTION_INDEX_MAPPING 884 .get(DESTINATION_PORT_COLUMN)); 885 // strip format flags and convert to real port number, or -1 886 port = InboundSmsTracker.getRealDestPort(port); 887 if (port != -1) { 888 destPort = port; 889 } 890 } 891 892 timestamps[index] = cursor.getLong( 893 PDU_SEQUENCE_PORT_PROJECTION_INDEX_MAPPING.get(DATE_COLUMN)); 894 895 // check if display address should be blocked or not 896 if (!block) { 897 // Depending on the nature of the gateway, the display origination address 898 // is either derived from the content of the SMS TP-OA field, or the TP-OA 899 // field contains a generic gateway address and the from address is added 900 // at the beginning in the message body. In that case only the first SMS 901 // (part of Multi-SMS) comes with the display originating address which 902 // could be used for block checking purpose. 903 block = BlockChecker.isBlocked(mContext, 904 cursor.getString(PDU_SEQUENCE_PORT_PROJECTION_INDEX_MAPPING 905 .get(DISPLAY_ADDRESS_COLUMN)), null); 906 } 907 } 908 } catch (SQLException e) { 909 loge("Can't access multipart SMS database", e); 910 return false; 911 } finally { 912 if (cursor != null) { 913 cursor.close(); 914 } 915 } 916 } 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.is3gpp2() ? SmsConstants.FORMAT_3GPP : SmsConstants.FORMAT_3GPP2); 921 if (destPort != SmsHeader.PORT_WAP_PUSH) { 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 SmsBroadcastReceiver resultReceiver = new SmsBroadcastReceiver(tracker); 937 938 if (!mUserManager.isUserUnlocked()) { 939 return processMessagePartWithUserLocked(tracker, pdus, destPort, resultReceiver); 940 } 941 942 if (destPort == SmsHeader.PORT_WAP_PUSH) { 943 // Build up the data stream 944 ByteArrayOutputStream output = new ByteArrayOutputStream(); 945 for (byte[] pdu : pdus) { 946 // 3GPP needs to extract the User Data from the PDU; 3GPP2 has already done this 947 if (!tracker.is3gpp2()) { 948 SmsMessage msg = SmsMessage.createFromPdu(pdu, SmsConstants.FORMAT_3GPP); 949 if (msg != null) { 950 pdu = msg.getUserData(); 951 } else { 952 loge("processMessagePart: SmsMessage.createFromPdu returned null"); 953 mMetrics.writeIncomingWapPush(mPhone.getPhoneId(), mLastSmsWasInjected, 954 format, timestamps, false); 955 return false; 956 } 957 } 958 output.write(pdu, 0, pdu.length); 959 } 960 int result = mWapPush.dispatchWapPdu(output.toByteArray(), resultReceiver, 961 this, address); 962 if (DBG) log("dispatchWapPdu() returned " + result); 963 // Add result of WAP-PUSH into metrics. RESULT_SMS_HANDLED indicates that the WAP-PUSH 964 // needs to be ignored, so treating it as a success case. 965 if (result == Activity.RESULT_OK || result == Intents.RESULT_SMS_HANDLED) { 966 mMetrics.writeIncomingWapPush(mPhone.getPhoneId(), mLastSmsWasInjected, 967 format, timestamps, true); 968 } else { 969 mMetrics.writeIncomingWapPush(mPhone.getPhoneId(), mLastSmsWasInjected, 970 format, timestamps, false); 971 } 972 // result is Activity.RESULT_OK if an ordered broadcast was sent 973 if (result == Activity.RESULT_OK) { 974 return true; 975 } else { 976 deleteFromRawTable(tracker.getDeleteWhere(), tracker.getDeleteWhereArgs(), 977 MARK_DELETED); 978 return false; 979 } 980 } 981 982 if (block) { 983 deleteFromRawTable(tracker.getDeleteWhere(), tracker.getDeleteWhereArgs(), 984 DELETE_PERMANENTLY); 985 return false; 986 } 987 988 boolean filterInvoked = filterSms( 989 pdus, destPort, tracker, resultReceiver, true /* userUnlocked */); 990 991 if (!filterInvoked) { 992 dispatchSmsDeliveryIntent(pdus, tracker.getFormat(), destPort, resultReceiver, 993 tracker.isClass0()); 994 } 995 996 return true; 997 } 998 999 /** 1000 * Processes the message part while the credential-encrypted storage is still locked. 1001 * 1002 * <p>If the message is a regular MMS, show a new message notification. If the message is a 1003 * SMS, ask the carrier app to filter it and show the new message notification if the carrier 1004 * app asks to keep the message. 1005 * 1006 * @return true if an ordered broadcast was sent to the carrier app; false otherwise. 1007 */ processMessagePartWithUserLocked(InboundSmsTracker tracker, byte[][] pdus, int destPort, SmsBroadcastReceiver resultReceiver)1008 private boolean processMessagePartWithUserLocked(InboundSmsTracker tracker, 1009 byte[][] pdus, int destPort, SmsBroadcastReceiver resultReceiver) { 1010 log("Credential-encrypted storage not available. Port: " + destPort); 1011 if (destPort == SmsHeader.PORT_WAP_PUSH && mWapPush.isWapPushForMms(pdus[0], this)) { 1012 showNewMessageNotification(); 1013 return false; 1014 } 1015 if (destPort == -1) { 1016 // This is a regular SMS - hand it to the carrier or system app for filtering. 1017 boolean filterInvoked = filterSms( 1018 pdus, destPort, tracker, resultReceiver, false /* userUnlocked */); 1019 if (filterInvoked) { 1020 // filter invoked, wait for it to return the result. 1021 return true; 1022 } else { 1023 // filter not invoked, show the notification and do nothing further. 1024 showNewMessageNotification(); 1025 return false; 1026 } 1027 } 1028 return false; 1029 } 1030 1031 @UnsupportedAppUsage showNewMessageNotification()1032 private void showNewMessageNotification() { 1033 // Do not show the notification on non-FBE devices. 1034 if (!StorageManager.isFileEncryptedNativeOrEmulated()) { 1035 return; 1036 } 1037 log("Show new message notification."); 1038 PendingIntent intent = PendingIntent.getBroadcast( 1039 mContext, 1040 0, 1041 new Intent(ACTION_OPEN_SMS_APP), 1042 PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE); 1043 Notification.Builder mBuilder = new Notification.Builder(mContext) 1044 .setSmallIcon(com.android.internal.R.drawable.sym_action_chat) 1045 .setAutoCancel(true) 1046 .setVisibility(Notification.VISIBILITY_PUBLIC) 1047 .setDefaults(Notification.DEFAULT_ALL) 1048 .setContentTitle(mContext.getString(R.string.new_sms_notification_title)) 1049 .setContentText(mContext.getString(R.string.new_sms_notification_content)) 1050 .setContentIntent(intent) 1051 .setChannelId(NotificationChannelController.CHANNEL_ID_SMS); 1052 NotificationManager mNotificationManager = 1053 (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); 1054 mNotificationManager.notify( 1055 NOTIFICATION_TAG, NOTIFICATION_ID_NEW_MESSAGE, mBuilder.build()); 1056 } 1057 cancelNewMessageNotification(Context context)1058 static void cancelNewMessageNotification(Context context) { 1059 NotificationManager mNotificationManager = 1060 (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); 1061 mNotificationManager.cancel(InboundSmsHandler.NOTIFICATION_TAG, 1062 InboundSmsHandler.NOTIFICATION_ID_NEW_MESSAGE); 1063 } 1064 1065 /** 1066 * Filters the SMS. 1067 * 1068 * <p>currently 3 filters exists: the carrier package, the system package, and the 1069 * VisualVoicemailSmsFilter. 1070 * 1071 * <p>The filtering process is: 1072 * 1073 * <p>If the carrier package exists, the SMS will be filtered with it first. If the carrier 1074 * package did not drop the SMS, then the VisualVoicemailSmsFilter will filter it in the 1075 * callback. 1076 * 1077 * <p>If the carrier package does not exists, we will let the VisualVoicemailSmsFilter filter 1078 * it. If the SMS passed the filter, then we will try to find the system package to do the 1079 * filtering. 1080 * 1081 * @return true if a filter is invoked and the SMS processing flow is diverted, false otherwise. 1082 */ filterSms(byte[][] pdus, int destPort, InboundSmsTracker tracker, SmsBroadcastReceiver resultReceiver, boolean userUnlocked)1083 private boolean filterSms(byte[][] pdus, int destPort, 1084 InboundSmsTracker tracker, SmsBroadcastReceiver resultReceiver, boolean userUnlocked) { 1085 CarrierServicesSmsFilterCallback filterCallback = 1086 new CarrierServicesSmsFilterCallback( 1087 pdus, destPort, tracker.getFormat(), resultReceiver, userUnlocked, 1088 tracker.isClass0()); 1089 CarrierServicesSmsFilter carrierServicesFilter = new CarrierServicesSmsFilter( 1090 mContext, mPhone, pdus, destPort, tracker.getFormat(), 1091 filterCallback, getName(), mLocalLog); 1092 if (carrierServicesFilter.filter()) { 1093 return true; 1094 } 1095 1096 if (VisualVoicemailSmsFilter.filter( 1097 mContext, pdus, tracker.getFormat(), destPort, mPhone.getSubId())) { 1098 log("Visual voicemail SMS dropped"); 1099 dropSms(resultReceiver); 1100 return true; 1101 } 1102 1103 return false; 1104 } 1105 1106 /** 1107 * Dispatch the intent with the specified permission, appOp, and result receiver, using 1108 * this state machine's handler thread to run the result receiver. 1109 * 1110 * @param intent the intent to broadcast 1111 * @param permission receivers are required to have this permission 1112 * @param appOp app op that is being performed when dispatching to a receiver 1113 * @param user user to deliver the intent to 1114 */ 1115 @UnsupportedAppUsage dispatchIntent(Intent intent, String permission, int appOp, Bundle opts, BroadcastReceiver resultReceiver, UserHandle user)1116 public void dispatchIntent(Intent intent, String permission, int appOp, 1117 Bundle opts, BroadcastReceiver resultReceiver, UserHandle user) { 1118 intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT); 1119 final String action = intent.getAction(); 1120 if (Intents.SMS_DELIVER_ACTION.equals(action) 1121 || Intents.SMS_RECEIVED_ACTION.equals(action) 1122 || Intents.WAP_PUSH_DELIVER_ACTION.equals(action) 1123 || Intents.WAP_PUSH_RECEIVED_ACTION.equals(action)) { 1124 // Some intents need to be delivered with high priority: 1125 // SMS_DELIVER, SMS_RECEIVED, WAP_PUSH_DELIVER, WAP_PUSH_RECEIVED 1126 // In some situations, like after boot up or system under load, normal 1127 // intent delivery could take a long time. 1128 // This flag should only be set for intents for visible, timely operations 1129 // which is true for the intents above. 1130 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); 1131 } 1132 SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId()); 1133 if (user.equals(UserHandle.ALL)) { 1134 // Get a list of currently started users. 1135 int[] users = null; 1136 try { 1137 users = ActivityManager.getService().getRunningUserIds(); 1138 } catch (RemoteException re) { 1139 } 1140 if (users == null) { 1141 users = new int[] {user.getIdentifier()}; 1142 } 1143 // Deliver the broadcast only to those running users that are permitted 1144 // by user policy. 1145 for (int i = users.length - 1; i >= 0; i--) { 1146 UserHandle targetUser = new UserHandle(users[i]); 1147 if (users[i] != UserHandle.USER_SYSTEM) { 1148 // Is the user not allowed to use SMS? 1149 if (mUserManager.hasUserRestriction(UserManager.DISALLOW_SMS, targetUser)) { 1150 continue; 1151 } 1152 // Skip unknown users and managed profiles as well 1153 UserInfo info = mUserManager.getUserInfo(users[i]); 1154 if (info == null || info.isManagedProfile()) { 1155 continue; 1156 } 1157 } 1158 // Only pass in the resultReceiver when the USER_SYSTEM is processed. 1159 mContext.sendOrderedBroadcastAsUser(intent, targetUser, permission, appOp, opts, 1160 users[i] == UserHandle.USER_SYSTEM ? resultReceiver : null, 1161 getHandler(), Activity.RESULT_OK, null, null); 1162 } 1163 } else { 1164 mContext.sendOrderedBroadcastAsUser(intent, user, permission, appOp, opts, 1165 resultReceiver, getHandler(), Activity.RESULT_OK, null, null); 1166 } 1167 } 1168 1169 /** 1170 * Helper for {@link SmsBroadcastUndelivered} to delete an old message in the raw table. 1171 */ 1172 @UnsupportedAppUsage deleteFromRawTable(String deleteWhere, String[] deleteWhereArgs, int deleteType)1173 private void deleteFromRawTable(String deleteWhere, String[] deleteWhereArgs, 1174 int deleteType) { 1175 Uri uri = deleteType == DELETE_PERMANENTLY ? sRawUriPermanentDelete : sRawUri; 1176 int rows = mResolver.delete(uri, deleteWhere, deleteWhereArgs); 1177 if (rows == 0) { 1178 loge("No rows were deleted from raw table!"); 1179 } else if (DBG) { 1180 log("Deleted " + rows + " rows from raw table."); 1181 } 1182 } 1183 1184 @UnsupportedAppUsage handleSmsWhitelisting(ComponentName target, boolean bgActivityStartAllowed)1185 private Bundle handleSmsWhitelisting(ComponentName target, boolean bgActivityStartAllowed) { 1186 String pkgName; 1187 String reason; 1188 if (target != null) { 1189 pkgName = target.getPackageName(); 1190 reason = "sms-app"; 1191 } else { 1192 pkgName = mContext.getPackageName(); 1193 reason = "sms-broadcast"; 1194 } 1195 BroadcastOptions bopts = null; 1196 Bundle bundle = null; 1197 if (bgActivityStartAllowed) { 1198 bopts = BroadcastOptions.makeBasic(); 1199 bopts.setBackgroundActivityStartsAllowed(true); 1200 bundle = bopts.toBundle(); 1201 } 1202 try { 1203 long duration = mDeviceIdleController.addPowerSaveTempWhitelistAppForSms( 1204 pkgName, 0, reason); 1205 if (bopts == null) bopts = BroadcastOptions.makeBasic(); 1206 bopts.setTemporaryAppWhitelistDuration(duration); 1207 bundle = bopts.toBundle(); 1208 } catch (RemoteException e) { 1209 } 1210 1211 return bundle; 1212 } 1213 1214 /** 1215 * Creates and dispatches the intent to the default SMS app, appropriate port or via the {@link 1216 * AppSmsManager}. 1217 * 1218 * @param pdus message pdus 1219 * @param format the message format, typically "3gpp" or "3gpp2" 1220 * @param destPort the destination port 1221 * @param resultReceiver the receiver handling the delivery result 1222 */ dispatchSmsDeliveryIntent(byte[][] pdus, String format, int destPort, SmsBroadcastReceiver resultReceiver, boolean isClass0)1223 private void dispatchSmsDeliveryIntent(byte[][] pdus, String format, int destPort, 1224 SmsBroadcastReceiver resultReceiver, boolean isClass0) { 1225 Intent intent = new Intent(); 1226 intent.putExtra("pdus", pdus); 1227 intent.putExtra("format", format); 1228 1229 if (destPort == -1) { 1230 intent.setAction(Intents.SMS_DELIVER_ACTION); 1231 // Direct the intent to only the default SMS app. If we can't find a default SMS app 1232 // then sent it to all broadcast receivers. 1233 // We are deliberately delivering to the primary user's default SMS App. 1234 ComponentName componentName = SmsApplication.getDefaultSmsApplication(mContext, true); 1235 if (componentName != null) { 1236 // Deliver SMS message only to this receiver. 1237 intent.setComponent(componentName); 1238 log("Delivering SMS to: " + componentName.getPackageName() + 1239 " " + componentName.getClassName()); 1240 } else { 1241 intent.setComponent(null); 1242 } 1243 1244 // TODO: Validate that this is the right place to store the SMS. 1245 if (SmsManager.getDefault().getAutoPersisting()) { 1246 final Uri uri = writeInboxMessage(intent); 1247 if (uri != null) { 1248 // Pass this to SMS apps so that they know where it is stored 1249 intent.putExtra("uri", uri.toString()); 1250 } 1251 } 1252 1253 // Handle app specific sms messages. 1254 AppSmsManager appManager = mPhone.getAppSmsManager(); 1255 if (appManager.handleSmsReceivedIntent(intent)) { 1256 // The AppSmsManager handled this intent, we're done. 1257 dropSms(resultReceiver); 1258 return; 1259 } 1260 } else { 1261 intent.setAction(Intents.DATA_SMS_RECEIVED_ACTION); 1262 Uri uri = Uri.parse("sms://localhost:" + destPort); 1263 intent.setData(uri); 1264 intent.setComponent(null); 1265 // Allow registered broadcast receivers to get this intent even 1266 // when they are in the background. 1267 intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 1268 } 1269 1270 Bundle options = handleSmsWhitelisting(intent.getComponent(), isClass0); 1271 dispatchIntent(intent, android.Manifest.permission.RECEIVE_SMS, 1272 AppOpsManager.OP_RECEIVE_SMS, options, resultReceiver, UserHandle.SYSTEM); 1273 } 1274 1275 /** 1276 * Function to detect and handle duplicate messages. If the received message should replace an 1277 * existing message in the raw db, this function deletes the existing message. If an existing 1278 * message takes priority (for eg, existing message has already been broadcast), then this new 1279 * message should be dropped. 1280 * @return true if the message represented by the passed in tracker should be dropped, 1281 * false otherwise 1282 */ checkAndHandleDuplicate(InboundSmsTracker tracker)1283 private boolean checkAndHandleDuplicate(InboundSmsTracker tracker) throws SQLException { 1284 Pair<String, String[]> exactMatchQuery = tracker.getExactMatchDupDetectQuery(); 1285 1286 Cursor cursor = null; 1287 try { 1288 // Check for duplicate message segments 1289 cursor = mResolver.query(sRawUri, PDU_DELETED_FLAG_PROJECTION, exactMatchQuery.first, 1290 exactMatchQuery.second, null); 1291 1292 // moveToNext() returns false if no duplicates were found 1293 if (cursor != null && cursor.moveToNext()) { 1294 if (cursor.getCount() != 1) { 1295 loge("Exact match query returned " + cursor.getCount() + " rows"); 1296 } 1297 1298 // if the exact matching row is marked deleted, that means this message has already 1299 // been received and processed, and can be discarded as dup 1300 if (cursor.getInt( 1301 PDU_DELETED_FLAG_PROJECTION_INDEX_MAPPING.get(DELETED_FLAG_COLUMN)) == 1) { 1302 loge("Discarding duplicate message segment: " + tracker); 1303 logDupPduMismatch(cursor, tracker); 1304 return true; // reject message 1305 } else { 1306 // exact match duplicate is not marked deleted. If it is a multi-part segment, 1307 // the code below for inexact match will take care of it. If it is a single 1308 // part message, handle it here. 1309 if (tracker.getMessageCount() == 1) { 1310 // delete the old message segment permanently 1311 deleteFromRawTable(exactMatchQuery.first, exactMatchQuery.second, 1312 DELETE_PERMANENTLY); 1313 loge("Replacing duplicate message: " + tracker); 1314 logDupPduMismatch(cursor, tracker); 1315 } 1316 } 1317 } 1318 } finally { 1319 if (cursor != null) { 1320 cursor.close(); 1321 } 1322 } 1323 1324 // The code above does an exact match. Multi-part message segments need an additional check 1325 // on top of that: if there is a message segment that conflicts this new one (may not be an 1326 // exact match), replace the old message segment with this one. 1327 if (tracker.getMessageCount() > 1) { 1328 Pair<String, String[]> inexactMatchQuery = tracker.getInexactMatchDupDetectQuery(); 1329 cursor = null; 1330 try { 1331 // Check for duplicate message segments 1332 cursor = mResolver.query(sRawUri, PDU_DELETED_FLAG_PROJECTION, 1333 inexactMatchQuery.first, inexactMatchQuery.second, null); 1334 1335 // moveToNext() returns false if no duplicates were found 1336 if (cursor != null && cursor.moveToNext()) { 1337 if (cursor.getCount() != 1) { 1338 loge("Inexact match query returned " + cursor.getCount() + " rows"); 1339 } 1340 // delete the old message segment permanently 1341 deleteFromRawTable(inexactMatchQuery.first, inexactMatchQuery.second, 1342 DELETE_PERMANENTLY); 1343 loge("Replacing duplicate message segment: " + tracker); 1344 logDupPduMismatch(cursor, tracker); 1345 } 1346 } finally { 1347 if (cursor != null) { 1348 cursor.close(); 1349 } 1350 } 1351 } 1352 1353 return false; 1354 } 1355 logDupPduMismatch(Cursor cursor, InboundSmsTracker tracker)1356 private void logDupPduMismatch(Cursor cursor, InboundSmsTracker tracker) { 1357 String oldPduString = cursor.getString( 1358 PDU_DELETED_FLAG_PROJECTION_INDEX_MAPPING.get(PDU_COLUMN)); 1359 byte[] pdu = tracker.getPdu(); 1360 byte[] oldPdu = HexDump.hexStringToByteArray(oldPduString); 1361 if (!Arrays.equals(oldPdu, tracker.getPdu())) { 1362 loge("Warning: dup message PDU of length " + pdu.length 1363 + " is different from existing PDU of length " + oldPdu.length); 1364 } 1365 } 1366 1367 /** 1368 * Insert a message PDU into the raw table so we can acknowledge it immediately. 1369 * If the device crashes before the broadcast to listeners completes, it will be delivered 1370 * from the raw table on the next device boot. For single-part messages, the deleteWhere 1371 * and deleteWhereArgs fields of the tracker will be set to delete the correct row after 1372 * the ordered broadcast completes. 1373 * 1374 * @param tracker the tracker to add to the raw table 1375 * @return true on success; false on failure to write to database 1376 */ addTrackerToRawTable(InboundSmsTracker tracker, boolean deDup)1377 private int addTrackerToRawTable(InboundSmsTracker tracker, boolean deDup) { 1378 if (deDup) { 1379 try { 1380 if (checkAndHandleDuplicate(tracker)) { 1381 return Intents.RESULT_SMS_DUPLICATED; // reject message 1382 } 1383 } catch (SQLException e) { 1384 loge("Can't access SMS database", e); 1385 return Intents.RESULT_SMS_GENERIC_ERROR; // reject message 1386 } 1387 } else { 1388 logd("Skipped message de-duping logic"); 1389 } 1390 1391 String address = tracker.getAddress(); 1392 String refNumber = Integer.toString(tracker.getReferenceNumber()); 1393 String count = Integer.toString(tracker.getMessageCount()); 1394 ContentValues values = tracker.getContentValues(); 1395 1396 if (VDBG) log("adding content values to raw table: " + values.toString()); 1397 Uri newUri = mResolver.insert(sRawUri, values); 1398 if (DBG) log("URI of new row -> " + newUri); 1399 1400 try { 1401 long rowId = ContentUris.parseId(newUri); 1402 if (tracker.getMessageCount() == 1) { 1403 // set the delete selection args for single-part message 1404 tracker.setDeleteWhere(SELECT_BY_ID, new String[]{Long.toString(rowId)}); 1405 } else { 1406 // set the delete selection args for multi-part message 1407 String[] deleteWhereArgs = {address, refNumber, count}; 1408 tracker.setDeleteWhere(tracker.getQueryForSegments(), deleteWhereArgs); 1409 } 1410 return Intents.RESULT_SMS_HANDLED; 1411 } catch (Exception e) { 1412 loge("error parsing URI for new row: " + newUri, e); 1413 return Intents.RESULT_SMS_GENERIC_ERROR; 1414 } 1415 } 1416 1417 /** 1418 * Returns whether the default message format for the current radio technology is 3GPP2. 1419 * @return true if the radio technology uses 3GPP2 format by default, false for 3GPP format 1420 */ isCurrentFormat3gpp2()1421 static boolean isCurrentFormat3gpp2() { 1422 int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(); 1423 return (PHONE_TYPE_CDMA == activePhone); 1424 } 1425 1426 /** 1427 * Handler for an {@link InboundSmsTracker} broadcast. Deletes PDUs from the raw table and 1428 * logs the broadcast duration (as an error if the other receivers were especially slow). 1429 */ 1430 private final class SmsBroadcastReceiver extends BroadcastReceiver { 1431 @UnsupportedAppUsage 1432 private final String mDeleteWhere; 1433 @UnsupportedAppUsage 1434 private final String[] mDeleteWhereArgs; 1435 private long mBroadcastTimeNano; 1436 SmsBroadcastReceiver(InboundSmsTracker tracker)1437 SmsBroadcastReceiver(InboundSmsTracker tracker) { 1438 mDeleteWhere = tracker.getDeleteWhere(); 1439 mDeleteWhereArgs = tracker.getDeleteWhereArgs(); 1440 mBroadcastTimeNano = System.nanoTime(); 1441 } 1442 1443 @Override onReceive(Context context, Intent intent)1444 public void onReceive(Context context, Intent intent) { 1445 String action = intent.getAction(); 1446 if (action.equals(Intents.SMS_DELIVER_ACTION)) { 1447 // Now dispatch the notification only intent 1448 intent.setAction(Intents.SMS_RECEIVED_ACTION); 1449 // Allow registered broadcast receivers to get this intent even 1450 // when they are in the background. 1451 intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 1452 intent.setComponent(null); 1453 // All running users will be notified of the received sms. 1454 Bundle options = handleSmsWhitelisting(null, false /* bgActivityStartAllowed */); 1455 1456 dispatchIntent(intent, android.Manifest.permission.RECEIVE_SMS, 1457 AppOpsManager.OP_RECEIVE_SMS, 1458 options, this, UserHandle.ALL); 1459 } else if (action.equals(Intents.WAP_PUSH_DELIVER_ACTION)) { 1460 // Now dispatch the notification only intent 1461 intent.setAction(Intents.WAP_PUSH_RECEIVED_ACTION); 1462 intent.setComponent(null); 1463 // Allow registered broadcast receivers to get this intent even 1464 // when they are in the background. 1465 intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 1466 // Only the primary user will receive notification of incoming mms. 1467 // That app will do the actual downloading of the mms. 1468 Bundle options = null; 1469 try { 1470 long duration = mDeviceIdleController.addPowerSaveTempWhitelistAppForMms( 1471 mContext.getPackageName(), 0, "mms-broadcast"); 1472 BroadcastOptions bopts = BroadcastOptions.makeBasic(); 1473 bopts.setTemporaryAppWhitelistDuration(duration); 1474 options = bopts.toBundle(); 1475 } catch (RemoteException e) { 1476 } 1477 1478 String mimeType = intent.getType(); 1479 dispatchIntent(intent, WapPushOverSms.getPermissionForType(mimeType), 1480 WapPushOverSms.getAppOpsPermissionForIntent(mimeType), options, this, 1481 UserHandle.SYSTEM); 1482 } else { 1483 // Now that the intents have been deleted we can clean up the PDU data. 1484 if (!Intents.DATA_SMS_RECEIVED_ACTION.equals(action) 1485 && !Intents.SMS_RECEIVED_ACTION.equals(action) 1486 && !Intents.DATA_SMS_RECEIVED_ACTION.equals(action) 1487 && !Intents.WAP_PUSH_RECEIVED_ACTION.equals(action)) { 1488 loge("unexpected BroadcastReceiver action: " + action); 1489 } 1490 1491 int rc = getResultCode(); 1492 if ((rc != Activity.RESULT_OK) && (rc != Intents.RESULT_SMS_HANDLED)) { 1493 loge("a broadcast receiver set the result code to " + rc 1494 + ", deleting from raw table anyway!"); 1495 } else if (DBG) { 1496 log("successful broadcast, deleting from raw table."); 1497 } 1498 1499 deleteFromRawTable(mDeleteWhere, mDeleteWhereArgs, MARK_DELETED); 1500 sendMessage(EVENT_BROADCAST_COMPLETE); 1501 1502 int durationMillis = (int) ((System.nanoTime() - mBroadcastTimeNano) / 1000000); 1503 if (durationMillis >= 5000) { 1504 loge("Slow ordered broadcast completion time: " + durationMillis + " ms"); 1505 } else if (DBG) { 1506 log("ordered broadcast completed in: " + durationMillis + " ms"); 1507 } 1508 } 1509 } 1510 } 1511 1512 /** 1513 * Callback that handles filtering results by carrier services. 1514 */ 1515 private final class CarrierServicesSmsFilterCallback implements 1516 CarrierServicesSmsFilter.CarrierServicesSmsFilterCallbackInterface { 1517 private final byte[][] mPdus; 1518 private final int mDestPort; 1519 private final String mSmsFormat; 1520 private final SmsBroadcastReceiver mSmsBroadcastReceiver; 1521 private final boolean mUserUnlocked; 1522 private final boolean mIsClass0; 1523 CarrierServicesSmsFilterCallback(byte[][] pdus, int destPort, String smsFormat, SmsBroadcastReceiver smsBroadcastReceiver, boolean userUnlocked, boolean isClass0)1524 CarrierServicesSmsFilterCallback(byte[][] pdus, int destPort, String smsFormat, 1525 SmsBroadcastReceiver smsBroadcastReceiver, boolean userUnlocked, 1526 boolean isClass0) { 1527 mPdus = pdus; 1528 mDestPort = destPort; 1529 mSmsFormat = smsFormat; 1530 mSmsBroadcastReceiver = smsBroadcastReceiver; 1531 mUserUnlocked = userUnlocked; 1532 mIsClass0 = isClass0; 1533 } 1534 1535 @Override onFilterComplete(int result)1536 public void onFilterComplete(int result) { 1537 logv("onFilterComplete: result is " + result); 1538 if ((result & CarrierMessagingService.RECEIVE_OPTIONS_DROP) == 0) { 1539 if (VisualVoicemailSmsFilter.filter(mContext, mPdus, 1540 mSmsFormat, mDestPort, mPhone.getSubId())) { 1541 log("Visual voicemail SMS dropped"); 1542 dropSms(mSmsBroadcastReceiver); 1543 return; 1544 } 1545 1546 if (mUserUnlocked) { 1547 dispatchSmsDeliveryIntent( 1548 mPdus, mSmsFormat, mDestPort, mSmsBroadcastReceiver, mIsClass0); 1549 } else { 1550 // Don't do anything further, leave the message in the raw table if the 1551 // credential-encrypted storage is still locked and show the new message 1552 // notification if the message is visible to the user. 1553 if (!isSkipNotifyFlagSet(result)) { 1554 showNewMessageNotification(); 1555 } 1556 sendMessage(EVENT_BROADCAST_COMPLETE); 1557 } 1558 } else { 1559 // Drop this SMS. 1560 dropSms(mSmsBroadcastReceiver); 1561 } 1562 } 1563 } 1564 dropSms(SmsBroadcastReceiver receiver)1565 private void dropSms(SmsBroadcastReceiver receiver) { 1566 // Needs phone package permissions. 1567 deleteFromRawTable(receiver.mDeleteWhere, receiver.mDeleteWhereArgs, MARK_DELETED); 1568 sendMessage(EVENT_BROADCAST_COMPLETE); 1569 } 1570 1571 /** Checks whether the flag to skip new message notification is set in the bitmask returned 1572 * from the carrier app. 1573 */ 1574 @UnsupportedAppUsage isSkipNotifyFlagSet(int callbackResult)1575 private boolean isSkipNotifyFlagSet(int callbackResult) { 1576 return (callbackResult 1577 & RECEIVE_OPTIONS_SKIP_NOTIFY_WHEN_CREDENTIAL_PROTECTED_STORAGE_UNAVAILABLE) > 0; 1578 } 1579 1580 /** 1581 * Log with debug level. 1582 * @param s the string to log 1583 */ 1584 @UnsupportedAppUsage 1585 @Override log(String s)1586 protected void log(String s) { 1587 Rlog.d(getName(), s); 1588 } 1589 1590 /** 1591 * Log with error level. 1592 * @param s the string to log 1593 */ 1594 @UnsupportedAppUsage 1595 @Override loge(String s)1596 protected void loge(String s) { 1597 Rlog.e(getName(), s); 1598 } 1599 1600 /** 1601 * Log with error level. 1602 * @param s the string to log 1603 * @param e is a Throwable which logs additional information. 1604 */ 1605 @Override loge(String s, Throwable e)1606 protected void loge(String s, Throwable e) { 1607 Rlog.e(getName(), s, e); 1608 } 1609 1610 /** 1611 * Store a received SMS into Telephony provider 1612 * 1613 * @param intent The intent containing the received SMS 1614 * @return The URI of written message 1615 */ 1616 @UnsupportedAppUsage writeInboxMessage(Intent intent)1617 private Uri writeInboxMessage(Intent intent) { 1618 final SmsMessage[] messages = Telephony.Sms.Intents.getMessagesFromIntent(intent); 1619 if (messages == null || messages.length < 1) { 1620 loge("Failed to parse SMS pdu"); 1621 return null; 1622 } 1623 // Sometimes, SmsMessage is null if it can’t be parsed correctly. 1624 for (final SmsMessage sms : messages) { 1625 if (sms == null) { 1626 loge("Can’t write null SmsMessage"); 1627 return null; 1628 } 1629 } 1630 final ContentValues values = parseSmsMessage(messages); 1631 final long identity = Binder.clearCallingIdentity(); 1632 try { 1633 return mContext.getContentResolver().insert(Telephony.Sms.Inbox.CONTENT_URI, values); 1634 } catch (Exception e) { 1635 loge("Failed to persist inbox message", e); 1636 } finally { 1637 Binder.restoreCallingIdentity(identity); 1638 } 1639 return null; 1640 } 1641 1642 /** 1643 * Convert SmsMessage[] into SMS database schema columns 1644 * 1645 * @param msgs The SmsMessage array of the received SMS 1646 * @return ContentValues representing the columns of parsed SMS 1647 */ parseSmsMessage(SmsMessage[] msgs)1648 private static ContentValues parseSmsMessage(SmsMessage[] msgs) { 1649 final SmsMessage sms = msgs[0]; 1650 final ContentValues values = new ContentValues(); 1651 values.put(Telephony.Sms.Inbox.ADDRESS, sms.getDisplayOriginatingAddress()); 1652 values.put(Telephony.Sms.Inbox.BODY, buildMessageBodyFromPdus(msgs)); 1653 values.put(Telephony.Sms.Inbox.DATE_SENT, sms.getTimestampMillis()); 1654 values.put(Telephony.Sms.Inbox.DATE, System.currentTimeMillis()); 1655 values.put(Telephony.Sms.Inbox.PROTOCOL, sms.getProtocolIdentifier()); 1656 values.put(Telephony.Sms.Inbox.SEEN, 0); 1657 values.put(Telephony.Sms.Inbox.READ, 0); 1658 final String subject = sms.getPseudoSubject(); 1659 if (!TextUtils.isEmpty(subject)) { 1660 values.put(Telephony.Sms.Inbox.SUBJECT, subject); 1661 } 1662 values.put(Telephony.Sms.Inbox.REPLY_PATH_PRESENT, sms.isReplyPathPresent() ? 1 : 0); 1663 values.put(Telephony.Sms.Inbox.SERVICE_CENTER, sms.getServiceCenterAddress()); 1664 return values; 1665 } 1666 1667 /** 1668 * Build up the SMS message body from the SmsMessage array of received SMS 1669 * 1670 * @param msgs The SmsMessage array of the received SMS 1671 * @return The text message body 1672 */ buildMessageBodyFromPdus(SmsMessage[] msgs)1673 private static String buildMessageBodyFromPdus(SmsMessage[] msgs) { 1674 if (msgs.length == 1) { 1675 // There is only one part, so grab the body directly. 1676 return replaceFormFeeds(msgs[0].getDisplayMessageBody()); 1677 } else { 1678 // Build up the body from the parts. 1679 StringBuilder body = new StringBuilder(); 1680 for (SmsMessage msg: msgs) { 1681 // getDisplayMessageBody() can NPE if mWrappedMessage inside is null. 1682 body.append(msg.getDisplayMessageBody()); 1683 } 1684 return replaceFormFeeds(body.toString()); 1685 } 1686 } 1687 1688 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)1689 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1690 super.dump(fd, pw, args); 1691 if (mCellBroadcastHandler != null) { 1692 mCellBroadcastHandler.dump(fd, pw, args); 1693 } 1694 mLocalLog.dump(fd, pw, args); 1695 } 1696 1697 // Some providers send formfeeds in their messages. Convert those formfeeds to newlines. replaceFormFeeds(String s)1698 private static String replaceFormFeeds(String s) { 1699 return s == null ? "" : s.replace('\f', '\n'); 1700 } 1701 1702 @VisibleForTesting getWakeLock()1703 public PowerManager.WakeLock getWakeLock() { 1704 return mWakeLock; 1705 } 1706 1707 @VisibleForTesting getWakeLockTimeout()1708 public int getWakeLockTimeout() { 1709 return mWakeLockTimeout; 1710 } 1711 1712 /** 1713 * Sets the wakelock timeout to {@link timeOut} milliseconds 1714 */ setWakeLockTimeout(int timeOut)1715 private void setWakeLockTimeout(int timeOut) { 1716 mWakeLockTimeout = timeOut; 1717 } 1718 1719 /** 1720 * Handler for the broadcast sent when the new message notification is clicked. It launches the 1721 * default SMS app. 1722 */ 1723 private static class NewMessageNotificationActionReceiver extends BroadcastReceiver { 1724 @Override onReceive(Context context, Intent intent)1725 public void onReceive(Context context, Intent intent) { 1726 if (ACTION_OPEN_SMS_APP.equals(intent.getAction())) { 1727 // do nothing if the user had not unlocked the device yet 1728 UserManager userManager = 1729 (UserManager) context.getSystemService(Context.USER_SERVICE); 1730 if (userManager.isUserUnlocked()) { 1731 context.startActivity(context.getPackageManager().getLaunchIntentForPackage( 1732 Telephony.Sms.getDefaultSmsPackage(context))); 1733 } 1734 } 1735 } 1736 } 1737 1738 /** 1739 * Registers the broadcast receiver to launch the default SMS app when the user clicks the 1740 * new message notification. 1741 */ registerNewMessageNotificationActionHandler(Context context)1742 static void registerNewMessageNotificationActionHandler(Context context) { 1743 IntentFilter userFilter = new IntentFilter(); 1744 userFilter.addAction(ACTION_OPEN_SMS_APP); 1745 context.registerReceiver(new NewMessageNotificationActionReceiver(), userFilter); 1746 } 1747 } 1748