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