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