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