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