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