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