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 android.app.Activity; 20 import android.app.AppOpsManager; 21 import android.content.BroadcastReceiver; 22 import android.content.ComponentName; 23 import android.content.ContentResolver; 24 import android.content.ContentUris; 25 import android.content.ContentValues; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.database.Cursor; 29 import android.database.SQLException; 30 import android.net.Uri; 31 import android.os.AsyncResult; 32 import android.os.Build; 33 import android.os.Message; 34 import android.os.PowerManager; 35 import android.os.SystemProperties; 36 import android.provider.Telephony; 37 import android.provider.Telephony.Sms.Intents; 38 import android.telephony.Rlog; 39 import android.telephony.SmsMessage; 40 import android.telephony.TelephonyManager; 41 42 import com.android.internal.util.HexDump; 43 import com.android.internal.util.State; 44 import com.android.internal.util.StateMachine; 45 46 import java.io.ByteArrayOutputStream; 47 import java.util.Arrays; 48 49 import static android.telephony.TelephonyManager.PHONE_TYPE_CDMA; 50 51 /** 52 * This class broadcasts incoming SMS messages to interested apps after storing them in 53 * the SmsProvider "raw" table and ACKing them to the SMSC. After each message has been 54 * broadcast, its parts are removed from the raw table. If the device crashes after ACKing 55 * but before the broadcast completes, the pending messages will be rebroadcast on the next boot. 56 * 57 * <p>The state machine starts in {@link IdleState} state. When the {@link SMSDispatcher} receives a 58 * new SMS from the radio, it calls {@link #dispatchNormalMessage}, 59 * which sends a message to the state machine, causing the wakelock to be acquired in 60 * {@link #haltedProcessMessage}, which transitions to {@link DeliveringState} state, where the message 61 * is saved to the raw table, then acknowledged via the {@link SMSDispatcher} which called us. 62 * 63 * <p>After saving the SMS, if the message is complete (either single-part or the final segment 64 * of a multi-part SMS), we broadcast the completed PDUs as an ordered broadcast, then transition to 65 * {@link WaitingState} state to wait for the broadcast to complete. When the local 66 * {@link BroadcastReceiver} is called with the result, it sends {@link #EVENT_BROADCAST_COMPLETE} 67 * to the state machine, causing us to either broadcast the next pending message (if one has 68 * arrived while waiting for the broadcast to complete), or to transition back to the halted state 69 * after all messages are processed. Then the wakelock is released and we wait for the next SMS. 70 */ 71 public abstract class InboundSmsHandler extends StateMachine { 72 protected static final boolean DBG = true; 73 private static final boolean VDBG = false; // STOPSHIP if true, logs user data 74 75 /** Query projection for checking for duplicate message segments. */ 76 private static final String[] PDU_PROJECTION = { 77 "pdu" 78 }; 79 80 /** Query projection for combining concatenated message segments. */ 81 private static final String[] PDU_SEQUENCE_PORT_PROJECTION = { 82 "pdu", 83 "sequence", 84 "destination_port" 85 }; 86 87 static final int PDU_COLUMN = 0; 88 static final int SEQUENCE_COLUMN = 1; 89 static final int DESTINATION_PORT_COLUMN = 2; 90 static final int DATE_COLUMN = 3; 91 static final int REFERENCE_NUMBER_COLUMN = 4; 92 static final int COUNT_COLUMN = 5; 93 static final int ADDRESS_COLUMN = 6; 94 static final int ID_COLUMN = 7; 95 96 static final String SELECT_BY_ID = "_id=?"; 97 static final String SELECT_BY_REFERENCE = "address=? AND reference_number=? AND count=?"; 98 99 /** New SMS received as an AsyncResult. */ 100 public static final int EVENT_NEW_SMS = 1; 101 102 /** Message type containing a {@link InboundSmsTracker} ready to broadcast to listeners. */ 103 static final int EVENT_BROADCAST_SMS = 2; 104 105 /** Message from resultReceiver notifying {@link WaitingState} of a completed broadcast. */ 106 static final int EVENT_BROADCAST_COMPLETE = 3; 107 108 /** Sent on exit from {@link WaitingState} to return to idle after sending all broadcasts. */ 109 static final int EVENT_RETURN_TO_IDLE = 4; 110 111 /** Release wakelock after a short timeout when returning to idle state. */ 112 static final int EVENT_RELEASE_WAKELOCK = 5; 113 114 /** Sent by {@link SmsBroadcastUndelivered} after cleaning the raw table. */ 115 static final int EVENT_START_ACCEPTING_SMS = 6; 116 117 /** Update phone object */ 118 static final int EVENT_UPDATE_PHONE_OBJECT = 7; 119 120 /** Wakelock release delay when returning to idle state. */ 121 private static final int WAKELOCK_TIMEOUT = 3000; 122 123 /** URI for raw table of SMS provider. */ 124 private static final Uri sRawUri = Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, "raw"); 125 126 protected final Context mContext; 127 private final ContentResolver mResolver; 128 129 /** Special handler for WAP push messages. */ 130 private final WapPushOverSms mWapPush; 131 132 /** Wake lock to ensure device stays awake while dispatching the SMS intents. */ 133 final PowerManager.WakeLock mWakeLock; 134 135 /** DefaultState throws an exception or logs an error for unhandled message types. */ 136 final DefaultState mDefaultState = new DefaultState(); 137 138 /** Startup state. Waiting for {@link SmsBroadcastUndelivered} to complete. */ 139 final StartupState mStartupState = new StartupState(); 140 141 /** Idle state. Waiting for messages to process. */ 142 final IdleState mIdleState = new IdleState(); 143 144 /** Delivering state. Saves the PDU in the raw table and acknowledges to SMSC. */ 145 final DeliveringState mDeliveringState = new DeliveringState(); 146 147 /** Broadcasting state. Waits for current broadcast to complete before delivering next. */ 148 final WaitingState mWaitingState = new WaitingState(); 149 150 /** Helper class to check whether storage is available for incoming messages. */ 151 protected SmsStorageMonitor mStorageMonitor; 152 153 private final boolean mSmsReceiveDisabled; 154 155 protected PhoneBase mPhone; 156 157 protected CellBroadcastHandler mCellBroadcastHandler; 158 159 160 /** 161 * Create a new SMS broadcast helper. 162 * @param name the class name for logging 163 * @param context the context of the phone app 164 * @param storageMonitor the SmsStorageMonitor to check for storage availability 165 */ 166 protected InboundSmsHandler(String name, Context context, SmsStorageMonitor storageMonitor, 167 PhoneBase phone, CellBroadcastHandler cellBroadcastHandler) { 168 super(name); 169 170 mContext = context; 171 mStorageMonitor = storageMonitor; 172 mPhone = phone; 173 mCellBroadcastHandler = cellBroadcastHandler; 174 mResolver = context.getContentResolver(); 175 mWapPush = new WapPushOverSms(context); 176 177 boolean smsCapable = mContext.getResources().getBoolean( 178 com.android.internal.R.bool.config_sms_capable); 179 mSmsReceiveDisabled = !SystemProperties.getBoolean( 180 TelephonyProperties.PROPERTY_SMS_RECEIVE, smsCapable); 181 182 PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 183 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, name); 184 mWakeLock.acquire(); // wake lock released after we enter idle state 185 186 addState(mDefaultState); 187 addState(mStartupState, mDefaultState); 188 addState(mIdleState, mDefaultState); 189 addState(mDeliveringState, mDefaultState); 190 addState(mWaitingState, mDeliveringState); 191 192 setInitialState(mStartupState); 193 if (DBG) log("created InboundSmsHandler"); 194 } 195 196 /** 197 * Tell the state machine to quit after processing all messages. 198 */ 199 public void dispose() { 200 quit(); 201 } 202 203 /** 204 * Update the phone object when it changes. 205 */ 206 public void updatePhoneObject(PhoneBase phone) { 207 sendMessage(EVENT_UPDATE_PHONE_OBJECT, phone); 208 } 209 210 /** 211 * Dispose of the WAP push object and release the wakelock. 212 */ 213 @Override 214 protected void onQuitting() { 215 mWapPush.dispose(); 216 217 while (mWakeLock.isHeld()) { 218 mWakeLock.release(); 219 } 220 } 221 222 /** 223 * This parent state throws an exception (for debug builds) or prints an error for unhandled 224 * message types. 225 */ 226 class DefaultState extends State { 227 @Override 228 public boolean processMessage(Message msg) { 229 switch (msg.what) { 230 case EVENT_UPDATE_PHONE_OBJECT: { 231 onUpdatePhoneObject((PhoneBase) msg.obj); 232 break; 233 } 234 default: { 235 String errorText = "processMessage: unhandled message type " + msg.what; 236 if (Build.IS_DEBUGGABLE) { 237 throw new RuntimeException(errorText); 238 } else { 239 loge(errorText); 240 } 241 break; 242 } 243 } 244 return HANDLED; 245 } 246 } 247 248 /** 249 * The Startup state waits for {@link SmsBroadcastUndelivered} to process the raw table and 250 * notify the state machine to broadcast any complete PDUs that might not have been broadcast. 251 */ 252 class StartupState extends State { 253 @Override 254 public boolean processMessage(Message msg) { 255 switch (msg.what) { 256 case EVENT_NEW_SMS: 257 case EVENT_BROADCAST_SMS: 258 deferMessage(msg); 259 return HANDLED; 260 261 case EVENT_START_ACCEPTING_SMS: 262 transitionTo(mIdleState); 263 return HANDLED; 264 265 case EVENT_BROADCAST_COMPLETE: 266 case EVENT_RETURN_TO_IDLE: 267 case EVENT_RELEASE_WAKELOCK: 268 default: 269 // let DefaultState handle these unexpected message types 270 return NOT_HANDLED; 271 } 272 } 273 } 274 275 /** 276 * In the idle state the wakelock is released until a new SM arrives, then we transition 277 * to Delivering mode to handle it, acquiring the wakelock on exit. 278 */ 279 class IdleState extends State { 280 @Override 281 public void enter() { 282 if (DBG) log("entering Idle state"); 283 sendMessageDelayed(EVENT_RELEASE_WAKELOCK, WAKELOCK_TIMEOUT); 284 } 285 286 @Override 287 public void exit() { 288 mWakeLock.acquire(); 289 if (DBG) log("acquired wakelock, leaving Idle state"); 290 } 291 292 @Override 293 public boolean processMessage(Message msg) { 294 if (DBG) log("Idle state processing message type " + msg.what); 295 switch (msg.what) { 296 case EVENT_NEW_SMS: 297 case EVENT_BROADCAST_SMS: 298 deferMessage(msg); 299 transitionTo(mDeliveringState); 300 return HANDLED; 301 302 case EVENT_RELEASE_WAKELOCK: 303 mWakeLock.release(); 304 if (DBG) { 305 if (mWakeLock.isHeld()) { 306 // this is okay as long as we call release() for every acquire() 307 log("mWakeLock is still held after release"); 308 } else { 309 log("mWakeLock released"); 310 } 311 } 312 return HANDLED; 313 314 case EVENT_RETURN_TO_IDLE: 315 // already in idle state; ignore 316 return HANDLED; 317 318 case EVENT_BROADCAST_COMPLETE: 319 case EVENT_START_ACCEPTING_SMS: 320 default: 321 // let DefaultState handle these unexpected message types 322 return NOT_HANDLED; 323 } 324 } 325 } 326 327 /** 328 * In the delivering state, the inbound SMS is processed and stored in the raw table. 329 * The message is acknowledged before we exit this state. If there is a message to broadcast, 330 * transition to {@link WaitingState} state to send the ordered broadcast and wait for the 331 * results. When all messages have been processed, the halting state will release the wakelock. 332 */ 333 class DeliveringState extends State { 334 @Override 335 public void enter() { 336 if (DBG) log("entering Delivering state"); 337 } 338 339 @Override 340 public void exit() { 341 if (DBG) log("leaving Delivering state"); 342 } 343 344 @Override 345 public boolean processMessage(Message msg) { 346 switch (msg.what) { 347 case EVENT_NEW_SMS: 348 // handle new SMS from RIL 349 handleNewSms((AsyncResult) msg.obj); 350 sendMessage(EVENT_RETURN_TO_IDLE); 351 return HANDLED; 352 353 case EVENT_BROADCAST_SMS: 354 // if any broadcasts were sent, transition to waiting state 355 if (processMessagePart((InboundSmsTracker) msg.obj)) { 356 transitionTo(mWaitingState); 357 } 358 return HANDLED; 359 360 case EVENT_RETURN_TO_IDLE: 361 // return to idle after processing all other messages 362 transitionTo(mIdleState); 363 return HANDLED; 364 365 case EVENT_RELEASE_WAKELOCK: 366 mWakeLock.release(); // decrement wakelock from previous entry to Idle 367 if (!mWakeLock.isHeld()) { 368 // wakelock should still be held until 3 seconds after we enter Idle 369 loge("mWakeLock released while delivering/broadcasting!"); 370 } 371 return HANDLED; 372 373 // we shouldn't get this message type in this state, log error and halt. 374 case EVENT_BROADCAST_COMPLETE: 375 case EVENT_START_ACCEPTING_SMS: 376 default: 377 // let DefaultState handle these unexpected message types 378 return NOT_HANDLED; 379 } 380 } 381 } 382 383 /** 384 * The waiting state delegates handling of new SMS to parent {@link DeliveringState}, but 385 * defers handling of the {@link #EVENT_BROADCAST_SMS} phase until after the current 386 * result receiver sends {@link #EVENT_BROADCAST_COMPLETE}. Before transitioning to 387 * {@link DeliveringState}, {@link #EVENT_RETURN_TO_IDLE} is sent to transition to 388 * {@link IdleState} after any deferred {@link #EVENT_BROADCAST_SMS} messages are handled. 389 */ 390 class WaitingState extends State { 391 @Override 392 public boolean processMessage(Message msg) { 393 switch (msg.what) { 394 case EVENT_BROADCAST_SMS: 395 // defer until the current broadcast completes 396 deferMessage(msg); 397 return HANDLED; 398 399 case EVENT_BROADCAST_COMPLETE: 400 // return to idle after handling all deferred messages 401 sendMessage(EVENT_RETURN_TO_IDLE); 402 transitionTo(mDeliveringState); 403 return HANDLED; 404 405 case EVENT_RETURN_TO_IDLE: 406 // not ready to return to idle; ignore 407 return HANDLED; 408 409 default: 410 // parent state handles the other message types 411 return NOT_HANDLED; 412 } 413 } 414 } 415 416 void handleNewSms(AsyncResult ar) { 417 if (ar.exception != null) { 418 loge("Exception processing incoming SMS: " + ar.exception); 419 return; 420 } 421 422 int result; 423 try { 424 SmsMessage sms = (SmsMessage) ar.result; 425 result = dispatchMessage(sms.mWrappedSmsMessage); 426 } catch (RuntimeException ex) { 427 loge("Exception dispatching message", ex); 428 result = Intents.RESULT_SMS_GENERIC_ERROR; 429 } 430 431 // RESULT_OK means that the SMS will be acknowledged by special handling, 432 // e.g. for SMS-PP data download. Any other result, we should ack here. 433 if (result != Activity.RESULT_OK) { 434 boolean handled = (result == Intents.RESULT_SMS_HANDLED); 435 notifyAndAcknowledgeLastIncomingSms(handled, result, null); 436 } 437 } 438 439 /** 440 * Process an SMS message from the RIL, calling subclass methods to handle 3GPP and 441 * 3GPP2-specific message types. 442 * 443 * @param smsb the SmsMessageBase object from the RIL 444 * @return a result code from {@link android.provider.Telephony.Sms.Intents}, 445 * or {@link Activity#RESULT_OK} for delayed acknowledgment to SMSC 446 */ 447 public int dispatchMessage(SmsMessageBase smsb) { 448 // If sms is null, there was a parsing error. 449 if (smsb == null) { 450 loge("dispatchSmsMessage: message is null"); 451 return Intents.RESULT_SMS_GENERIC_ERROR; 452 } 453 454 if (mSmsReceiveDisabled) { 455 // Device doesn't support receiving SMS, 456 log("Received short message on device which doesn't support " 457 + "receiving SMS. Ignored."); 458 return Intents.RESULT_SMS_HANDLED; 459 } 460 461 return dispatchMessageRadioSpecific(smsb); 462 } 463 464 /** 465 * Process voicemail notification, SMS-PP data download, CDMA CMAS, CDMA WAP push, and other 466 * 3GPP/3GPP2-specific messages. Regular SMS messages are handled by calling the shared 467 * {@link #dispatchNormalMessage} from this class. 468 * 469 * @param smsb the SmsMessageBase object from the RIL 470 * @return a result code from {@link android.provider.Telephony.Sms.Intents}, 471 * or {@link Activity#RESULT_OK} for delayed acknowledgment to SMSC 472 */ 473 protected abstract int dispatchMessageRadioSpecific(SmsMessageBase smsb); 474 475 /** 476 * Send an acknowledge message to the SMSC. 477 * @param success indicates that last message was successfully received. 478 * @param result result code indicating any error 479 * @param response callback message sent when operation completes. 480 */ 481 protected abstract void acknowledgeLastIncomingSms(boolean success, 482 int result, Message response); 483 484 /** 485 * Called when the phone changes the default method updates mPhone 486 * mStorageMonitor and mCellBroadcastHandler.updatePhoneObject. 487 * Override if different or other behavior is desired. 488 * 489 * @param phone 490 */ 491 protected void onUpdatePhoneObject(PhoneBase phone) { 492 mPhone = phone; 493 mStorageMonitor = mPhone.mSmsStorageMonitor; 494 log("onUpdatePhoneObject: phone=" + mPhone.getClass().getSimpleName()); 495 } 496 497 /** 498 * Notify interested apps if the framework has rejected an incoming SMS, 499 * and send an acknowledge message to the network. 500 * @param success indicates that last message was successfully received. 501 * @param result result code indicating any error 502 * @param response callback message sent when operation completes. 503 */ 504 void notifyAndAcknowledgeLastIncomingSms(boolean success, 505 int result, Message response) { 506 if (!success) { 507 // broadcast SMS_REJECTED_ACTION intent 508 Intent intent = new Intent(Intents.SMS_REJECTED_ACTION); 509 intent.putExtra("result", result); 510 mContext.sendBroadcast(intent, android.Manifest.permission.RECEIVE_SMS); 511 } 512 acknowledgeLastIncomingSms(success, result, response); 513 } 514 515 /** 516 * Return true if this handler is for 3GPP2 messages; false for 3GPP format. 517 * @return true for the 3GPP2 handler; false for the 3GPP handler 518 */ 519 protected abstract boolean is3gpp2(); 520 521 /** 522 * Dispatch a normal incoming SMS. This is called from {@link #dispatchMessageRadioSpecific} 523 * if no format-specific handling was required. Saves the PDU to the SMS provider raw table, 524 * creates an {@link InboundSmsTracker}, then sends it to the state machine as an 525 * {@link #EVENT_BROADCAST_SMS}. Returns {@link Intents#RESULT_SMS_HANDLED} or an error value. 526 * 527 * @param sms the message to dispatch 528 * @return {@link Intents#RESULT_SMS_HANDLED} if the message was accepted, or an error status 529 */ 530 protected int dispatchNormalMessage(SmsMessageBase sms) { 531 SmsHeader smsHeader = sms.getUserDataHeader(); 532 InboundSmsTracker tracker; 533 534 if ((smsHeader == null) || (smsHeader.concatRef == null)) { 535 // Message is not concatenated. 536 int destPort = -1; 537 if (smsHeader != null && smsHeader.portAddrs != null) { 538 // The message was sent to a port. 539 destPort = smsHeader.portAddrs.destPort; 540 if (DBG) log("destination port: " + destPort); 541 } 542 543 tracker = new InboundSmsTracker(sms.getPdu(), sms.getTimestampMillis(), destPort, 544 is3gpp2(), false); 545 } else { 546 // Create a tracker for this message segment. 547 SmsHeader.ConcatRef concatRef = smsHeader.concatRef; 548 SmsHeader.PortAddrs portAddrs = smsHeader.portAddrs; 549 int destPort = (portAddrs != null ? portAddrs.destPort : -1); 550 551 tracker = new InboundSmsTracker(sms.getPdu(), sms.getTimestampMillis(), destPort, 552 is3gpp2(), sms.getOriginatingAddress(), concatRef.refNumber, 553 concatRef.seqNumber, concatRef.msgCount, false); 554 } 555 556 if (VDBG) log("created tracker: " + tracker); 557 return addTrackerToRawTableAndSendMessage(tracker); 558 } 559 560 /** 561 * Helper to add the tracker to the raw table and then send a message to broadcast it, if 562 * successful. Returns the SMS intent status to return to the SMSC. 563 * @param tracker the tracker to save to the raw table and then deliver 564 * @return {@link Intents#RESULT_SMS_HANDLED} or {@link Intents#RESULT_SMS_GENERIC_ERROR} 565 * or {@link Intents#RESULT_SMS_DUPLICATED} 566 */ 567 protected int addTrackerToRawTableAndSendMessage(InboundSmsTracker tracker) { 568 switch(addTrackerToRawTable(tracker)) { 569 case Intents.RESULT_SMS_HANDLED: 570 sendMessage(EVENT_BROADCAST_SMS, tracker); 571 return Intents.RESULT_SMS_HANDLED; 572 573 case Intents.RESULT_SMS_DUPLICATED: 574 return Intents.RESULT_SMS_HANDLED; 575 576 case Intents.RESULT_SMS_GENERIC_ERROR: 577 default: 578 return Intents.RESULT_SMS_GENERIC_ERROR; 579 } 580 } 581 582 /** 583 * Process the inbound SMS segment. If the message is complete, send it as an ordered 584 * broadcast to interested receivers and return true. If the message is a segment of an 585 * incomplete multi-part SMS, return false. 586 * @param tracker the tracker containing the message segment to process 587 * @return true if an ordered broadcast was sent; false if waiting for more message segments 588 */ 589 boolean processMessagePart(InboundSmsTracker tracker) { 590 int messageCount = tracker.getMessageCount(); 591 byte[][] pdus; 592 int destPort = tracker.getDestPort(); 593 594 if (messageCount == 1) { 595 // single-part message 596 pdus = new byte[][]{tracker.getPdu()}; 597 } else { 598 // multi-part message 599 Cursor cursor = null; 600 try { 601 // used by several query selection arguments 602 String address = tracker.getAddress(); 603 String refNumber = Integer.toString(tracker.getReferenceNumber()); 604 String count = Integer.toString(tracker.getMessageCount()); 605 606 // query for all segments and broadcast message if we have all the parts 607 String[] whereArgs = {address, refNumber, count}; 608 cursor = mResolver.query(sRawUri, PDU_SEQUENCE_PORT_PROJECTION, 609 SELECT_BY_REFERENCE, whereArgs, null); 610 611 int cursorCount = cursor.getCount(); 612 if (cursorCount < messageCount) { 613 // Wait for the other message parts to arrive. It's also possible for the last 614 // segment to arrive before processing the EVENT_BROADCAST_SMS for one of the 615 // earlier segments. In that case, the broadcast will be sent as soon as all 616 // segments are in the table, and any later EVENT_BROADCAST_SMS messages will 617 // get a row count of 0 and return. 618 return false; 619 } 620 621 // All the parts are in place, deal with them 622 pdus = new byte[messageCount][]; 623 while (cursor.moveToNext()) { 624 // subtract offset to convert sequence to 0-based array index 625 int index = cursor.getInt(SEQUENCE_COLUMN) - tracker.getIndexOffset(); 626 627 pdus[index] = HexDump.hexStringToByteArray(cursor.getString(PDU_COLUMN)); 628 629 // Read the destination port from the first segment (needed for CDMA WAP PDU). 630 // It's not a bad idea to prefer the port from the first segment in other cases. 631 if (index == 0 && !cursor.isNull(DESTINATION_PORT_COLUMN)) { 632 int port = cursor.getInt(DESTINATION_PORT_COLUMN); 633 // strip format flags and convert to real port number, or -1 634 port = InboundSmsTracker.getRealDestPort(port); 635 if (port != -1) { 636 destPort = port; 637 } 638 } 639 } 640 } catch (SQLException e) { 641 loge("Can't access multipart SMS database", e); 642 return false; 643 } finally { 644 if (cursor != null) { 645 cursor.close(); 646 } 647 } 648 } 649 650 BroadcastReceiver resultReceiver = new SmsBroadcastReceiver(tracker); 651 652 if (destPort == SmsHeader.PORT_WAP_PUSH) { 653 // Build up the data stream 654 ByteArrayOutputStream output = new ByteArrayOutputStream(); 655 for (byte[] pdu : pdus) { 656 // 3GPP needs to extract the User Data from the PDU; 3GPP2 has already done this 657 if (!tracker.is3gpp2()) { 658 SmsMessage msg = SmsMessage.createFromPdu(pdu, SmsConstants.FORMAT_3GPP); 659 pdu = msg.getUserData(); 660 } 661 output.write(pdu, 0, pdu.length); 662 } 663 int result = mWapPush.dispatchWapPdu(output.toByteArray(), resultReceiver, this); 664 if (DBG) log("dispatchWapPdu() returned " + result); 665 // result is Activity.RESULT_OK if an ordered broadcast was sent 666 return (result == Activity.RESULT_OK); 667 } 668 669 Intent intent; 670 if (destPort == -1) { 671 intent = new Intent(Intents.SMS_DELIVER_ACTION); 672 673 // Direct the intent to only the default SMS app. If we can't find a default SMS app 674 // then sent it to all broadcast receivers. 675 ComponentName componentName = SmsApplication.getDefaultSmsApplication(mContext, true); 676 if (componentName != null) { 677 // Deliver SMS message only to this receiver 678 intent.setComponent(componentName); 679 log("Delivering SMS to: " + componentName.getPackageName() + 680 " " + componentName.getClassName()); 681 } 682 } else { 683 Uri uri = Uri.parse("sms://localhost:" + destPort); 684 intent = new Intent(Intents.DATA_SMS_RECEIVED_ACTION, uri); 685 } 686 687 intent.putExtra("pdus", pdus); 688 intent.putExtra("format", tracker.getFormat()); 689 dispatchIntent(intent, android.Manifest.permission.RECEIVE_SMS, 690 AppOpsManager.OP_RECEIVE_SMS, resultReceiver); 691 return true; 692 } 693 694 /** 695 * Dispatch the intent with the specified permission, appOp, and result receiver, using 696 * this state machine's handler thread to run the result receiver. 697 * 698 * @param intent the intent to broadcast 699 * @param permission receivers are required to have this permission 700 * @param appOp app op that is being performed when dispatching to a receiver 701 */ 702 void dispatchIntent(Intent intent, String permission, int appOp, 703 BroadcastReceiver resultReceiver) { 704 intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT); 705 mContext.sendOrderedBroadcast(intent, permission, appOp, resultReceiver, 706 getHandler(), Activity.RESULT_OK, null, null); 707 } 708 709 /** 710 * Helper for {@link SmsBroadcastUndelivered} to delete an old message in the raw table. 711 */ 712 void deleteFromRawTable(String deleteWhere, String[] deleteWhereArgs) { 713 int rows = mResolver.delete(sRawUri, deleteWhere, deleteWhereArgs); 714 if (rows == 0) { 715 loge("No rows were deleted from raw table!"); 716 } else if (DBG) { 717 log("Deleted " + rows + " rows from raw table."); 718 } 719 } 720 721 /** 722 * Insert a message PDU into the raw table so we can acknowledge it immediately. 723 * If the device crashes before the broadcast to listeners completes, it will be delivered 724 * from the raw table on the next device boot. For single-part messages, the deleteWhere 725 * and deleteWhereArgs fields of the tracker will be set to delete the correct row after 726 * the ordered broadcast completes. 727 * 728 * @param tracker the tracker to add to the raw table 729 * @return true on success; false on failure to write to database 730 */ 731 private int addTrackerToRawTable(InboundSmsTracker tracker) { 732 if (tracker.getMessageCount() != 1) { 733 // check for duplicate message segments 734 Cursor cursor = null; 735 try { 736 // sequence numbers are 1-based except for CDMA WAP, which is 0-based 737 int sequence = tracker.getSequenceNumber(); 738 739 // convert to strings for query 740 String address = tracker.getAddress(); 741 String refNumber = Integer.toString(tracker.getReferenceNumber()); 742 String count = Integer.toString(tracker.getMessageCount()); 743 744 String seqNumber = Integer.toString(sequence); 745 746 // set the delete selection args for multi-part message 747 String[] deleteWhereArgs = {address, refNumber, count}; 748 tracker.setDeleteWhere(SELECT_BY_REFERENCE, deleteWhereArgs); 749 750 // Check for duplicate message segments 751 cursor = mResolver.query(sRawUri, PDU_PROJECTION, 752 "address=? AND reference_number=? AND count=? AND sequence=?", 753 new String[] {address, refNumber, count, seqNumber}, null); 754 755 // moveToNext() returns false if no duplicates were found 756 if (cursor.moveToNext()) { 757 loge("Discarding duplicate message segment, refNumber=" + refNumber 758 + " seqNumber=" + seqNumber); 759 String oldPduString = cursor.getString(PDU_COLUMN); 760 byte[] pdu = tracker.getPdu(); 761 byte[] oldPdu = HexDump.hexStringToByteArray(oldPduString); 762 if (!Arrays.equals(oldPdu, tracker.getPdu())) { 763 loge("Warning: dup message segment PDU of length " + pdu.length 764 + " is different from existing PDU of length " + oldPdu.length); 765 } 766 return Intents.RESULT_SMS_DUPLICATED; // reject message 767 } 768 cursor.close(); 769 } catch (SQLException e) { 770 loge("Can't access multipart SMS database", e); 771 return Intents.RESULT_SMS_GENERIC_ERROR; // reject message 772 } finally { 773 if (cursor != null) { 774 cursor.close(); 775 } 776 } 777 } 778 779 ContentValues values = tracker.getContentValues(); 780 781 if (VDBG) log("adding content values to raw table: " + values.toString()); 782 Uri newUri = mResolver.insert(sRawUri, values); 783 if (DBG) log("URI of new row -> " + newUri); 784 785 try { 786 long rowId = ContentUris.parseId(newUri); 787 if (tracker.getMessageCount() == 1) { 788 // set the delete selection args for single-part message 789 tracker.setDeleteWhere(SELECT_BY_ID, new String[]{Long.toString(rowId)}); 790 } 791 return Intents.RESULT_SMS_HANDLED; 792 } catch (Exception e) { 793 loge("error parsing URI for new row: " + newUri, e); 794 return Intents.RESULT_SMS_GENERIC_ERROR; 795 } 796 } 797 798 /** 799 * Returns whether the default message format for the current radio technology is 3GPP2. 800 * @return true if the radio technology uses 3GPP2 format by default, false for 3GPP format 801 */ 802 static boolean isCurrentFormat3gpp2() { 803 int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(); 804 return (PHONE_TYPE_CDMA == activePhone); 805 } 806 807 /** 808 * Handler for an {@link InboundSmsTracker} broadcast. Deletes PDUs from the raw table and 809 * logs the broadcast duration (as an error if the other receivers were especially slow). 810 */ 811 private final class SmsBroadcastReceiver extends BroadcastReceiver { 812 private final String mDeleteWhere; 813 private final String[] mDeleteWhereArgs; 814 private long mBroadcastTimeNano; 815 816 SmsBroadcastReceiver(InboundSmsTracker tracker) { 817 mDeleteWhere = tracker.getDeleteWhere(); 818 mDeleteWhereArgs = tracker.getDeleteWhereArgs(); 819 mBroadcastTimeNano = System.nanoTime(); 820 } 821 822 @Override 823 public void onReceive(Context context, Intent intent) { 824 String action = intent.getAction(); 825 if (action.equals(Intents.SMS_DELIVER_ACTION)) { 826 // Now dispatch the notification only intent 827 intent.setAction(Intents.SMS_RECEIVED_ACTION); 828 intent.setComponent(null); 829 dispatchIntent(intent, android.Manifest.permission.RECEIVE_SMS, 830 AppOpsManager.OP_RECEIVE_SMS, this); 831 } else if (action.equals(Intents.WAP_PUSH_DELIVER_ACTION)) { 832 // Now dispatch the notification only intent 833 intent.setAction(Intents.WAP_PUSH_RECEIVED_ACTION); 834 intent.setComponent(null); 835 dispatchIntent(intent, android.Manifest.permission.RECEIVE_SMS, 836 AppOpsManager.OP_RECEIVE_SMS, this); 837 } else { 838 // Now that the intents have been deleted we can clean up the PDU data. 839 if (!Intents.DATA_SMS_RECEIVED_ACTION.equals(action) 840 && !Intents.DATA_SMS_RECEIVED_ACTION.equals(action) 841 && !Intents.WAP_PUSH_RECEIVED_ACTION.equals(action)) { 842 loge("unexpected BroadcastReceiver action: " + action); 843 } 844 845 int rc = getResultCode(); 846 if ((rc != Activity.RESULT_OK) && (rc != Intents.RESULT_SMS_HANDLED)) { 847 loge("a broadcast receiver set the result code to " + rc 848 + ", deleting from raw table anyway!"); 849 } else if (DBG) { 850 log("successful broadcast, deleting from raw table."); 851 } 852 853 deleteFromRawTable(mDeleteWhere, mDeleteWhereArgs); 854 sendMessage(EVENT_BROADCAST_COMPLETE); 855 856 int durationMillis = (int) ((System.nanoTime() - mBroadcastTimeNano) / 1000000); 857 if (durationMillis >= 5000) { 858 loge("Slow ordered broadcast completion time: " + durationMillis + " ms"); 859 } else if (DBG) { 860 log("ordered broadcast completed in: " + durationMillis + " ms"); 861 } 862 } 863 } 864 } 865 866 /** 867 * Log with debug level. 868 * @param s the string to log 869 */ 870 @Override 871 protected void log(String s) { 872 Rlog.d(getName(), s); 873 } 874 875 /** 876 * Log with error level. 877 * @param s the string to log 878 */ 879 @Override 880 protected void loge(String s) { 881 Rlog.e(getName(), s); 882 } 883 884 /** 885 * Log with error level. 886 * @param s the string to log 887 * @param e is a Throwable which logs additional information. 888 */ 889 @Override 890 protected void loge(String s, Throwable e) { 891 Rlog.e(getName(), s, e); 892 } 893 } 894