InboundSmsHandler.java revision ba798021d26fc3690a16a2c9b4f41f44a1122b49
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 17package com.android.internal.telephony; 18 19import static android.telephony.TelephonyManager.PHONE_TYPE_CDMA; 20 21import android.app.Activity; 22import android.app.ActivityManagerNative; 23import android.app.AppOpsManager; 24import android.app.BroadcastOptions; 25import android.app.PendingIntent; 26import android.app.PendingIntent.CanceledException; 27import android.content.BroadcastReceiver; 28import android.content.ComponentName; 29import android.content.ContentResolver; 30import android.content.ContentUris; 31import android.content.ContentValues; 32import android.content.Context; 33import android.content.Intent; 34import android.content.SharedPreferences; 35import android.content.pm.UserInfo; 36import android.content.pm.PackageManager; 37import android.content.pm.ResolveInfo; 38import android.database.Cursor; 39import android.database.SQLException; 40import android.net.Uri; 41import android.os.AsyncResult; 42import android.os.Binder; 43import android.os.Build; 44import android.os.Bundle; 45import android.os.IDeviceIdleController; 46import android.os.Message; 47import android.os.PowerManager; 48import android.os.RemoteException; 49import android.os.ServiceManager; 50import android.os.UserHandle; 51import android.os.UserManager; 52import android.preference.PreferenceManager; 53import android.provider.Telephony; 54import android.provider.Telephony.Sms.Intents; 55import android.service.carrier.CarrierMessagingService; 56import android.service.carrier.ICarrierMessagingCallback; 57import android.service.carrier.ICarrierMessagingService; 58import android.service.carrier.MessagePdu; 59import android.telephony.CarrierMessagingServiceManager; 60import android.telephony.Rlog; 61import android.telephony.SmsManager; 62import android.telephony.SmsMessage; 63import android.telephony.SubscriptionManager; 64import android.telephony.TelephonyManager; 65import android.text.TextUtils; 66 67import com.android.internal.telephony.uicc.UiccCard; 68import com.android.internal.telephony.uicc.UiccController; 69import com.android.internal.util.HexDump; 70import com.android.internal.util.State; 71import com.android.internal.util.StateMachine; 72 73import java.io.ByteArrayOutputStream; 74import java.util.Arrays; 75import java.util.ArrayList; 76import java.util.List; 77 78/** 79 * This class broadcasts incoming SMS messages to interested apps after storing them in 80 * the SmsProvider "raw" table and ACKing them to the SMSC. After each message has been 81 * broadcast, its parts are removed from the raw table. If the device crashes after ACKing 82 * but before the broadcast completes, the pending messages will be rebroadcast on the next boot. 83 * 84 * <p>The state machine starts in {@link IdleState} state. When the {@link SMSDispatcher} receives a 85 * new SMS from the radio, it calls {@link #dispatchNormalMessage}, 86 * which sends a message to the state machine, causing the wakelock to be acquired in 87 * {@link #haltedProcessMessage}, which transitions to {@link DeliveringState} state, where the message 88 * is saved to the raw table, then acknowledged via the {@link SMSDispatcher} which called us. 89 * 90 * <p>After saving the SMS, if the message is complete (either single-part or the final segment 91 * of a multi-part SMS), we broadcast the completed PDUs as an ordered broadcast, then transition to 92 * {@link WaitingState} state to wait for the broadcast to complete. When the local 93 * {@link BroadcastReceiver} is called with the result, it sends {@link #EVENT_BROADCAST_COMPLETE} 94 * to the state machine, causing us to either broadcast the next pending message (if one has 95 * arrived while waiting for the broadcast to complete), or to transition back to the halted state 96 * after all messages are processed. Then the wakelock is released and we wait for the next SMS. 97 */ 98public abstract class InboundSmsHandler extends StateMachine { 99 protected static final boolean DBG = true; 100 private static final boolean VDBG = false; // STOPSHIP if true, logs user data 101 102 /** Query projection for checking for duplicate message segments. */ 103 private static final String[] PDU_PROJECTION = { 104 "pdu" 105 }; 106 107 /** Query projection for combining concatenated message segments. */ 108 private static final String[] PDU_SEQUENCE_PORT_PROJECTION = { 109 "pdu", 110 "sequence", 111 "destination_port" 112 }; 113 114 static final int PDU_COLUMN = 0; 115 static final int SEQUENCE_COLUMN = 1; 116 static final int DESTINATION_PORT_COLUMN = 2; 117 static final int DATE_COLUMN = 3; 118 static final int REFERENCE_NUMBER_COLUMN = 4; 119 static final int COUNT_COLUMN = 5; 120 static final int ADDRESS_COLUMN = 6; 121 static final int ID_COLUMN = 7; 122 123 static final String SELECT_BY_ID = "_id=?"; 124 static final String SELECT_BY_REFERENCE = "address=? AND reference_number=? AND count=?"; 125 126 /** New SMS received as an AsyncResult. */ 127 public static final int EVENT_NEW_SMS = 1; 128 129 /** Message type containing a {@link InboundSmsTracker} ready to broadcast to listeners. */ 130 static final int EVENT_BROADCAST_SMS = 2; 131 132 /** Message from resultReceiver notifying {@link WaitingState} of a completed broadcast. */ 133 static final int EVENT_BROADCAST_COMPLETE = 3; 134 135 /** Sent on exit from {@link WaitingState} to return to idle after sending all broadcasts. */ 136 static final int EVENT_RETURN_TO_IDLE = 4; 137 138 /** Release wakelock after a short timeout when returning to idle state. */ 139 static final int EVENT_RELEASE_WAKELOCK = 5; 140 141 /** Sent by {@link SmsBroadcastUndelivered} after cleaning the raw table. */ 142 static final int EVENT_START_ACCEPTING_SMS = 6; 143 144 /** Update phone object */ 145 static final int EVENT_UPDATE_PHONE_OBJECT = 7; 146 147 /** New SMS received as an AsyncResult. */ 148 public static final int EVENT_INJECT_SMS = 8; 149 150 /** Wakelock release delay when returning to idle state. */ 151 private static final int WAKELOCK_TIMEOUT = 3000; 152 153 /** URI for raw table of SMS provider. */ 154 private static final Uri sRawUri = Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, "raw"); 155 156 protected final Context mContext; 157 private final ContentResolver mResolver; 158 159 /** Special handler for WAP push messages. */ 160 private final WapPushOverSms mWapPush; 161 162 /** Wake lock to ensure device stays awake while dispatching the SMS intents. */ 163 final PowerManager.WakeLock mWakeLock; 164 165 /** DefaultState throws an exception or logs an error for unhandled message types. */ 166 final DefaultState mDefaultState = new DefaultState(); 167 168 /** Startup state. Waiting for {@link SmsBroadcastUndelivered} to complete. */ 169 final StartupState mStartupState = new StartupState(); 170 171 /** Idle state. Waiting for messages to process. */ 172 final IdleState mIdleState = new IdleState(); 173 174 /** Delivering state. Saves the PDU in the raw table and acknowledges to SMSC. */ 175 final DeliveringState mDeliveringState = new DeliveringState(); 176 177 /** Broadcasting state. Waits for current broadcast to complete before delivering next. */ 178 final WaitingState mWaitingState = new WaitingState(); 179 180 /** Helper class to check whether storage is available for incoming messages. */ 181 protected SmsStorageMonitor mStorageMonitor; 182 183 private final boolean mSmsReceiveDisabled; 184 185 protected PhoneBase mPhone; 186 187 protected CellBroadcastHandler mCellBroadcastHandler; 188 189 private UserManager mUserManager; 190 191 IDeviceIdleController mDeviceIdleController; 192 193 /** 194 * Create a new SMS broadcast helper. 195 * @param name the class name for logging 196 * @param context the context of the phone app 197 * @param storageMonitor the SmsStorageMonitor to check for storage availability 198 */ 199 protected InboundSmsHandler(String name, Context context, SmsStorageMonitor storageMonitor, 200 PhoneBase phone, CellBroadcastHandler cellBroadcastHandler) { 201 super(name); 202 203 mContext = context; 204 mStorageMonitor = storageMonitor; 205 mPhone = phone; 206 mCellBroadcastHandler = cellBroadcastHandler; 207 mResolver = context.getContentResolver(); 208 mWapPush = new WapPushOverSms(context); 209 210 boolean smsCapable = mContext.getResources().getBoolean( 211 com.android.internal.R.bool.config_sms_capable); 212 mSmsReceiveDisabled = !TelephonyManager.from(mContext).getSmsReceiveCapableForPhone( 213 mPhone.getPhoneId(), smsCapable); 214 215 PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 216 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, name); 217 mWakeLock.acquire(); // wake lock released after we enter idle state 218 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 219 mDeviceIdleController = IDeviceIdleController.Stub.asInterface( 220 ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER)); 221 222 addState(mDefaultState); 223 addState(mStartupState, mDefaultState); 224 addState(mIdleState, mDefaultState); 225 addState(mDeliveringState, mDefaultState); 226 addState(mWaitingState, mDeliveringState); 227 228 setInitialState(mStartupState); 229 if (DBG) log("created InboundSmsHandler"); 230 } 231 232 /** 233 * Tell the state machine to quit after processing all messages. 234 */ 235 public void dispose() { 236 quit(); 237 } 238 239 /** 240 * Update the phone object when it changes. 241 */ 242 public void updatePhoneObject(PhoneBase phone) { 243 sendMessage(EVENT_UPDATE_PHONE_OBJECT, phone); 244 } 245 246 /** 247 * Dispose of the WAP push object and release the wakelock. 248 */ 249 @Override 250 protected void onQuitting() { 251 mWapPush.dispose(); 252 253 while (mWakeLock.isHeld()) { 254 mWakeLock.release(); 255 } 256 } 257 258 // CAF_MSIM Is this used anywhere ? if not remove it 259 public PhoneBase getPhone() { 260 return mPhone; 261 } 262 263 /** 264 * This parent state throws an exception (for debug builds) or prints an error for unhandled 265 * message types. 266 */ 267 class DefaultState extends State { 268 @Override 269 public boolean processMessage(Message msg) { 270 switch (msg.what) { 271 case EVENT_UPDATE_PHONE_OBJECT: { 272 onUpdatePhoneObject((PhoneBase) msg.obj); 273 break; 274 } 275 default: { 276 String errorText = "processMessage: unhandled message type " + msg.what + 277 " currState=" + getCurrentState().getName(); 278 if (Build.IS_DEBUGGABLE) { 279 loge("---- Dumping InboundSmsHandler ----"); 280 loge("Total records=" + getLogRecCount()); 281 for (int i = Math.max(getLogRecSize() - 20, 0); i < getLogRecSize(); i++) { 282 loge("Rec[%d]: %s\n" + i + getLogRec(i).toString()); 283 } 284 loge("---- Dumped InboundSmsHandler ----"); 285 286 throw new RuntimeException(errorText); 287 } else { 288 loge(errorText); 289 } 290 break; 291 } 292 } 293 return HANDLED; 294 } 295 } 296 297 /** 298 * The Startup state waits for {@link SmsBroadcastUndelivered} to process the raw table and 299 * notify the state machine to broadcast any complete PDUs that might not have been broadcast. 300 */ 301 class StartupState extends State { 302 @Override 303 public boolean processMessage(Message msg) { 304 log("StartupState.processMessage:" + msg.what); 305 switch (msg.what) { 306 case EVENT_NEW_SMS: 307 case EVENT_INJECT_SMS: 308 case EVENT_BROADCAST_SMS: 309 deferMessage(msg); 310 return HANDLED; 311 312 case EVENT_START_ACCEPTING_SMS: 313 transitionTo(mIdleState); 314 return HANDLED; 315 316 case EVENT_BROADCAST_COMPLETE: 317 case EVENT_RETURN_TO_IDLE: 318 case EVENT_RELEASE_WAKELOCK: 319 default: 320 // let DefaultState handle these unexpected message types 321 return NOT_HANDLED; 322 } 323 } 324 } 325 326 /** 327 * In the idle state the wakelock is released until a new SM arrives, then we transition 328 * to Delivering mode to handle it, acquiring the wakelock on exit. 329 */ 330 class IdleState extends State { 331 @Override 332 public void enter() { 333 if (DBG) log("entering Idle state"); 334 sendMessageDelayed(EVENT_RELEASE_WAKELOCK, WAKELOCK_TIMEOUT); 335 } 336 337 @Override 338 public void exit() { 339 mWakeLock.acquire(); 340 if (DBG) log("acquired wakelock, leaving Idle state"); 341 } 342 343 @Override 344 public boolean processMessage(Message msg) { 345 log("IdleState.processMessage:" + msg.what); 346 if (DBG) log("Idle state processing message type " + msg.what); 347 switch (msg.what) { 348 case EVENT_NEW_SMS: 349 case EVENT_INJECT_SMS: 350 case EVENT_BROADCAST_SMS: 351 deferMessage(msg); 352 transitionTo(mDeliveringState); 353 return HANDLED; 354 355 case EVENT_RELEASE_WAKELOCK: 356 mWakeLock.release(); 357 if (DBG) { 358 if (mWakeLock.isHeld()) { 359 // this is okay as long as we call release() for every acquire() 360 log("mWakeLock is still held after release"); 361 } else { 362 log("mWakeLock released"); 363 } 364 } 365 return HANDLED; 366 367 case EVENT_RETURN_TO_IDLE: 368 // already in idle state; ignore 369 return HANDLED; 370 371 case EVENT_BROADCAST_COMPLETE: 372 case EVENT_START_ACCEPTING_SMS: 373 default: 374 // let DefaultState handle these unexpected message types 375 return NOT_HANDLED; 376 } 377 } 378 } 379 380 /** 381 * In the delivering state, the inbound SMS is processed and stored in the raw table. 382 * The message is acknowledged before we exit this state. If there is a message to broadcast, 383 * transition to {@link WaitingState} state to send the ordered broadcast and wait for the 384 * results. When all messages have been processed, the halting state will release the wakelock. 385 */ 386 class DeliveringState extends State { 387 @Override 388 public void enter() { 389 if (DBG) log("entering Delivering state"); 390 } 391 392 @Override 393 public void exit() { 394 if (DBG) log("leaving Delivering state"); 395 } 396 397 @Override 398 public boolean processMessage(Message msg) { 399 log("DeliveringState.processMessage:" + msg.what); 400 switch (msg.what) { 401 case EVENT_NEW_SMS: 402 // handle new SMS from RIL 403 handleNewSms((AsyncResult) msg.obj); 404 sendMessage(EVENT_RETURN_TO_IDLE); 405 return HANDLED; 406 407 case EVENT_INJECT_SMS: 408 // handle new injected SMS 409 handleInjectSms((AsyncResult) msg.obj); 410 sendMessage(EVENT_RETURN_TO_IDLE); 411 return HANDLED; 412 413 case EVENT_BROADCAST_SMS: 414 // if any broadcasts were sent, transition to waiting state 415 InboundSmsTracker inboundSmsTracker = (InboundSmsTracker) msg.obj; 416 if (processMessagePart(inboundSmsTracker)) { 417 transitionTo(mWaitingState); 418 } else { 419 // if event is sent from SmsBroadcastUndelivered.broadcastSms(), and 420 // processMessagePart() returns false, the state machine will be stuck in 421 // DeliveringState until next message is received. Send message to 422 // transition to idle to avoid that so that wakelock can be released 423 log("No broadcast sent on processing EVENT_BROADCAST_SMS in Delivering " + 424 "state. Return to Idle state"); 425 sendMessage(EVENT_RETURN_TO_IDLE); 426 } 427 return HANDLED; 428 429 case EVENT_RETURN_TO_IDLE: 430 // return to idle after processing all other messages 431 transitionTo(mIdleState); 432 return HANDLED; 433 434 case EVENT_RELEASE_WAKELOCK: 435 mWakeLock.release(); // decrement wakelock from previous entry to Idle 436 if (!mWakeLock.isHeld()) { 437 // wakelock should still be held until 3 seconds after we enter Idle 438 loge("mWakeLock released while delivering/broadcasting!"); 439 } 440 return HANDLED; 441 442 // we shouldn't get this message type in this state, log error and halt. 443 case EVENT_BROADCAST_COMPLETE: 444 case EVENT_START_ACCEPTING_SMS: 445 default: 446 // let DefaultState handle these unexpected message types 447 return NOT_HANDLED; 448 } 449 } 450 } 451 452 /** 453 * The waiting state delegates handling of new SMS to parent {@link DeliveringState}, but 454 * defers handling of the {@link #EVENT_BROADCAST_SMS} phase until after the current 455 * result receiver sends {@link #EVENT_BROADCAST_COMPLETE}. Before transitioning to 456 * {@link DeliveringState}, {@link #EVENT_RETURN_TO_IDLE} is sent to transition to 457 * {@link IdleState} after any deferred {@link #EVENT_BROADCAST_SMS} messages are handled. 458 */ 459 class WaitingState extends State { 460 @Override 461 public boolean processMessage(Message msg) { 462 log("WaitingState.processMessage:" + msg.what); 463 switch (msg.what) { 464 case EVENT_BROADCAST_SMS: 465 // defer until the current broadcast completes 466 deferMessage(msg); 467 return HANDLED; 468 469 case EVENT_BROADCAST_COMPLETE: 470 // return to idle after handling all deferred messages 471 sendMessage(EVENT_RETURN_TO_IDLE); 472 transitionTo(mDeliveringState); 473 return HANDLED; 474 475 case EVENT_RETURN_TO_IDLE: 476 // not ready to return to idle; ignore 477 return HANDLED; 478 479 default: 480 // parent state handles the other message types 481 return NOT_HANDLED; 482 } 483 } 484 } 485 486 void handleNewSms(AsyncResult ar) { 487 if (ar.exception != null) { 488 loge("Exception processing incoming SMS: " + ar.exception); 489 return; 490 } 491 492 int result; 493 try { 494 SmsMessage sms = (SmsMessage) ar.result; 495 result = dispatchMessage(sms.mWrappedSmsMessage); 496 } catch (RuntimeException ex) { 497 loge("Exception dispatching message", ex); 498 result = Intents.RESULT_SMS_GENERIC_ERROR; 499 } 500 501 // RESULT_OK means that the SMS will be acknowledged by special handling, 502 // e.g. for SMS-PP data download. Any other result, we should ack here. 503 if (result != Activity.RESULT_OK) { 504 boolean handled = (result == Intents.RESULT_SMS_HANDLED); 505 notifyAndAcknowledgeLastIncomingSms(handled, result, null); 506 } 507 } 508 509 /** 510 * This method is called when a new SMS PDU is injected into application framework. 511 * @param ar is the AsyncResult that has the SMS PDU to be injected. 512 */ 513 void handleInjectSms(AsyncResult ar) { 514 int result; 515 PendingIntent receivedIntent = null; 516 try { 517 receivedIntent = (PendingIntent) ar.userObj; 518 SmsMessage sms = (SmsMessage) ar.result; 519 if (sms == null) { 520 result = Intents.RESULT_SMS_GENERIC_ERROR; 521 } else { 522 result = dispatchMessage(sms.mWrappedSmsMessage); 523 } 524 } catch (RuntimeException ex) { 525 loge("Exception dispatching message", ex); 526 result = Intents.RESULT_SMS_GENERIC_ERROR; 527 } 528 529 if (receivedIntent != null) { 530 try { 531 receivedIntent.send(result); 532 } catch (CanceledException e) { } 533 } 534 } 535 536 /** 537 * Process an SMS message from the RIL, calling subclass methods to handle 3GPP and 538 * 3GPP2-specific message types. 539 * 540 * @param smsb the SmsMessageBase object from the RIL 541 * @return a result code from {@link android.provider.Telephony.Sms.Intents}, 542 * or {@link Activity#RESULT_OK} for delayed acknowledgment to SMSC 543 */ 544 public int dispatchMessage(SmsMessageBase smsb) { 545 // If sms is null, there was a parsing error. 546 if (smsb == null) { 547 loge("dispatchSmsMessage: message is null"); 548 return Intents.RESULT_SMS_GENERIC_ERROR; 549 } 550 551 if (mSmsReceiveDisabled) { 552 // Device doesn't support receiving SMS, 553 log("Received short message on device which doesn't support " 554 + "receiving SMS. Ignored."); 555 return Intents.RESULT_SMS_HANDLED; 556 } 557 558 return dispatchMessageRadioSpecific(smsb); 559 } 560 561 /** 562 * Process voicemail notification, SMS-PP data download, CDMA CMAS, CDMA WAP push, and other 563 * 3GPP/3GPP2-specific messages. Regular SMS messages are handled by calling the shared 564 * {@link #dispatchNormalMessage} from this class. 565 * 566 * @param smsb the SmsMessageBase object from the RIL 567 * @return a result code from {@link android.provider.Telephony.Sms.Intents}, 568 * or {@link Activity#RESULT_OK} for delayed acknowledgment to SMSC 569 */ 570 protected abstract int dispatchMessageRadioSpecific(SmsMessageBase smsb); 571 572 /** 573 * Send an acknowledge message to the SMSC. 574 * @param success indicates that last message was successfully received. 575 * @param result result code indicating any error 576 * @param response callback message sent when operation completes. 577 */ 578 protected abstract void acknowledgeLastIncomingSms(boolean success, 579 int result, Message response); 580 581 /** 582 * Called when the phone changes the default method updates mPhone 583 * mStorageMonitor and mCellBroadcastHandler.updatePhoneObject. 584 * Override if different or other behavior is desired. 585 * 586 * @param phone 587 */ 588 protected void onUpdatePhoneObject(PhoneBase phone) { 589 mPhone = phone; 590 mStorageMonitor = mPhone.mSmsStorageMonitor; 591 log("onUpdatePhoneObject: phone=" + mPhone.getClass().getSimpleName()); 592 } 593 594 /** 595 * Notify interested apps if the framework has rejected an incoming SMS, 596 * and send an acknowledge message to the network. 597 * @param success indicates that last message was successfully received. 598 * @param result result code indicating any error 599 * @param response callback message sent when operation completes. 600 */ 601 void notifyAndAcknowledgeLastIncomingSms(boolean success, 602 int result, Message response) { 603 if (!success) { 604 // broadcast SMS_REJECTED_ACTION intent 605 Intent intent = new Intent(Intents.SMS_REJECTED_ACTION); 606 intent.putExtra("result", result); 607 mContext.sendBroadcast(intent, android.Manifest.permission.RECEIVE_SMS); 608 } 609 acknowledgeLastIncomingSms(success, result, response); 610 } 611 612 /** 613 * Return true if this handler is for 3GPP2 messages; false for 3GPP format. 614 * @return true for the 3GPP2 handler; false for the 3GPP handler 615 */ 616 protected abstract boolean is3gpp2(); 617 618 /** 619 * Dispatch a normal incoming SMS. This is called from {@link #dispatchMessageRadioSpecific} 620 * if no format-specific handling was required. Saves the PDU to the SMS provider raw table, 621 * creates an {@link InboundSmsTracker}, then sends it to the state machine as an 622 * {@link #EVENT_BROADCAST_SMS}. Returns {@link Intents#RESULT_SMS_HANDLED} or an error value. 623 * 624 * @param sms the message to dispatch 625 * @return {@link Intents#RESULT_SMS_HANDLED} if the message was accepted, or an error status 626 */ 627 protected int dispatchNormalMessage(SmsMessageBase sms) { 628 SmsHeader smsHeader = sms.getUserDataHeader(); 629 InboundSmsTracker tracker; 630 631 if ((smsHeader == null) || (smsHeader.concatRef == null)) { 632 // Message is not concatenated. 633 int destPort = -1; 634 if (smsHeader != null && smsHeader.portAddrs != null) { 635 // The message was sent to a port. 636 destPort = smsHeader.portAddrs.destPort; 637 if (DBG) log("destination port: " + destPort); 638 } 639 640 tracker = new InboundSmsTracker(sms.getPdu(), sms.getTimestampMillis(), destPort, 641 is3gpp2(), false); 642 } else { 643 // Create a tracker for this message segment. 644 SmsHeader.ConcatRef concatRef = smsHeader.concatRef; 645 SmsHeader.PortAddrs portAddrs = smsHeader.portAddrs; 646 int destPort = (portAddrs != null ? portAddrs.destPort : -1); 647 648 tracker = new InboundSmsTracker(sms.getPdu(), sms.getTimestampMillis(), destPort, 649 is3gpp2(), sms.getOriginatingAddress(), concatRef.refNumber, 650 concatRef.seqNumber, concatRef.msgCount, false); 651 } 652 653 if (VDBG) log("created tracker: " + tracker); 654 return addTrackerToRawTableAndSendMessage(tracker); 655 } 656 657 /** 658 * Helper to add the tracker to the raw table and then send a message to broadcast it, if 659 * successful. Returns the SMS intent status to return to the SMSC. 660 * @param tracker the tracker to save to the raw table and then deliver 661 * @return {@link Intents#RESULT_SMS_HANDLED} or {@link Intents#RESULT_SMS_GENERIC_ERROR} 662 * or {@link Intents#RESULT_SMS_DUPLICATED} 663 */ 664 protected int addTrackerToRawTableAndSendMessage(InboundSmsTracker tracker) { 665 switch(addTrackerToRawTable(tracker)) { 666 case Intents.RESULT_SMS_HANDLED: 667 sendMessage(EVENT_BROADCAST_SMS, tracker); 668 return Intents.RESULT_SMS_HANDLED; 669 670 case Intents.RESULT_SMS_DUPLICATED: 671 return Intents.RESULT_SMS_HANDLED; 672 673 case Intents.RESULT_SMS_GENERIC_ERROR: 674 default: 675 return Intents.RESULT_SMS_GENERIC_ERROR; 676 } 677 } 678 679 /** 680 * Process the inbound SMS segment. If the message is complete, send it as an ordered 681 * broadcast to interested receivers and return true. If the message is a segment of an 682 * incomplete multi-part SMS, return false. 683 * @param tracker the tracker containing the message segment to process 684 * @return true if an ordered broadcast was sent; false if waiting for more message segments 685 */ 686 boolean processMessagePart(InboundSmsTracker tracker) { 687 int messageCount = tracker.getMessageCount(); 688 byte[][] pdus; 689 int destPort = tracker.getDestPort(); 690 691 if (messageCount == 1) { 692 // single-part message 693 pdus = new byte[][]{tracker.getPdu()}; 694 } else { 695 // multi-part message 696 Cursor cursor = null; 697 try { 698 // used by several query selection arguments 699 String address = tracker.getAddress(); 700 String refNumber = Integer.toString(tracker.getReferenceNumber()); 701 String count = Integer.toString(tracker.getMessageCount()); 702 703 // query for all segments and broadcast message if we have all the parts 704 String[] whereArgs = {address, refNumber, count}; 705 cursor = mResolver.query(sRawUri, PDU_SEQUENCE_PORT_PROJECTION, 706 SELECT_BY_REFERENCE, whereArgs, null); 707 708 int cursorCount = cursor.getCount(); 709 if (cursorCount < messageCount) { 710 // Wait for the other message parts to arrive. It's also possible for the last 711 // segment to arrive before processing the EVENT_BROADCAST_SMS for one of the 712 // earlier segments. In that case, the broadcast will be sent as soon as all 713 // segments are in the table, and any later EVENT_BROADCAST_SMS messages will 714 // get a row count of 0 and return. 715 return false; 716 } 717 718 // All the parts are in place, deal with them 719 pdus = new byte[messageCount][]; 720 while (cursor.moveToNext()) { 721 // subtract offset to convert sequence to 0-based array index 722 int index = cursor.getInt(SEQUENCE_COLUMN) - tracker.getIndexOffset(); 723 724 pdus[index] = HexDump.hexStringToByteArray(cursor.getString(PDU_COLUMN)); 725 726 // Read the destination port from the first segment (needed for CDMA WAP PDU). 727 // It's not a bad idea to prefer the port from the first segment in other cases. 728 if (index == 0 && !cursor.isNull(DESTINATION_PORT_COLUMN)) { 729 int port = cursor.getInt(DESTINATION_PORT_COLUMN); 730 // strip format flags and convert to real port number, or -1 731 port = InboundSmsTracker.getRealDestPort(port); 732 if (port != -1) { 733 destPort = port; 734 } 735 } 736 } 737 } catch (SQLException e) { 738 loge("Can't access multipart SMS database", e); 739 return false; 740 } finally { 741 if (cursor != null) { 742 cursor.close(); 743 } 744 } 745 } 746 747 SmsBroadcastReceiver resultReceiver = new SmsBroadcastReceiver(tracker); 748 749 if (destPort == SmsHeader.PORT_WAP_PUSH) { 750 // Build up the data stream 751 ByteArrayOutputStream output = new ByteArrayOutputStream(); 752 for (byte[] pdu : pdus) { 753 // 3GPP needs to extract the User Data from the PDU; 3GPP2 has already done this 754 if (!tracker.is3gpp2()) { 755 SmsMessage msg = SmsMessage.createFromPdu(pdu, SmsConstants.FORMAT_3GPP); 756 pdu = msg.getUserData(); 757 } 758 output.write(pdu, 0, pdu.length); 759 } 760 int result = mWapPush.dispatchWapPdu(output.toByteArray(), resultReceiver, this); 761 if (DBG) log("dispatchWapPdu() returned " + result); 762 // result is Activity.RESULT_OK if an ordered broadcast was sent 763 if (result == Activity.RESULT_OK) { 764 return true; 765 } else { 766 deleteFromRawTable(tracker.getDeleteWhere(), tracker.getDeleteWhereArgs()); 767 return false; 768 } 769 } 770 771 List<String> carrierPackages = null; 772 UiccCard card = UiccController.getInstance().getUiccCard(mPhone.getPhoneId()); 773 if (card != null) { 774 carrierPackages = card.getCarrierPackageNamesForIntent( 775 mContext.getPackageManager(), 776 new Intent(CarrierMessagingService.SERVICE_INTERFACE)); 777 } else { 778 loge("UiccCard not initialized."); 779 } 780 781 List<String> systemPackages = 782 getSystemAppForIntent(new Intent(CarrierMessagingService.SERVICE_INTERFACE)); 783 784 if (carrierPackages != null && carrierPackages.size() == 1) { 785 log("Found carrier package."); 786 CarrierSmsFilter smsFilter = new CarrierSmsFilter(pdus, destPort, 787 tracker.getFormat(), resultReceiver); 788 CarrierSmsFilterCallback smsFilterCallback = new CarrierSmsFilterCallback(smsFilter); 789 smsFilter.filterSms(carrierPackages.get(0), smsFilterCallback); 790 } else if (systemPackages != null && systemPackages.size() == 1) { 791 log("Found system package."); 792 CarrierSmsFilter smsFilter = new CarrierSmsFilter(pdus, destPort, 793 tracker.getFormat(), resultReceiver); 794 CarrierSmsFilterCallback smsFilterCallback = new CarrierSmsFilterCallback(smsFilter); 795 smsFilter.filterSms(systemPackages.get(0), smsFilterCallback); 796 } else { 797 logv("Unable to find carrier package: " + carrierPackages 798 + ", nor systemPackages: " + systemPackages); 799 dispatchSmsDeliveryIntent(pdus, tracker.getFormat(), destPort, resultReceiver); 800 } 801 802 return true; 803 } 804 805 private List<String> getSystemAppForIntent(Intent intent) { 806 List<String> packages = new ArrayList<String>(); 807 PackageManager packageManager = mContext.getPackageManager(); 808 List<ResolveInfo> receivers = packageManager.queryIntentServices(intent, 0); 809 String carrierFilterSmsPerm = "android.permission.CARRIER_FILTER_SMS"; 810 811 for (ResolveInfo info : receivers) { 812 if (info.serviceInfo == null) { 813 loge("Can't get service information from " + info); 814 continue; 815 } 816 String packageName = info.serviceInfo.packageName; 817 if (packageManager.checkPermission(carrierFilterSmsPerm, packageName) == 818 packageManager.PERMISSION_GRANTED) { 819 packages.add(packageName); 820 if (DBG) log("getSystemAppForIntent: added package "+ packageName); 821 } 822 } 823 return packages; 824 } 825 826 /** 827 * Dispatch the intent with the specified permission, appOp, and result receiver, using 828 * this state machine's handler thread to run the result receiver. 829 * 830 * @param intent the intent to broadcast 831 * @param permission receivers are required to have this permission 832 * @param appOp app op that is being performed when dispatching to a receiver 833 * @param user user to deliver the intent to 834 */ 835 protected void dispatchIntent(Intent intent, String permission, int appOp, 836 Bundle opts, BroadcastReceiver resultReceiver, UserHandle user) { 837 intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT); 838 SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId()); 839 if (user.equals(UserHandle.ALL)) { 840 // Get a list of currently started users. 841 int[] users = null; 842 try { 843 users = ActivityManagerNative.getDefault().getRunningUserIds(); 844 } catch (RemoteException re) { 845 } 846 if (users == null) { 847 users = new int[] {user.getIdentifier()}; 848 } 849 // Deliver the broadcast only to those running users that are permitted 850 // by user policy. 851 for (int i = users.length - 1; i >= 0; i--) { 852 UserHandle targetUser = new UserHandle(users[i]); 853 if (users[i] != UserHandle.USER_SYSTEM) { 854 // Is the user not allowed to use SMS? 855 if (mUserManager.hasUserRestriction(UserManager.DISALLOW_SMS, targetUser)) { 856 continue; 857 } 858 // Skip unknown users and managed profiles as well 859 UserInfo info = mUserManager.getUserInfo(users[i]); 860 if (info == null || info.isManagedProfile()) { 861 continue; 862 } 863 } 864 // Only pass in the resultReceiver when the USER_SYSTEM is processed. 865 mContext.sendOrderedBroadcastAsUser(intent, targetUser, permission, appOp, opts, 866 users[i] == UserHandle.USER_SYSTEM ? resultReceiver : null, 867 getHandler(), Activity.RESULT_OK, null, null); 868 } 869 } else { 870 mContext.sendOrderedBroadcastAsUser(intent, user, permission, appOp, opts, 871 resultReceiver, getHandler(), Activity.RESULT_OK, null, null); 872 } 873 } 874 875 /** 876 * Helper for {@link SmsBroadcastUndelivered} to delete an old message in the raw table. 877 */ 878 void deleteFromRawTable(String deleteWhere, String[] deleteWhereArgs) { 879 int rows = mResolver.delete(sRawUri, deleteWhere, deleteWhereArgs); 880 if (rows == 0) { 881 loge("No rows were deleted from raw table!"); 882 } else if (DBG) { 883 log("Deleted " + rows + " rows from raw table."); 884 } 885 } 886 887 Bundle handleSmsWhitelisting(ComponentName target) { 888 String pkgName; 889 String reason; 890 if (target != null) { 891 pkgName = target.getPackageName(); 892 reason = "sms-app"; 893 } else { 894 pkgName = mContext.getPackageName(); 895 reason = "sms-broadcast"; 896 } 897 try { 898 long duration = mDeviceIdleController.addPowerSaveTempWhitelistAppForSms( 899 pkgName, 0, reason); 900 BroadcastOptions bopts = BroadcastOptions.makeBasic(); 901 bopts.setTemporaryAppWhitelistDuration(duration); 902 return bopts.toBundle(); 903 } catch (RemoteException e) { 904 } 905 906 return null; 907 } 908 909 /** 910 * Creates and dispatches the intent to the default SMS app or the appropriate port. 911 * 912 * @param pdus message pdus 913 * @param format the message format, typically "3gpp" or "3gpp2" 914 * @param destPort the destination port 915 * @param resultReceiver the receiver handling the delivery result 916 */ 917 void dispatchSmsDeliveryIntent(byte[][] pdus, String format, int destPort, 918 BroadcastReceiver resultReceiver) { 919 Intent intent = new Intent(); 920 intent.putExtra("pdus", pdus); 921 intent.putExtra("format", format); 922 923 if (destPort == -1) { 924 intent.setAction(Intents.SMS_DELIVER_ACTION); 925 // Direct the intent to only the default SMS app. If we can't find a default SMS app 926 // then sent it to all broadcast receivers. 927 // We are deliberately delivering to the primary user's default SMS App. 928 ComponentName componentName = SmsApplication.getDefaultSmsApplication(mContext, true); 929 if (componentName != null) { 930 // Deliver SMS message only to this receiver. 931 intent.setComponent(componentName); 932 log("Delivering SMS to: " + componentName.getPackageName() + 933 " " + componentName.getClassName()); 934 } else { 935 intent.setComponent(null); 936 } 937 938 // TODO: Validate that this is the right place to store the SMS. 939 if (SmsManager.getDefault().getAutoPersisting()) { 940 final Uri uri = writeInboxMessage(intent); 941 if (uri != null) { 942 // Pass this to SMS apps so that they know where it is stored 943 intent.putExtra("uri", uri.toString()); 944 } 945 } 946 } else { 947 intent.setAction(Intents.DATA_SMS_RECEIVED_ACTION); 948 Uri uri = Uri.parse("sms://localhost:" + destPort); 949 intent.setData(uri); 950 intent.setComponent(null); 951 } 952 953 Bundle options = handleSmsWhitelisting(intent.getComponent()); 954 dispatchIntent(intent, android.Manifest.permission.RECEIVE_SMS, 955 AppOpsManager.OP_RECEIVE_SMS, options, resultReceiver, UserHandle.SYSTEM); 956 } 957 958 /** 959 * Insert a message PDU into the raw table so we can acknowledge it immediately. 960 * If the device crashes before the broadcast to listeners completes, it will be delivered 961 * from the raw table on the next device boot. For single-part messages, the deleteWhere 962 * and deleteWhereArgs fields of the tracker will be set to delete the correct row after 963 * the ordered broadcast completes. 964 * 965 * @param tracker the tracker to add to the raw table 966 * @return true on success; false on failure to write to database 967 */ 968 private int addTrackerToRawTable(InboundSmsTracker tracker) { 969 if (tracker.getMessageCount() != 1) { 970 // check for duplicate message segments 971 Cursor cursor = null; 972 try { 973 // sequence numbers are 1-based except for CDMA WAP, which is 0-based 974 int sequence = tracker.getSequenceNumber(); 975 976 // convert to strings for query 977 String address = tracker.getAddress(); 978 String refNumber = Integer.toString(tracker.getReferenceNumber()); 979 String count = Integer.toString(tracker.getMessageCount()); 980 981 String seqNumber = Integer.toString(sequence); 982 983 // set the delete selection args for multi-part message 984 String[] deleteWhereArgs = {address, refNumber, count}; 985 tracker.setDeleteWhere(SELECT_BY_REFERENCE, deleteWhereArgs); 986 987 // Check for duplicate message segments 988 cursor = mResolver.query(sRawUri, PDU_PROJECTION, 989 "address=? AND reference_number=? AND count=? AND sequence=?", 990 new String[] {address, refNumber, count, seqNumber}, null); 991 992 // moveToNext() returns false if no duplicates were found 993 if (cursor.moveToNext()) { 994 loge("Discarding duplicate message segment, refNumber=" + refNumber 995 + " seqNumber=" + seqNumber); 996 String oldPduString = cursor.getString(PDU_COLUMN); 997 byte[] pdu = tracker.getPdu(); 998 byte[] oldPdu = HexDump.hexStringToByteArray(oldPduString); 999 if (!Arrays.equals(oldPdu, tracker.getPdu())) { 1000 loge("Warning: dup message segment PDU of length " + pdu.length 1001 + " is different from existing PDU of length " + oldPdu.length); 1002 } 1003 return Intents.RESULT_SMS_DUPLICATED; // reject message 1004 } 1005 cursor.close(); 1006 } catch (SQLException e) { 1007 loge("Can't access multipart SMS database", e); 1008 return Intents.RESULT_SMS_GENERIC_ERROR; // reject message 1009 } finally { 1010 if (cursor != null) { 1011 cursor.close(); 1012 } 1013 } 1014 } 1015 1016 ContentValues values = tracker.getContentValues(); 1017 1018 if (VDBG) log("adding content values to raw table: " + values.toString()); 1019 Uri newUri = mResolver.insert(sRawUri, values); 1020 if (DBG) log("URI of new row -> " + newUri); 1021 1022 try { 1023 long rowId = ContentUris.parseId(newUri); 1024 if (tracker.getMessageCount() == 1) { 1025 // set the delete selection args for single-part message 1026 tracker.setDeleteWhere(SELECT_BY_ID, new String[]{Long.toString(rowId)}); 1027 } 1028 return Intents.RESULT_SMS_HANDLED; 1029 } catch (Exception e) { 1030 loge("error parsing URI for new row: " + newUri, e); 1031 return Intents.RESULT_SMS_GENERIC_ERROR; 1032 } 1033 } 1034 1035 /** 1036 * Returns whether the default message format for the current radio technology is 3GPP2. 1037 * @return true if the radio technology uses 3GPP2 format by default, false for 3GPP format 1038 */ 1039 static boolean isCurrentFormat3gpp2() { 1040 int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(); 1041 return (PHONE_TYPE_CDMA == activePhone); 1042 } 1043 1044 protected void storeVoiceMailCount() { 1045 // Store the voice mail count in persistent memory. 1046 String imsi = mPhone.getSubscriberId(); 1047 int mwi = mPhone.getVoiceMessageCount(); 1048 1049 log("Storing Voice Mail Count = " + mwi 1050 + " for mVmCountKey = " + mPhone.VM_COUNT 1051 + " vmId = " + mPhone.VM_ID 1052 + " in preferences."); 1053 1054 SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext); 1055 SharedPreferences.Editor editor = sp.edit(); 1056 editor.putInt(mPhone.VM_COUNT, mwi); 1057 editor.putString(mPhone.VM_ID, imsi); 1058 editor.commit(); 1059 } 1060 1061 /** 1062 * Handler for an {@link InboundSmsTracker} broadcast. Deletes PDUs from the raw table and 1063 * logs the broadcast duration (as an error if the other receivers were especially slow). 1064 */ 1065 private final class SmsBroadcastReceiver extends BroadcastReceiver { 1066 private final String mDeleteWhere; 1067 private final String[] mDeleteWhereArgs; 1068 private long mBroadcastTimeNano; 1069 1070 SmsBroadcastReceiver(InboundSmsTracker tracker) { 1071 mDeleteWhere = tracker.getDeleteWhere(); 1072 mDeleteWhereArgs = tracker.getDeleteWhereArgs(); 1073 mBroadcastTimeNano = System.nanoTime(); 1074 } 1075 1076 @Override 1077 public void onReceive(Context context, Intent intent) { 1078 String action = intent.getAction(); 1079 if (action.equals(Intents.SMS_DELIVER_ACTION)) { 1080 // Now dispatch the notification only intent 1081 intent.setAction(Intents.SMS_RECEIVED_ACTION); 1082 intent.setComponent(null); 1083 // All running users will be notified of the received sms. 1084 Bundle options = handleSmsWhitelisting(null); 1085 dispatchIntent(intent, android.Manifest.permission.RECEIVE_SMS, 1086 AppOpsManager.OP_RECEIVE_SMS, options, this, UserHandle.ALL); 1087 } else if (action.equals(Intents.WAP_PUSH_DELIVER_ACTION)) { 1088 // Now dispatch the notification only intent 1089 intent.setAction(Intents.WAP_PUSH_RECEIVED_ACTION); 1090 intent.setComponent(null); 1091 // Only the primary user will receive notification of incoming mms. 1092 // That app will do the actual downloading of the mms. 1093 Bundle options = null; 1094 try { 1095 long duration = mDeviceIdleController.addPowerSaveTempWhitelistAppForMms( 1096 mContext.getPackageName(), 0, "mms-broadcast"); 1097 BroadcastOptions bopts = BroadcastOptions.makeBasic(); 1098 bopts.setTemporaryAppWhitelistDuration(duration); 1099 options = bopts.toBundle(); 1100 } catch (RemoteException e) { 1101 } 1102 1103 String mimeType = intent.getType(); 1104 dispatchIntent(intent, WapPushOverSms.getPermissionForType(mimeType), 1105 WapPushOverSms.getAppOpsPermissionForIntent(mimeType), options, this, 1106 UserHandle.SYSTEM); 1107 } else { 1108 // Now that the intents have been deleted we can clean up the PDU data. 1109 if (!Intents.DATA_SMS_RECEIVED_ACTION.equals(action) 1110 && !Intents.SMS_RECEIVED_ACTION.equals(action) 1111 && !Intents.DATA_SMS_RECEIVED_ACTION.equals(action) 1112 && !Intents.WAP_PUSH_RECEIVED_ACTION.equals(action)) { 1113 loge("unexpected BroadcastReceiver action: " + action); 1114 } 1115 1116 int rc = getResultCode(); 1117 if ((rc != Activity.RESULT_OK) && (rc != Intents.RESULT_SMS_HANDLED)) { 1118 loge("a broadcast receiver set the result code to " + rc 1119 + ", deleting from raw table anyway!"); 1120 } else if (DBG) { 1121 log("successful broadcast, deleting from raw table."); 1122 } 1123 1124 deleteFromRawTable(mDeleteWhere, mDeleteWhereArgs); 1125 sendMessage(EVENT_BROADCAST_COMPLETE); 1126 1127 int durationMillis = (int) ((System.nanoTime() - mBroadcastTimeNano) / 1000000); 1128 if (durationMillis >= 5000) { 1129 loge("Slow ordered broadcast completion time: " + durationMillis + " ms"); 1130 } else if (DBG) { 1131 log("ordered broadcast completed in: " + durationMillis + " ms"); 1132 } 1133 } 1134 } 1135 } 1136 1137 /** 1138 * Asynchronously binds to the carrier messaging service, and filters out the message if 1139 * instructed to do so by the carrier messaging service. A new instance must be used for every 1140 * message. 1141 */ 1142 private final class CarrierSmsFilter extends CarrierMessagingServiceManager { 1143 private final byte[][] mPdus; 1144 private final int mDestPort; 1145 private final String mSmsFormat; 1146 private final SmsBroadcastReceiver mSmsBroadcastReceiver; 1147 // Instantiated in filterSms. 1148 private volatile CarrierSmsFilterCallback mSmsFilterCallback; 1149 1150 CarrierSmsFilter(byte[][] pdus, int destPort, String smsFormat, 1151 SmsBroadcastReceiver smsBroadcastReceiver) { 1152 mPdus = pdus; 1153 mDestPort = destPort; 1154 mSmsFormat = smsFormat; 1155 mSmsBroadcastReceiver = smsBroadcastReceiver; 1156 } 1157 1158 /** 1159 * Attempts to bind to a {@link ICarrierMessagingService}. Filtering is initiated 1160 * asynchronously once the service is ready using {@link #onServiceReady}. 1161 */ 1162 void filterSms(String carrierPackageName, CarrierSmsFilterCallback smsFilterCallback) { 1163 mSmsFilterCallback = smsFilterCallback; 1164 if (!bindToCarrierMessagingService(mContext, carrierPackageName)) { 1165 loge("bindService() for carrier messaging service failed"); 1166 smsFilterCallback.onFilterComplete(true); 1167 } else { 1168 logv("bindService() for carrier messaging service succeeded"); 1169 } 1170 } 1171 1172 /** 1173 * Invokes the {@code carrierMessagingService} to filter messages. The filtering result is 1174 * delivered to {@code smsFilterCallback}. 1175 */ 1176 @Override 1177 protected void onServiceReady(ICarrierMessagingService carrierMessagingService) { 1178 try { 1179 carrierMessagingService.filterSms( 1180 new MessagePdu(Arrays.asList(mPdus)), mSmsFormat, mDestPort, 1181 mPhone.getSubId(), mSmsFilterCallback); 1182 } catch (RemoteException e) { 1183 loge("Exception filtering the SMS: " + e); 1184 mSmsFilterCallback.onFilterComplete(true); 1185 } 1186 } 1187 } 1188 1189 /** 1190 * A callback used to notify the platform of the carrier messaging app filtering result. Once 1191 * the result is ready, the carrier messaging service connection is disposed. 1192 */ 1193 private final class CarrierSmsFilterCallback extends ICarrierMessagingCallback.Stub { 1194 private final CarrierSmsFilter mSmsFilter; 1195 1196 CarrierSmsFilterCallback(CarrierSmsFilter smsFilter) { 1197 mSmsFilter = smsFilter; 1198 } 1199 1200 /** 1201 * This method should be called only once. 1202 */ 1203 @Override 1204 public void onFilterComplete(boolean keepMessage) { 1205 mSmsFilter.disposeConnection(mContext); 1206 1207 logv("onFilterComplete: keepMessage is "+ keepMessage); 1208 if (keepMessage) { 1209 dispatchSmsDeliveryIntent(mSmsFilter.mPdus, mSmsFilter.mSmsFormat, 1210 mSmsFilter.mDestPort, mSmsFilter.mSmsBroadcastReceiver); 1211 } else { 1212 // Drop this SMS. 1213 final long token = Binder.clearCallingIdentity(); 1214 try { 1215 // Needs phone package permissions. 1216 deleteFromRawTable(mSmsFilter.mSmsBroadcastReceiver.mDeleteWhere, 1217 mSmsFilter.mSmsBroadcastReceiver.mDeleteWhereArgs); 1218 } finally { 1219 Binder.restoreCallingIdentity(token); 1220 } 1221 sendMessage(EVENT_BROADCAST_COMPLETE); 1222 } 1223 } 1224 1225 @Override 1226 public void onSendSmsComplete(int result, int messageRef) { 1227 loge("Unexpected onSendSmsComplete call with result: " + result); 1228 } 1229 1230 @Override 1231 public void onSendMultipartSmsComplete(int result, int[] messageRefs) { 1232 loge("Unexpected onSendMultipartSmsComplete call with result: " + result); 1233 } 1234 1235 @Override 1236 public void onSendMmsComplete(int result, byte[] sendConfPdu) { 1237 loge("Unexpected onSendMmsComplete call with result: " + result); 1238 } 1239 1240 @Override 1241 public void onDownloadMmsComplete(int result) { 1242 loge("Unexpected onDownloadMmsComplete call with result: " + result); 1243 } 1244 } 1245 1246 /** 1247 * Log with debug level. 1248 * @param s the string to log 1249 */ 1250 @Override 1251 protected void log(String s) { 1252 Rlog.d(getName(), s); 1253 } 1254 1255 /** 1256 * Log with error level. 1257 * @param s the string to log 1258 */ 1259 @Override 1260 protected void loge(String s) { 1261 Rlog.e(getName(), s); 1262 } 1263 1264 /** 1265 * Log with error level. 1266 * @param s the string to log 1267 * @param e is a Throwable which logs additional information. 1268 */ 1269 @Override 1270 protected void loge(String s, Throwable e) { 1271 Rlog.e(getName(), s, e); 1272 } 1273 1274 /** 1275 * Store a received SMS into Telephony provider 1276 * 1277 * @param intent The intent containing the received SMS 1278 * @return The URI of written message 1279 */ 1280 private Uri writeInboxMessage(Intent intent) { 1281 final SmsMessage[] messages = Telephony.Sms.Intents.getMessagesFromIntent(intent); 1282 if (messages == null || messages.length < 1) { 1283 loge("Failed to parse SMS pdu"); 1284 return null; 1285 } 1286 // Sometimes, SmsMessage.mWrappedSmsMessage is null causing NPE when we access 1287 // the methods on it although the SmsMessage itself is not null. So do this check 1288 // before we do anything on the parsed SmsMessages. 1289 for (final SmsMessage sms : messages) { 1290 try { 1291 sms.getDisplayMessageBody(); 1292 } catch (NullPointerException e) { 1293 loge("NPE inside SmsMessage"); 1294 return null; 1295 } 1296 } 1297 final ContentValues values = parseSmsMessage(messages); 1298 final long identity = Binder.clearCallingIdentity(); 1299 try { 1300 return mContext.getContentResolver().insert(Telephony.Sms.Inbox.CONTENT_URI, values); 1301 } catch (Exception e) { 1302 loge("Failed to persist inbox message", e); 1303 } finally { 1304 Binder.restoreCallingIdentity(identity); 1305 } 1306 return null; 1307 } 1308 1309 /** 1310 * Convert SmsMessage[] into SMS database schema columns 1311 * 1312 * @param msgs The SmsMessage array of the received SMS 1313 * @return ContentValues representing the columns of parsed SMS 1314 */ 1315 private static ContentValues parseSmsMessage(SmsMessage[] msgs) { 1316 final SmsMessage sms = msgs[0]; 1317 final ContentValues values = new ContentValues(); 1318 values.put(Telephony.Sms.Inbox.ADDRESS, sms.getDisplayOriginatingAddress()); 1319 values.put(Telephony.Sms.Inbox.BODY, buildMessageBodyFromPdus(msgs)); 1320 values.put(Telephony.Sms.Inbox.DATE_SENT, sms.getTimestampMillis()); 1321 values.put(Telephony.Sms.Inbox.DATE, System.currentTimeMillis()); 1322 values.put(Telephony.Sms.Inbox.PROTOCOL, sms.getProtocolIdentifier()); 1323 values.put(Telephony.Sms.Inbox.SEEN, 0); 1324 values.put(Telephony.Sms.Inbox.READ, 0); 1325 final String subject = sms.getPseudoSubject(); 1326 if (!TextUtils.isEmpty(subject)) { 1327 values.put(Telephony.Sms.Inbox.SUBJECT, subject); 1328 } 1329 values.put(Telephony.Sms.Inbox.REPLY_PATH_PRESENT, sms.isReplyPathPresent() ? 1 : 0); 1330 values.put(Telephony.Sms.Inbox.SERVICE_CENTER, sms.getServiceCenterAddress()); 1331 return values; 1332 } 1333 1334 /** 1335 * Build up the SMS message body from the SmsMessage array of received SMS 1336 * 1337 * @param msgs The SmsMessage array of the received SMS 1338 * @return The text message body 1339 */ 1340 private static String buildMessageBodyFromPdus(SmsMessage[] msgs) { 1341 if (msgs.length == 1) { 1342 // There is only one part, so grab the body directly. 1343 return replaceFormFeeds(msgs[0].getDisplayMessageBody()); 1344 } else { 1345 // Build up the body from the parts. 1346 StringBuilder body = new StringBuilder(); 1347 for (SmsMessage msg: msgs) { 1348 // getDisplayMessageBody() can NPE if mWrappedMessage inside is null. 1349 body.append(msg.getDisplayMessageBody()); 1350 } 1351 return replaceFormFeeds(body.toString()); 1352 } 1353 } 1354 1355 // Some providers send formfeeds in their messages. Convert those formfeeds to newlines. 1356 private static String replaceFormFeeds(String s) { 1357 return s == null ? "" : s.replace('\f', '\n'); 1358 } 1359} 1360