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.app.Activity;
23 import android.app.ActivityManager;
24 import android.app.AppOpsManager;
25 import android.app.BroadcastOptions;
26 import android.app.Notification;
27 import android.app.NotificationManager;
28 import android.app.PendingIntent;
29 import android.compat.annotation.UnsupportedAppUsage;
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.PackageManager;
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.Bundle;
46 import android.os.IDeviceIdleController;
47 import android.os.Message;
48 import android.os.PowerManager;
49 import android.os.RemoteException;
50 import android.os.ServiceManager;
51 import android.os.UserHandle;
52 import android.os.UserManager;
53 import android.os.storage.StorageManager;
54 import android.provider.Telephony;
55 import android.provider.Telephony.Sms.Intents;
56 import android.service.carrier.CarrierMessagingService;
57 import android.telephony.SmsMessage;
58 import android.telephony.SubscriptionManager;
59 import android.telephony.TelephonyManager;
60 import android.text.TextUtils;
61 import android.util.LocalLog;
62 import android.util.Pair;
63 
64 import com.android.internal.R;
65 import com.android.internal.annotations.VisibleForTesting;
66 import com.android.internal.telephony.SmsConstants.MessageClass;
67 import com.android.internal.telephony.metrics.TelephonyMetrics;
68 import com.android.internal.telephony.util.NotificationChannelController;
69 import com.android.internal.telephony.util.TelephonyUtils;
70 import com.android.internal.util.HexDump;
71 import com.android.internal.util.State;
72 import com.android.internal.util.StateMachine;
73 import com.android.telephony.Rlog;
74 
75 import java.io.ByteArrayOutputStream;
76 import java.io.FileDescriptor;
77 import java.io.PrintWriter;
78 import java.util.Arrays;
79 import java.util.HashMap;
80 import java.util.List;
81 import java.util.Map;
82 
83 /**
84  * This class broadcasts incoming SMS messages to interested apps after storing them in
85  * the SmsProvider "raw" table and ACKing them to the SMSC. After each message has been
86  * broadcast, its parts are removed from the raw table. If the device crashes after ACKing
87  * but before the broadcast completes, the pending messages will be rebroadcast on the next boot.
88  *
89  * <p>The state machine starts in {@link IdleState} state. When the {@link SMSDispatcher} receives a
90  * new SMS from the radio, it calls {@link #dispatchNormalMessage},
91  * which sends a message to the state machine, causing the wakelock to be acquired in
92  * {@link #haltedProcessMessage}, which transitions to {@link DeliveringState} state, where the message
93  * is saved to the raw table, then acknowledged via the {@link SMSDispatcher} which called us.
94  *
95  * <p>After saving the SMS, if the message is complete (either single-part or the final segment
96  * of a multi-part SMS), we broadcast the completed PDUs as an ordered broadcast, then transition to
97  * {@link WaitingState} state to wait for the broadcast to complete. When the local
98  * {@link BroadcastReceiver} is called with the result, it sends {@link #EVENT_BROADCAST_COMPLETE}
99  * to the state machine, causing us to either broadcast the next pending message (if one has
100  * arrived while waiting for the broadcast to complete), or to transition back to the halted state
101  * after all messages are processed. Then the wakelock is released and we wait for the next SMS.
102  */
103 public abstract class InboundSmsHandler extends StateMachine {
104     protected static final boolean DBG = true;
105     protected static final boolean VDBG = false; // STOPSHIP if true, logs user data
106 
107     /** Query projection for checking for duplicate message segments. */
108     private static final String[] PDU_DELETED_FLAG_PROJECTION = {
109             "pdu",
110             "deleted"
111     };
112 
113     /** Mapping from DB COLUMN to PDU_SEQUENCE_PORT PROJECTION index */
114     private static final Map<Integer, Integer> PDU_DELETED_FLAG_PROJECTION_INDEX_MAPPING =
115             new HashMap<Integer, Integer>() {{
116             put(PDU_COLUMN, 0);
117             put(DELETED_FLAG_COLUMN, 1);
118             }};
119 
120     /** Query projection for combining concatenated message segments. */
121     private static final String[] PDU_SEQUENCE_PORT_PROJECTION = {
122             "pdu",
123             "sequence",
124             "destination_port",
125             "display_originating_addr",
126             "date"
127     };
128 
129     /** Mapping from DB COLUMN to PDU_SEQUENCE_PORT PROJECTION index */
130     private static final Map<Integer, Integer> PDU_SEQUENCE_PORT_PROJECTION_INDEX_MAPPING =
131             new HashMap<Integer, Integer>() {{
132                 put(PDU_COLUMN, 0);
133                 put(SEQUENCE_COLUMN, 1);
134                 put(DESTINATION_PORT_COLUMN, 2);
135                 put(DISPLAY_ADDRESS_COLUMN, 3);
136                 put(DATE_COLUMN, 4);
137     }};
138 
139     public static final int PDU_COLUMN = 0;
140     public static final int SEQUENCE_COLUMN = 1;
141     public static final int DESTINATION_PORT_COLUMN = 2;
142     public static final int DATE_COLUMN = 3;
143     public static final int REFERENCE_NUMBER_COLUMN = 4;
144     public static final int COUNT_COLUMN = 5;
145     public static final int ADDRESS_COLUMN = 6;
146     public static final int ID_COLUMN = 7;
147     public static final int MESSAGE_BODY_COLUMN = 8;
148     public static final int DISPLAY_ADDRESS_COLUMN = 9;
149     public static final int DELETED_FLAG_COLUMN = 10;
150     public static final int SUBID_COLUMN = 11;
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     private UserManager mUserManager;
232 
233     protected TelephonyMetrics mMetrics = TelephonyMetrics.getInstance();
234 
235     private LocalLog mLocalLog = new LocalLog(64);
236 
237     @UnsupportedAppUsage
238     IDeviceIdleController mDeviceIdleController;
239 
240     protected CellBroadcastServiceManager mCellBroadcastServiceManager;
241 
242     // Delete permanently from raw table
243     private final int DELETE_PERMANENTLY = 1;
244     // Only mark deleted, but keep in db for message de-duping
245     private final int MARK_DELETED = 2;
246 
247     private static String ACTION_OPEN_SMS_APP =
248         "com.android.internal.telephony.OPEN_DEFAULT_SMS_APP";
249 
250     /** Timeout for releasing wakelock */
251     private int mWakeLockTimeout;
252 
253     /** Indicates if last SMS was injected. This is used to recognize SMS received over IMS from
254         others in order to update metrics. */
255     private boolean mLastSmsWasInjected = false;
256 
257     /**
258      * Create a new SMS broadcast helper.
259      * @param name the class name for logging
260      * @param context the context of the phone app
261      * @param storageMonitor the SmsStorageMonitor to check for storage availability
262      */
InboundSmsHandler(String name, Context context, SmsStorageMonitor storageMonitor, Phone phone)263     protected InboundSmsHandler(String name, Context context, SmsStorageMonitor storageMonitor,
264             Phone phone) {
265         super(name);
266 
267         mContext = context;
268         mStorageMonitor = storageMonitor;
269         mPhone = phone;
270         mResolver = context.getContentResolver();
271         mWapPush = new WapPushOverSms(context);
272 
273         boolean smsCapable = mContext.getResources().getBoolean(
274                 com.android.internal.R.bool.config_sms_capable);
275         mSmsReceiveDisabled = !TelephonyManager.from(mContext).getSmsReceiveCapableForPhone(
276                 mPhone.getPhoneId(), smsCapable);
277 
278         PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
279         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, name);
280         mWakeLock.acquire();    // wake lock released after we enter idle state
281         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
282         mDeviceIdleController = TelephonyComponentFactory.getInstance()
283                 .inject(IDeviceIdleController.class.getName()).getIDeviceIdleController();
284         mCellBroadcastServiceManager = new CellBroadcastServiceManager(context, phone);
285 
286         addState(mDefaultState);
287         addState(mStartupState, mDefaultState);
288         addState(mIdleState, mDefaultState);
289         addState(mDeliveringState, mDefaultState);
290             addState(mWaitingState, mDeliveringState);
291 
292         setInitialState(mStartupState);
293         if (DBG) log("created InboundSmsHandler");
294     }
295 
296     /**
297      * Tell the state machine to quit after processing all messages.
298      */
dispose()299     public void dispose() {
300         quit();
301     }
302 
303     /**
304      * Dispose of the WAP push object and release the wakelock.
305      */
306     @Override
onQuitting()307     protected void onQuitting() {
308         mWapPush.dispose();
309         mCellBroadcastServiceManager.disable();
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 (TelephonyUtils.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             mContext.sendBroadcast(intent, android.Manifest.permission.RECEIVE_SMS);
721         }
722         acknowledgeLastIncomingSms(success, result, response);
723     }
724 
725     /**
726      * Return true if this handler is for 3GPP2 messages; false for 3GPP format.
727      * @return true for the 3GPP2 handler; false for the 3GPP handler
728      */
is3gpp2()729     protected abstract boolean is3gpp2();
730 
731     /**
732      * Dispatch a normal incoming SMS. This is called from {@link #dispatchMessageRadioSpecific}
733      * if no format-specific handling was required. Saves the PDU to the SMS provider raw table,
734      * creates an {@link InboundSmsTracker}, then sends it to the state machine as an
735      * {@link #EVENT_BROADCAST_SMS}. Returns {@link Intents#RESULT_SMS_HANDLED} or an error value.
736      *
737      * @param sms the message to dispatch
738      * @return {@link Intents#RESULT_SMS_HANDLED} if the message was accepted, or an error status
739      */
740     @UnsupportedAppUsage
dispatchNormalMessage(SmsMessageBase sms)741     protected int dispatchNormalMessage(SmsMessageBase sms) {
742         SmsHeader smsHeader = sms.getUserDataHeader();
743         InboundSmsTracker tracker;
744 
745         if ((smsHeader == null) || (smsHeader.concatRef == null)) {
746             // Message is not concatenated.
747             int destPort = -1;
748             if (smsHeader != null && smsHeader.portAddrs != null) {
749                 // The message was sent to a port.
750                 destPort = smsHeader.portAddrs.destPort;
751                 if (DBG) log("destination port: " + destPort);
752             }
753             tracker = TelephonyComponentFactory.getInstance()
754                     .inject(InboundSmsTracker.class.getName())
755                     .makeInboundSmsTracker(sms.getPdu(),
756                     sms.getTimestampMillis(), destPort, is3gpp2(), false,
757                     sms.getOriginatingAddress(), sms.getDisplayOriginatingAddress(),
758                     sms.getMessageBody(), sms.getMessageClass() == MessageClass.CLASS_0,
759                             mPhone.getSubId());
760         } else {
761             // Create a tracker for this message segment.
762             SmsHeader.ConcatRef concatRef = smsHeader.concatRef;
763             SmsHeader.PortAddrs portAddrs = smsHeader.portAddrs;
764             int destPort = (portAddrs != null ? portAddrs.destPort : -1);
765             tracker = TelephonyComponentFactory.getInstance()
766                     .inject(InboundSmsTracker.class.getName())
767                     .makeInboundSmsTracker(sms.getPdu(),
768                     sms.getTimestampMillis(), destPort, is3gpp2(), sms.getOriginatingAddress(),
769                     sms.getDisplayOriginatingAddress(), concatRef.refNumber, concatRef.seqNumber,
770                     concatRef.msgCount, false, sms.getMessageBody(),
771                     sms.getMessageClass() == MessageClass.CLASS_0, mPhone.getSubId());
772         }
773 
774         if (VDBG) log("created tracker: " + tracker);
775 
776         // de-duping is done only for text messages
777         // destPort = -1 indicates text messages, otherwise it's a data sms
778         return addTrackerToRawTableAndSendMessage(tracker,
779                 tracker.getDestPort() == -1 /* de-dup if text message */);
780     }
781 
782     /**
783      * Helper to add the tracker to the raw table and then send a message to broadcast it, if
784      * successful. Returns the SMS intent status to return to the SMSC.
785      * @param tracker the tracker to save to the raw table and then deliver
786      * @return {@link Intents#RESULT_SMS_HANDLED} or {@link Intents#RESULT_SMS_GENERIC_ERROR}
787      * or {@link Intents#RESULT_SMS_DUPLICATED}
788      */
addTrackerToRawTableAndSendMessage(InboundSmsTracker tracker, boolean deDup)789     protected int addTrackerToRawTableAndSendMessage(InboundSmsTracker tracker, boolean deDup) {
790         switch(addTrackerToRawTable(tracker, deDup)) {
791         case Intents.RESULT_SMS_HANDLED:
792             sendMessage(EVENT_BROADCAST_SMS, tracker);
793             return Intents.RESULT_SMS_HANDLED;
794 
795         case Intents.RESULT_SMS_DUPLICATED:
796             return Intents.RESULT_SMS_HANDLED;
797 
798         case Intents.RESULT_SMS_GENERIC_ERROR:
799         default:
800             return Intents.RESULT_SMS_GENERIC_ERROR;
801         }
802     }
803 
804     /**
805      * Process the inbound SMS segment. If the message is complete, send it as an ordered
806      * broadcast to interested receivers and return true. If the message is a segment of an
807      * incomplete multi-part SMS, return false.
808      * @param tracker the tracker containing the message segment to process
809      * @return true if an ordered broadcast was sent; false if waiting for more message segments
810      */
811     @UnsupportedAppUsage
processMessagePart(InboundSmsTracker tracker)812     private boolean processMessagePart(InboundSmsTracker tracker) {
813         int messageCount = tracker.getMessageCount();
814         byte[][] pdus;
815         long[] timestamps;
816         int destPort = tracker.getDestPort();
817         boolean block = false;
818         String address = tracker.getAddress();
819 
820         // Do not process when the message count is invalid.
821         if (messageCount <= 0) {
822             loge("processMessagePart: returning false due to invalid message count "
823                     + messageCount);
824             return false;
825         }
826 
827         if (messageCount == 1) {
828             // single-part message
829             pdus = new byte[][]{tracker.getPdu()};
830             timestamps = new long[]{tracker.getTimestamp()};
831             block = BlockChecker.isBlocked(mContext, tracker.getDisplayAddress(), null);
832         } else {
833             // multi-part message
834             Cursor cursor = null;
835             try {
836                 // used by several query selection arguments
837                 String refNumber = Integer.toString(tracker.getReferenceNumber());
838                 String count = Integer.toString(tracker.getMessageCount());
839 
840                 // query for all segments and broadcast message if we have all the parts
841                 String[] whereArgs = {address, refNumber, count};
842                 cursor = mResolver.query(sRawUri, PDU_SEQUENCE_PORT_PROJECTION,
843                         tracker.getQueryForSegments(), whereArgs, null);
844 
845                 int cursorCount = cursor.getCount();
846                 if (cursorCount < messageCount) {
847                     // Wait for the other message parts to arrive. It's also possible for the last
848                     // segment to arrive before processing the EVENT_BROADCAST_SMS for one of the
849                     // earlier segments. In that case, the broadcast will be sent as soon as all
850                     // segments are in the table, and any later EVENT_BROADCAST_SMS messages will
851                     // get a row count of 0 and return.
852                     return false;
853                 }
854 
855                 // All the parts are in place, deal with them
856                 pdus = new byte[messageCount][];
857                 timestamps = new long[messageCount];
858                 while (cursor.moveToNext()) {
859                     // subtract offset to convert sequence to 0-based array index
860                     int index = cursor.getInt(PDU_SEQUENCE_PORT_PROJECTION_INDEX_MAPPING
861                             .get(SEQUENCE_COLUMN)) - tracker.getIndexOffset();
862 
863                     // The invalid PDUs can be received and stored in the raw table. The range
864                     // check ensures the process not crash even if the seqNumber in the
865                     // UserDataHeader is invalid.
866                     if (index >= pdus.length || index < 0) {
867                         loge(String.format(
868                                 "processMessagePart: invalid seqNumber = %d, messageCount = %d",
869                                 index + tracker.getIndexOffset(),
870                                 messageCount));
871                         continue;
872                     }
873 
874                     pdus[index] = HexDump.hexStringToByteArray(cursor.getString(
875                             PDU_SEQUENCE_PORT_PROJECTION_INDEX_MAPPING.get(PDU_COLUMN)));
876 
877                     // Read the destination port from the first segment (needed for CDMA WAP PDU).
878                     // It's not a bad idea to prefer the port from the first segment in other cases.
879                     if (index == 0 && !cursor.isNull(PDU_SEQUENCE_PORT_PROJECTION_INDEX_MAPPING
880                             .get(DESTINATION_PORT_COLUMN))) {
881                         int port = cursor.getInt(PDU_SEQUENCE_PORT_PROJECTION_INDEX_MAPPING
882                                 .get(DESTINATION_PORT_COLUMN));
883                         // strip format flags and convert to real port number, or -1
884                         port = InboundSmsTracker.getRealDestPort(port);
885                         if (port != -1) {
886                             destPort = port;
887                         }
888                     }
889 
890                     timestamps[index] = cursor.getLong(
891                             PDU_SEQUENCE_PORT_PROJECTION_INDEX_MAPPING.get(DATE_COLUMN));
892 
893                     // check if display address should be blocked or not
894                     if (!block) {
895                         // Depending on the nature of the gateway, the display origination address
896                         // is either derived from the content of the SMS TP-OA field, or the TP-OA
897                         // field contains a generic gateway address and the from address is added
898                         // at the beginning in the message body. In that case only the first SMS
899                         // (part of Multi-SMS) comes with the display originating address which
900                         // could be used for block checking purpose.
901                         block = BlockChecker.isBlocked(mContext,
902                                 cursor.getString(PDU_SEQUENCE_PORT_PROJECTION_INDEX_MAPPING
903                                         .get(DISPLAY_ADDRESS_COLUMN)), null);
904                     }
905                 }
906             } catch (SQLException e) {
907                 loge("Can't access multipart SMS database", e);
908                 return false;
909             } finally {
910                 if (cursor != null) {
911                     cursor.close();
912                 }
913             }
914         }
915 
916         final boolean isWapPush = (destPort == SmsHeader.PORT_WAP_PUSH);
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.getFormat();
921         if (!isWapPush) {
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         ByteArrayOutputStream output = new ByteArrayOutputStream();
937         if (isWapPush) {
938             for (byte[] pdu : pdus) {
939                 // 3GPP needs to extract the User Data from the PDU; 3GPP2 has already done this
940                 if (format == SmsConstants.FORMAT_3GPP) {
941                     SmsMessage msg = SmsMessage.createFromPdu(pdu, SmsConstants.FORMAT_3GPP);
942                     if (msg != null) {
943                         pdu = msg.getUserData();
944                     } else {
945                         loge("processMessagePart: SmsMessage.createFromPdu returned null");
946                         mMetrics.writeIncomingWapPush(mPhone.getPhoneId(), mLastSmsWasInjected,
947                                 SmsConstants.FORMAT_3GPP, timestamps, false);
948                         return false;
949                     }
950                 }
951                 output.write(pdu, 0, pdu.length);
952             }
953         }
954 
955         SmsBroadcastReceiver resultReceiver = new SmsBroadcastReceiver(tracker);
956 
957         if (!mUserManager.isUserUnlocked()) {
958             return processMessagePartWithUserLocked(
959                     tracker,
960                     (isWapPush ? new byte[][] {output.toByteArray()} : pdus),
961                     destPort,
962                     resultReceiver);
963         }
964 
965         if (isWapPush) {
966             int result = mWapPush.dispatchWapPdu(output.toByteArray(), resultReceiver,
967                     this, address, tracker.getSubId());
968             if (DBG) log("dispatchWapPdu() returned " + result);
969             // Add result of WAP-PUSH into metrics. RESULT_SMS_HANDLED indicates that the WAP-PUSH
970             // needs to be ignored, so treating it as a success case.
971             if (result == Activity.RESULT_OK || result == Intents.RESULT_SMS_HANDLED) {
972                 mMetrics.writeIncomingWapPush(mPhone.getPhoneId(), mLastSmsWasInjected,
973                         format, timestamps, true);
974             } else {
975                 mMetrics.writeIncomingWapPush(mPhone.getPhoneId(), mLastSmsWasInjected,
976                         format, timestamps, false);
977             }
978             // result is Activity.RESULT_OK if an ordered broadcast was sent
979             if (result == Activity.RESULT_OK) {
980                 return true;
981             } else {
982                 deleteFromRawTable(tracker.getDeleteWhere(), tracker.getDeleteWhereArgs(),
983                         MARK_DELETED);
984                 return false;
985             }
986         }
987 
988         if (block) {
989             deleteFromRawTable(tracker.getDeleteWhere(), tracker.getDeleteWhereArgs(),
990                     DELETE_PERMANENTLY);
991             return false;
992         }
993 
994         boolean filterInvoked = filterSms(
995             pdus, destPort, tracker, resultReceiver, true /* userUnlocked */);
996 
997         if (!filterInvoked) {
998             dispatchSmsDeliveryIntent(pdus, format, destPort, resultReceiver,
999                     tracker.isClass0(), tracker.getSubId());
1000         }
1001 
1002         return true;
1003     }
1004 
1005     /**
1006      * Processes the message part while the credential-encrypted storage is still locked.
1007      *
1008      * <p>If the message is a regular MMS, show a new message notification. If the message is a
1009      * SMS, ask the carrier app to filter it and show the new message notification if the carrier
1010      * app asks to keep the message.
1011      *
1012      * @return true if an ordered broadcast was sent to the carrier app; false otherwise.
1013      */
processMessagePartWithUserLocked(InboundSmsTracker tracker, byte[][] pdus, int destPort, SmsBroadcastReceiver resultReceiver)1014     private boolean processMessagePartWithUserLocked(InboundSmsTracker tracker,
1015             byte[][] pdus, int destPort, SmsBroadcastReceiver resultReceiver) {
1016         log("Credential-encrypted storage not available. Port: " + destPort);
1017         if (destPort == SmsHeader.PORT_WAP_PUSH && mWapPush.isWapPushForMms(pdus[0], this)) {
1018             showNewMessageNotification();
1019             return false;
1020         }
1021         if (destPort == -1) {
1022             // This is a regular SMS - hand it to the carrier or system app for filtering.
1023             boolean filterInvoked = filterSms(
1024                 pdus, destPort, tracker, resultReceiver, false /* userUnlocked */);
1025             if (filterInvoked) {
1026                 // filter invoked, wait for it to return the result.
1027                 return true;
1028             } else {
1029                 // filter not invoked, show the notification and do nothing further.
1030                 showNewMessageNotification();
1031                 return false;
1032             }
1033         }
1034         return false;
1035     }
1036 
1037     @UnsupportedAppUsage
showNewMessageNotification()1038     private void showNewMessageNotification() {
1039         // Do not show the notification on non-FBE devices.
1040         if (!StorageManager.isFileEncryptedNativeOrEmulated()) {
1041             return;
1042         }
1043         log("Show new message notification.");
1044         PendingIntent intent = PendingIntent.getBroadcast(
1045             mContext,
1046             0,
1047             new Intent(ACTION_OPEN_SMS_APP),
1048             PendingIntent.FLAG_ONE_SHOT);
1049         Notification.Builder mBuilder = new Notification.Builder(mContext)
1050                 .setSmallIcon(com.android.internal.R.drawable.sym_action_chat)
1051                 .setAutoCancel(true)
1052                 .setVisibility(Notification.VISIBILITY_PUBLIC)
1053                 .setDefaults(Notification.DEFAULT_ALL)
1054                 .setContentTitle(mContext.getString(R.string.new_sms_notification_title))
1055                 .setContentText(mContext.getString(R.string.new_sms_notification_content))
1056                 .setContentIntent(intent)
1057                 .setChannelId(NotificationChannelController.CHANNEL_ID_SMS);
1058         NotificationManager mNotificationManager =
1059             (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
1060         mNotificationManager.notify(
1061                 NOTIFICATION_TAG, NOTIFICATION_ID_NEW_MESSAGE, mBuilder.build());
1062     }
1063 
cancelNewMessageNotification(Context context)1064     static void cancelNewMessageNotification(Context context) {
1065         NotificationManager mNotificationManager =
1066             (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
1067         mNotificationManager.cancel(InboundSmsHandler.NOTIFICATION_TAG,
1068             InboundSmsHandler.NOTIFICATION_ID_NEW_MESSAGE);
1069     }
1070 
1071     /**
1072      * Filters the SMS.
1073      *
1074      * <p>currently 3 filters exists: the carrier package, the system package, and the
1075      * VisualVoicemailSmsFilter.
1076      *
1077      * <p>The filtering process is:
1078      *
1079      * <p>If the carrier package exists, the SMS will be filtered with it first. If the carrier
1080      * package did not drop the SMS, then the VisualVoicemailSmsFilter will filter it in the
1081      * callback.
1082      *
1083      * <p>If the carrier package does not exists, we will let the VisualVoicemailSmsFilter filter
1084      * it. If the SMS passed the filter, then we will try to find the system package to do the
1085      * filtering.
1086      *
1087      * @return true if a filter is invoked and the SMS processing flow is diverted, false otherwise.
1088      */
filterSms(byte[][] pdus, int destPort, InboundSmsTracker tracker, SmsBroadcastReceiver resultReceiver, boolean userUnlocked)1089     private boolean filterSms(byte[][] pdus, int destPort,
1090         InboundSmsTracker tracker, SmsBroadcastReceiver resultReceiver, boolean userUnlocked) {
1091         CarrierServicesSmsFilterCallback filterCallback =
1092                 new CarrierServicesSmsFilterCallback(
1093                         pdus, destPort, tracker.getFormat(), resultReceiver, userUnlocked,
1094                         tracker.isClass0(), tracker.getSubId());
1095         CarrierServicesSmsFilter carrierServicesFilter = new CarrierServicesSmsFilter(
1096                 mContext, mPhone, pdus, destPort, tracker.getFormat(),
1097                 filterCallback, getName(), mLocalLog);
1098         if (carrierServicesFilter.filter()) {
1099             return true;
1100         }
1101 
1102         if (VisualVoicemailSmsFilter.filter(
1103                 mContext, pdus, tracker.getFormat(), destPort, tracker.getSubId())) {
1104             log("Visual voicemail SMS dropped");
1105             dropSms(resultReceiver);
1106             return true;
1107         }
1108 
1109         MissedIncomingCallSmsFilter missedIncomingCallSmsFilter =
1110                 new MissedIncomingCallSmsFilter(mPhone);
1111         if (missedIncomingCallSmsFilter.filter(pdus, tracker.getFormat())) {
1112             log("Missed incoming call SMS received.");
1113             dropSms(resultReceiver);
1114             return true;
1115         }
1116 
1117         return false;
1118     }
1119 
1120     /**
1121      * Dispatch the intent with the specified permission, appOp, and result receiver, using
1122      * this state machine's handler thread to run the result receiver.
1123      *
1124      * @param intent the intent to broadcast
1125      * @param permission receivers are required to have this permission
1126      * @param appOp app op that is being performed when dispatching to a receiver
1127      * @param user user to deliver the intent to
1128      */
1129     @UnsupportedAppUsage
dispatchIntent(Intent intent, String permission, String appOp, Bundle opts, BroadcastReceiver resultReceiver, UserHandle user, int subId)1130     public void dispatchIntent(Intent intent, String permission, String appOp,
1131             Bundle opts, BroadcastReceiver resultReceiver, UserHandle user, int subId) {
1132         intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT);
1133         final String action = intent.getAction();
1134         SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId());
1135 
1136         // override the subId value in the intent with the values from tracker as they can be
1137         // different, specifically if the message is coming from SmsBroadcastUndelivered
1138         if (SubscriptionManager.isValidSubscriptionId(subId)) {
1139             SubscriptionManager.putSubscriptionIdExtra(intent, subId);
1140         }
1141 
1142         if (user.equals(UserHandle.ALL)) {
1143             // Get a list of currently started users.
1144             int[] users = null;
1145             try {
1146                 users = ActivityManager.getService().getRunningUserIds();
1147             } catch (RemoteException re) {
1148             }
1149             if (users == null) {
1150                 users = new int[] {user.getIdentifier()};
1151             }
1152             // Deliver the broadcast only to those running users that are permitted
1153             // by user policy.
1154             for (int i = users.length - 1; i >= 0; i--) {
1155                 UserHandle targetUser = UserHandle.of(users[i]);
1156                 if (users[i] != UserHandle.SYSTEM.getIdentifier()) {
1157                     // Is the user not allowed to use SMS?
1158                     if (hasUserRestriction(UserManager.DISALLOW_SMS, targetUser)) {
1159                         continue;
1160                     }
1161                     // Skip unknown users and managed profiles as well
1162                     if (mUserManager.isManagedProfile(users[i])) {
1163                         continue;
1164                     }
1165                 }
1166                 // Only pass in the resultReceiver when the user SYSTEM is processed.
1167                 try {
1168                     mContext.createPackageContextAsUser(mContext.getPackageName(), 0, targetUser)
1169                             .sendOrderedBroadcast(intent, Activity.RESULT_OK, permission, appOp,
1170                                     users[i] == UserHandle.SYSTEM.getIdentifier()
1171                                             ? resultReceiver : null,
1172                                     getHandler(), null /* initialData */,
1173                                     null /* initialExtras */, opts);
1174                 } catch (PackageManager.NameNotFoundException ignored) {
1175                 }
1176             }
1177         } else {
1178             try {
1179                 mContext.createPackageContextAsUser(mContext.getPackageName(), 0, user)
1180                         .sendOrderedBroadcast(intent, Activity.RESULT_OK, permission, appOp,
1181                                 resultReceiver, getHandler(), null /* initialData */,
1182                                 null /* initialExtras */, opts);
1183             } catch (PackageManager.NameNotFoundException ignored) {
1184             }
1185         }
1186     }
1187 
hasUserRestriction(String restrictionKey, UserHandle userHandle)1188     private boolean hasUserRestriction(String restrictionKey, UserHandle userHandle) {
1189         final List<UserManager.EnforcingUser> sources = mUserManager
1190                 .getUserRestrictionSources(restrictionKey, userHandle);
1191         return (sources != null && !sources.isEmpty());
1192     }
1193 
1194     /**
1195      * Helper for {@link SmsBroadcastUndelivered} to delete an old message in the raw table.
1196      */
1197     @UnsupportedAppUsage
deleteFromRawTable(String deleteWhere, String[] deleteWhereArgs, int deleteType)1198     private void deleteFromRawTable(String deleteWhere, String[] deleteWhereArgs,
1199                                     int deleteType) {
1200         Uri uri = deleteType == DELETE_PERMANENTLY ? sRawUriPermanentDelete : sRawUri;
1201         int rows = mResolver.delete(uri, deleteWhere, deleteWhereArgs);
1202         if (rows == 0) {
1203             loge("No rows were deleted from raw table!");
1204         } else if (DBG) {
1205             log("Deleted " + rows + " rows from raw table.");
1206         }
1207     }
1208 
1209     @UnsupportedAppUsage
handleSmsWhitelisting(ComponentName target, boolean bgActivityStartAllowed)1210     private Bundle handleSmsWhitelisting(ComponentName target, boolean bgActivityStartAllowed) {
1211         String pkgName;
1212         String reason;
1213         if (target != null) {
1214             pkgName = target.getPackageName();
1215             reason = "sms-app";
1216         } else {
1217             pkgName = mContext.getPackageName();
1218             reason = "sms-broadcast";
1219         }
1220         BroadcastOptions bopts = null;
1221         Bundle bundle = null;
1222         if (bgActivityStartAllowed) {
1223             bopts = BroadcastOptions.makeBasic();
1224             bopts.setBackgroundActivityStartsAllowed(true);
1225             bundle = bopts.toBundle();
1226         }
1227         try {
1228             long duration = mDeviceIdleController.addPowerSaveTempWhitelistAppForSms(
1229                     pkgName, 0, reason);
1230             if (bopts == null) bopts = BroadcastOptions.makeBasic();
1231             bopts.setTemporaryAppWhitelistDuration(duration);
1232             bundle = bopts.toBundle();
1233         } catch (RemoteException e) {
1234         }
1235 
1236         return bundle;
1237     }
1238 
1239     /**
1240      * Creates and dispatches the intent to the default SMS app, appropriate port or via the {@link
1241      * AppSmsManager}.
1242      *
1243      * @param pdus message pdus
1244      * @param format the message format, typically "3gpp" or "3gpp2"
1245      * @param destPort the destination port
1246      * @param resultReceiver the receiver handling the delivery result
1247      */
dispatchSmsDeliveryIntent(byte[][] pdus, String format, int destPort, SmsBroadcastReceiver resultReceiver, boolean isClass0, int subId)1248     private void dispatchSmsDeliveryIntent(byte[][] pdus, String format, int destPort,
1249             SmsBroadcastReceiver resultReceiver, boolean isClass0, int subId) {
1250         Intent intent = new Intent();
1251         intent.putExtra("pdus", pdus);
1252         intent.putExtra("format", format);
1253 
1254         if (destPort == -1) {
1255             intent.setAction(Intents.SMS_DELIVER_ACTION);
1256             // Direct the intent to only the default SMS app. If we can't find a default SMS app
1257             // then sent it to all broadcast receivers.
1258             // We are deliberately delivering to the primary user's default SMS App.
1259             ComponentName componentName = SmsApplication.getDefaultSmsApplication(mContext, true);
1260             if (componentName != null) {
1261                 // Deliver SMS message only to this receiver.
1262                 intent.setComponent(componentName);
1263                 log("Delivering SMS to: " + componentName.getPackageName() +
1264                     " " + componentName.getClassName());
1265             } else {
1266                 intent.setComponent(null);
1267             }
1268 
1269             // Handle app specific sms messages.
1270             AppSmsManager appManager = mPhone.getAppSmsManager();
1271             if (appManager.handleSmsReceivedIntent(intent)) {
1272                 // The AppSmsManager handled this intent, we're done.
1273                 dropSms(resultReceiver);
1274                 return;
1275             }
1276         } else {
1277             intent.setAction(Intents.DATA_SMS_RECEIVED_ACTION);
1278             Uri uri = Uri.parse("sms://localhost:" + destPort);
1279             intent.setData(uri);
1280             intent.setComponent(null);
1281         }
1282 
1283         Bundle options = handleSmsWhitelisting(intent.getComponent(), isClass0);
1284         dispatchIntent(intent, android.Manifest.permission.RECEIVE_SMS,
1285                 AppOpsManager.OPSTR_RECEIVE_SMS, options, resultReceiver, UserHandle.SYSTEM, subId);
1286     }
1287 
1288     /**
1289      * Function to detect and handle duplicate messages. If the received message should replace an
1290      * existing message in the raw db, this function deletes the existing message. If an existing
1291      * message takes priority (for eg, existing message has already been broadcast), then this new
1292      * message should be dropped.
1293      * @return true if the message represented by the passed in tracker should be dropped,
1294      * false otherwise
1295      */
checkAndHandleDuplicate(InboundSmsTracker tracker)1296     private boolean checkAndHandleDuplicate(InboundSmsTracker tracker) throws SQLException {
1297         Pair<String, String[]> exactMatchQuery = tracker.getExactMatchDupDetectQuery();
1298 
1299         Cursor cursor = null;
1300         try {
1301             // Check for duplicate message segments
1302             cursor = mResolver.query(sRawUri, PDU_DELETED_FLAG_PROJECTION, exactMatchQuery.first,
1303                     exactMatchQuery.second, null);
1304 
1305             // moveToNext() returns false if no duplicates were found
1306             if (cursor != null && cursor.moveToNext()) {
1307                 if (cursor.getCount() != 1) {
1308                     loge("Exact match query returned " + cursor.getCount() + " rows");
1309                 }
1310 
1311                 // if the exact matching row is marked deleted, that means this message has already
1312                 // been received and processed, and can be discarded as dup
1313                 if (cursor.getInt(
1314                         PDU_DELETED_FLAG_PROJECTION_INDEX_MAPPING.get(DELETED_FLAG_COLUMN)) == 1) {
1315                     loge("Discarding duplicate message segment: " + tracker);
1316                     logDupPduMismatch(cursor, tracker);
1317                     return true;   // reject message
1318                 } else {
1319                     // exact match duplicate is not marked deleted. If it is a multi-part segment,
1320                     // the code below for inexact match will take care of it. If it is a single
1321                     // part message, handle it here.
1322                     if (tracker.getMessageCount() == 1) {
1323                         // delete the old message segment permanently
1324                         deleteFromRawTable(exactMatchQuery.first, exactMatchQuery.second,
1325                                 DELETE_PERMANENTLY);
1326                         loge("Replacing duplicate message: " + tracker);
1327                         logDupPduMismatch(cursor, tracker);
1328                     }
1329                 }
1330             }
1331         } finally {
1332             if (cursor != null) {
1333                 cursor.close();
1334             }
1335         }
1336 
1337         // The code above does an exact match. Multi-part message segments need an additional check
1338         // on top of that: if there is a message segment that conflicts this new one (may not be an
1339         // exact match), replace the old message segment with this one.
1340         if (tracker.getMessageCount() > 1) {
1341             Pair<String, String[]> inexactMatchQuery = tracker.getInexactMatchDupDetectQuery();
1342             cursor = null;
1343             try {
1344                 // Check for duplicate message segments
1345                 cursor = mResolver.query(sRawUri, PDU_DELETED_FLAG_PROJECTION,
1346                         inexactMatchQuery.first, inexactMatchQuery.second, null);
1347 
1348                 // moveToNext() returns false if no duplicates were found
1349                 if (cursor != null && cursor.moveToNext()) {
1350                     if (cursor.getCount() != 1) {
1351                         loge("Inexact match query returned " + cursor.getCount() + " rows");
1352                     }
1353                     // delete the old message segment permanently
1354                     deleteFromRawTable(inexactMatchQuery.first, inexactMatchQuery.second,
1355                             DELETE_PERMANENTLY);
1356                     loge("Replacing duplicate message segment: " + tracker);
1357                     logDupPduMismatch(cursor, tracker);
1358                 }
1359             } finally {
1360                 if (cursor != null) {
1361                     cursor.close();
1362                 }
1363             }
1364         }
1365 
1366         return false;
1367     }
1368 
logDupPduMismatch(Cursor cursor, InboundSmsTracker tracker)1369     private void logDupPduMismatch(Cursor cursor, InboundSmsTracker tracker) {
1370         String oldPduString = cursor.getString(
1371                 PDU_DELETED_FLAG_PROJECTION_INDEX_MAPPING.get(PDU_COLUMN));
1372         byte[] pdu = tracker.getPdu();
1373         byte[] oldPdu = HexDump.hexStringToByteArray(oldPduString);
1374         if (!Arrays.equals(oldPdu, tracker.getPdu())) {
1375             loge("Warning: dup message PDU of length " + pdu.length
1376                     + " is different from existing PDU of length " + oldPdu.length);
1377         }
1378     }
1379 
1380     /**
1381      * Insert a message PDU into the raw table so we can acknowledge it immediately.
1382      * If the device crashes before the broadcast to listeners completes, it will be delivered
1383      * from the raw table on the next device boot. For single-part messages, the deleteWhere
1384      * and deleteWhereArgs fields of the tracker will be set to delete the correct row after
1385      * the ordered broadcast completes.
1386      *
1387      * @param tracker the tracker to add to the raw table
1388      * @return true on success; false on failure to write to database
1389      */
addTrackerToRawTable(InboundSmsTracker tracker, boolean deDup)1390     private int addTrackerToRawTable(InboundSmsTracker tracker, boolean deDup) {
1391         if (deDup) {
1392             try {
1393                 if (checkAndHandleDuplicate(tracker)) {
1394                     return Intents.RESULT_SMS_DUPLICATED;   // reject message
1395                 }
1396             } catch (SQLException e) {
1397                 loge("Can't access SMS database", e);
1398                 return Intents.RESULT_SMS_GENERIC_ERROR;    // reject message
1399             }
1400         } else {
1401             logd("Skipped message de-duping logic");
1402         }
1403 
1404         String address = tracker.getAddress();
1405         String refNumber = Integer.toString(tracker.getReferenceNumber());
1406         String count = Integer.toString(tracker.getMessageCount());
1407         ContentValues values = tracker.getContentValues();
1408 
1409         if (VDBG) log("adding content values to raw table: " + values.toString());
1410         Uri newUri = mResolver.insert(sRawUri, values);
1411         if (DBG) log("URI of new row -> " + newUri);
1412 
1413         try {
1414             long rowId = ContentUris.parseId(newUri);
1415             if (tracker.getMessageCount() == 1) {
1416                 // set the delete selection args for single-part message
1417                 tracker.setDeleteWhere(SELECT_BY_ID, new String[]{Long.toString(rowId)});
1418             } else {
1419                 // set the delete selection args for multi-part message
1420                 String[] deleteWhereArgs = {address, refNumber, count};
1421                 tracker.setDeleteWhere(tracker.getQueryForSegments(), deleteWhereArgs);
1422             }
1423             return Intents.RESULT_SMS_HANDLED;
1424         } catch (Exception e) {
1425             loge("error parsing URI for new row: " + newUri, e);
1426             return Intents.RESULT_SMS_GENERIC_ERROR;
1427         }
1428     }
1429 
1430     /**
1431      * Returns whether the default message format for the current radio technology is 3GPP2.
1432      * @return true if the radio technology uses 3GPP2 format by default, false for 3GPP format
1433      */
isCurrentFormat3gpp2()1434     static boolean isCurrentFormat3gpp2() {
1435         int activePhone = TelephonyManager.getDefault().getCurrentPhoneType();
1436         return (PHONE_TYPE_CDMA == activePhone);
1437     }
1438 
1439     /**
1440      * Handler for an {@link InboundSmsTracker} broadcast. Deletes PDUs from the raw table and
1441      * logs the broadcast duration (as an error if the other receivers were especially slow).
1442      */
1443     private final class SmsBroadcastReceiver extends BroadcastReceiver {
1444         @UnsupportedAppUsage
1445         private final String mDeleteWhere;
1446         @UnsupportedAppUsage
1447         private final String[] mDeleteWhereArgs;
1448         private long mBroadcastTimeNano;
1449 
SmsBroadcastReceiver(InboundSmsTracker tracker)1450         SmsBroadcastReceiver(InboundSmsTracker tracker) {
1451             mDeleteWhere = tracker.getDeleteWhere();
1452             mDeleteWhereArgs = tracker.getDeleteWhereArgs();
1453             mBroadcastTimeNano = System.nanoTime();
1454         }
1455 
1456         @Override
onReceive(Context context, Intent intent)1457         public void onReceive(Context context, Intent intent) {
1458             String action = intent.getAction();
1459             int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
1460                     SubscriptionManager.INVALID_SUBSCRIPTION_ID);
1461             if (action.equals(Intents.SMS_DELIVER_ACTION)) {
1462                 // Now dispatch the notification only intent
1463                 intent.setAction(Intents.SMS_RECEIVED_ACTION);
1464                 // Allow registered broadcast receivers to get this intent even
1465                 // when they are in the background.
1466                 intent.setComponent(null);
1467                 // All running users will be notified of the received sms.
1468                 Bundle options = handleSmsWhitelisting(null, false /* bgActivityStartAllowed */);
1469 
1470                 dispatchIntent(intent, android.Manifest.permission.RECEIVE_SMS,
1471                         AppOpsManager.OPSTR_RECEIVE_SMS,
1472                         options, this, UserHandle.ALL, subId);
1473             } else if (action.equals(Intents.WAP_PUSH_DELIVER_ACTION)) {
1474                 // Now dispatch the notification only intent
1475                 intent.setAction(Intents.WAP_PUSH_RECEIVED_ACTION);
1476                 intent.setComponent(null);
1477                 // Only the primary user will receive notification of incoming mms.
1478                 // That app will do the actual downloading of the mms.
1479                 Bundle options = null;
1480                 try {
1481                     long duration = mDeviceIdleController.addPowerSaveTempWhitelistAppForMms(
1482                             mContext.getPackageName(), 0, "mms-broadcast");
1483                     BroadcastOptions bopts = BroadcastOptions.makeBasic();
1484                     bopts.setTemporaryAppWhitelistDuration(duration);
1485                     options = bopts.toBundle();
1486                 } catch (RemoteException e) {
1487                 }
1488 
1489                 String mimeType = intent.getType();
1490                 dispatchIntent(intent, WapPushOverSms.getPermissionForType(mimeType),
1491                         WapPushOverSms.getAppOpsStringPermissionForIntent(mimeType), options, this,
1492                         UserHandle.SYSTEM, subId);
1493             } else {
1494                 // Now that the intents have been deleted we can clean up the PDU data.
1495                 if (!Intents.DATA_SMS_RECEIVED_ACTION.equals(action)
1496                         && !Intents.SMS_RECEIVED_ACTION.equals(action)
1497                         && !Intents.DATA_SMS_RECEIVED_ACTION.equals(action)
1498                         && !Intents.WAP_PUSH_RECEIVED_ACTION.equals(action)) {
1499                     loge("unexpected BroadcastReceiver action: " + action);
1500                 }
1501 
1502                 int rc = getResultCode();
1503                 if ((rc != Activity.RESULT_OK) && (rc != Intents.RESULT_SMS_HANDLED)) {
1504                     loge("a broadcast receiver set the result code to " + rc
1505                             + ", deleting from raw table anyway!");
1506                 } else if (DBG) {
1507                     log("successful broadcast, deleting from raw table.");
1508                 }
1509 
1510                 deleteFromRawTable(mDeleteWhere, mDeleteWhereArgs, MARK_DELETED);
1511                 sendMessage(EVENT_BROADCAST_COMPLETE);
1512 
1513                 int durationMillis = (int) ((System.nanoTime() - mBroadcastTimeNano) / 1000000);
1514                 if (durationMillis >= 5000) {
1515                     loge("Slow ordered broadcast completion time: " + durationMillis + " ms");
1516                 } else if (DBG) {
1517                     log("ordered broadcast completed in: " + durationMillis + " ms");
1518                 }
1519             }
1520         }
1521     }
1522 
1523     /**
1524      * Callback that handles filtering results by carrier services.
1525      */
1526     private final class CarrierServicesSmsFilterCallback implements
1527             CarrierServicesSmsFilter.CarrierServicesSmsFilterCallbackInterface {
1528         private final byte[][] mPdus;
1529         private final int mDestPort;
1530         private final String mSmsFormat;
1531         private final SmsBroadcastReceiver mSmsBroadcastReceiver;
1532         private final boolean mUserUnlocked;
1533         private final boolean mIsClass0;
1534         private final int mSubId;
1535 
CarrierServicesSmsFilterCallback(byte[][] pdus, int destPort, String smsFormat, SmsBroadcastReceiver smsBroadcastReceiver, boolean userUnlocked, boolean isClass0, int subId)1536         CarrierServicesSmsFilterCallback(byte[][] pdus, int destPort, String smsFormat,
1537                 SmsBroadcastReceiver smsBroadcastReceiver,  boolean userUnlocked,
1538                 boolean isClass0, int subId) {
1539             mPdus = pdus;
1540             mDestPort = destPort;
1541             mSmsFormat = smsFormat;
1542             mSmsBroadcastReceiver = smsBroadcastReceiver;
1543             mUserUnlocked = userUnlocked;
1544             mIsClass0 = isClass0;
1545             mSubId = subId;
1546         }
1547 
1548         @Override
onFilterComplete(int result)1549         public void onFilterComplete(int result) {
1550             logv("onFilterComplete: result is " + result);
1551             if ((result & CarrierMessagingService.RECEIVE_OPTIONS_DROP) == 0) {
1552                 if (VisualVoicemailSmsFilter.filter(mContext, mPdus,
1553                         mSmsFormat, mDestPort, mSubId)) {
1554                     log("Visual voicemail SMS dropped");
1555                     dropSms(mSmsBroadcastReceiver);
1556                     return;
1557                 }
1558 
1559                 if (mUserUnlocked) {
1560                     dispatchSmsDeliveryIntent(
1561                             mPdus, mSmsFormat, mDestPort, mSmsBroadcastReceiver, mIsClass0, mSubId);
1562                 } else {
1563                     // Don't do anything further, leave the message in the raw table if the
1564                     // credential-encrypted storage is still locked and show the new message
1565                     // notification if the message is visible to the user.
1566                     if (!isSkipNotifyFlagSet(result)) {
1567                         showNewMessageNotification();
1568                     }
1569                     sendMessage(EVENT_BROADCAST_COMPLETE);
1570                 }
1571             } else {
1572                 // Drop this SMS.
1573                 dropSms(mSmsBroadcastReceiver);
1574             }
1575         }
1576     }
1577 
dropSms(SmsBroadcastReceiver receiver)1578     private void dropSms(SmsBroadcastReceiver receiver) {
1579         // Needs phone package permissions.
1580         deleteFromRawTable(receiver.mDeleteWhere, receiver.mDeleteWhereArgs, MARK_DELETED);
1581         sendMessage(EVENT_BROADCAST_COMPLETE);
1582     }
1583 
1584     /** Checks whether the flag to skip new message notification is set in the bitmask returned
1585      *  from the carrier app.
1586      */
1587     @UnsupportedAppUsage
isSkipNotifyFlagSet(int callbackResult)1588     private boolean isSkipNotifyFlagSet(int callbackResult) {
1589         return (callbackResult
1590             & RECEIVE_OPTIONS_SKIP_NOTIFY_WHEN_CREDENTIAL_PROTECTED_STORAGE_UNAVAILABLE) > 0;
1591     }
1592 
1593     /**
1594      * Log with debug level.
1595      * @param s the string to log
1596      */
1597     @UnsupportedAppUsage
1598     @Override
log(String s)1599     protected void log(String s) {
1600         Rlog.d(getName(), s);
1601     }
1602 
1603     /**
1604      * Log with error level.
1605      * @param s the string to log
1606      */
1607     @UnsupportedAppUsage
1608     @Override
loge(String s)1609     protected void loge(String s) {
1610         Rlog.e(getName(), s);
1611     }
1612 
1613     /**
1614      * Log with error level.
1615      * @param s the string to log
1616      * @param e is a Throwable which logs additional information.
1617      */
1618     @Override
loge(String s, Throwable e)1619     protected void loge(String s, Throwable e) {
1620         Rlog.e(getName(), s, e);
1621     }
1622 
1623     /**
1624      * Store a received SMS into Telephony provider
1625      *
1626      * @param intent The intent containing the received SMS
1627      * @return The URI of written message
1628      */
1629     @UnsupportedAppUsage
writeInboxMessage(Intent intent)1630     private Uri writeInboxMessage(Intent intent) {
1631         final SmsMessage[] messages = Telephony.Sms.Intents.getMessagesFromIntent(intent);
1632         if (messages == null || messages.length < 1) {
1633             loge("Failed to parse SMS pdu");
1634             return null;
1635         }
1636         // Sometimes, SmsMessage is null if it can’t be parsed correctly.
1637         for (final SmsMessage sms : messages) {
1638             if (sms == null) {
1639                 loge("Can’t write null SmsMessage");
1640                 return null;
1641             }
1642         }
1643         final ContentValues values = parseSmsMessage(messages);
1644         final long identity = Binder.clearCallingIdentity();
1645         try {
1646             return mContext.getContentResolver().insert(Telephony.Sms.Inbox.CONTENT_URI, values);
1647         } catch (Exception e) {
1648             loge("Failed to persist inbox message", e);
1649         } finally {
1650             Binder.restoreCallingIdentity(identity);
1651         }
1652         return null;
1653     }
1654 
1655     /**
1656      * Convert SmsMessage[] into SMS database schema columns
1657      *
1658      * @param msgs The SmsMessage array of the received SMS
1659      * @return ContentValues representing the columns of parsed SMS
1660      */
parseSmsMessage(SmsMessage[] msgs)1661     private static ContentValues parseSmsMessage(SmsMessage[] msgs) {
1662         final SmsMessage sms = msgs[0];
1663         final ContentValues values = new ContentValues();
1664         values.put(Telephony.Sms.Inbox.ADDRESS, sms.getDisplayOriginatingAddress());
1665         values.put(Telephony.Sms.Inbox.BODY, buildMessageBodyFromPdus(msgs));
1666         values.put(Telephony.Sms.Inbox.DATE_SENT, sms.getTimestampMillis());
1667         values.put(Telephony.Sms.Inbox.DATE, System.currentTimeMillis());
1668         values.put(Telephony.Sms.Inbox.PROTOCOL, sms.getProtocolIdentifier());
1669         values.put(Telephony.Sms.Inbox.SEEN, 0);
1670         values.put(Telephony.Sms.Inbox.READ, 0);
1671         final String subject = sms.getPseudoSubject();
1672         if (!TextUtils.isEmpty(subject)) {
1673             values.put(Telephony.Sms.Inbox.SUBJECT, subject);
1674         }
1675         values.put(Telephony.Sms.Inbox.REPLY_PATH_PRESENT, sms.isReplyPathPresent() ? 1 : 0);
1676         values.put(Telephony.Sms.Inbox.SERVICE_CENTER, sms.getServiceCenterAddress());
1677         return values;
1678     }
1679 
1680     /**
1681      * Build up the SMS message body from the SmsMessage array of received SMS
1682      *
1683      * @param msgs The SmsMessage array of the received SMS
1684      * @return The text message body
1685      */
buildMessageBodyFromPdus(SmsMessage[] msgs)1686     private static String buildMessageBodyFromPdus(SmsMessage[] msgs) {
1687         if (msgs.length == 1) {
1688             // There is only one part, so grab the body directly.
1689             return replaceFormFeeds(msgs[0].getDisplayMessageBody());
1690         } else {
1691             // Build up the body from the parts.
1692             StringBuilder body = new StringBuilder();
1693             for (SmsMessage msg: msgs) {
1694                 // getDisplayMessageBody() can NPE if mWrappedMessage inside is null.
1695                 body.append(msg.getDisplayMessageBody());
1696             }
1697             return replaceFormFeeds(body.toString());
1698         }
1699     }
1700 
1701     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)1702     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1703         super.dump(fd, pw, args);
1704         if (mCellBroadcastServiceManager != null) {
1705             mCellBroadcastServiceManager.dump(fd, pw, args);
1706         }
1707         mLocalLog.dump(fd, pw, args);
1708     }
1709 
1710     // Some providers send formfeeds in their messages. Convert those formfeeds to newlines.
replaceFormFeeds(String s)1711     private static String replaceFormFeeds(String s) {
1712         return s == null ? "" : s.replace('\f', '\n');
1713     }
1714 
1715     @VisibleForTesting
getWakeLock()1716     public PowerManager.WakeLock getWakeLock() {
1717         return mWakeLock;
1718     }
1719 
1720     @VisibleForTesting
getWakeLockTimeout()1721     public int getWakeLockTimeout() {
1722         return mWakeLockTimeout;
1723     }
1724 
1725     /**
1726     * Sets the wakelock timeout to {@link timeOut} milliseconds
1727     */
setWakeLockTimeout(int timeOut)1728     private void setWakeLockTimeout(int timeOut) {
1729         mWakeLockTimeout = timeOut;
1730     }
1731 
1732     /**
1733      * Handler for the broadcast sent when the new message notification is clicked. It launches the
1734      * default SMS app.
1735      */
1736     private static class NewMessageNotificationActionReceiver extends BroadcastReceiver {
1737         @Override
onReceive(Context context, Intent intent)1738         public void onReceive(Context context, Intent intent) {
1739             if (ACTION_OPEN_SMS_APP.equals(intent.getAction())) {
1740                 // do nothing if the user had not unlocked the device yet
1741                 UserManager userManager =
1742                         (UserManager) context.getSystemService(Context.USER_SERVICE);
1743                 if (userManager.isUserUnlocked()) {
1744                     context.startActivity(context.getPackageManager().getLaunchIntentForPackage(
1745                             Telephony.Sms.getDefaultSmsPackage(context)));
1746                 }
1747             }
1748         }
1749     }
1750 
decodeHexString(String hexString)1751     protected byte[] decodeHexString(String hexString) {
1752         if (hexString == null || hexString.length() % 2 == 1) {
1753             return null;
1754         }
1755         byte[] bytes = new byte[hexString.length() / 2];
1756         for (int i = 0; i < hexString.length(); i += 2) {
1757             bytes[i / 2] = hexToByte(hexString.substring(i, i + 2));
1758         }
1759         return bytes;
1760     }
1761 
hexToByte(String hexString)1762     private byte hexToByte(String hexString) {
1763         int firstDigit = toDigit(hexString.charAt(0));
1764         int secondDigit = toDigit(hexString.charAt(1));
1765         return (byte) ((firstDigit << 4) + secondDigit);
1766     }
1767 
toDigit(char hexChar)1768     private int toDigit(char hexChar) {
1769         int digit = Character.digit(hexChar, 16);
1770         if (digit == -1) {
1771             return 0;
1772         }
1773         return digit;
1774     }
1775 
1776 
1777     /**
1778      * Registers the broadcast receiver to launch the default SMS app when the user clicks the
1779      * new message notification.
1780      */
registerNewMessageNotificationActionHandler(Context context)1781     static void registerNewMessageNotificationActionHandler(Context context) {
1782         IntentFilter userFilter = new IntentFilter();
1783         userFilter.addAction(ACTION_OPEN_SMS_APP);
1784         context.registerReceiver(new NewMessageNotificationActionReceiver(), userFilter);
1785     }
1786 
1787     protected abstract class CbTestBroadcastReceiver extends BroadcastReceiver {
1788 
handleTestAction(Intent intent)1789         protected abstract void handleTestAction(Intent intent);
1790 
1791         protected final String mTestAction;
1792 
CbTestBroadcastReceiver(String testAction)1793         public CbTestBroadcastReceiver(String testAction) {
1794             mTestAction = testAction;
1795         }
1796 
1797         @Override
onReceive(Context context, Intent intent)1798         public void onReceive(Context context, Intent intent) {
1799             logd("Received test intent action=" + intent.getAction());
1800             if (intent.getAction().equals(mTestAction)) {
1801                 // Return early if phone_id is explicilty included and does not match mPhone.
1802                 // If phone_id extra is not included, continue.
1803                 int phoneId = mPhone.getPhoneId();
1804                 if (intent.getIntExtra("phone_id", phoneId) != phoneId) {
1805                     return;
1806                 }
1807                 handleTestAction(intent);
1808             }
1809         }
1810     }
1811 }
1812