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