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