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