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