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