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