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