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