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