1 /*
2  * Copyright (C) 2008 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.telephony.SmsManager.STATUS_ON_ICC_FREE;
20 import static android.telephony.SmsManager.STATUS_ON_ICC_READ;
21 import static android.telephony.SmsManager.STATUS_ON_ICC_UNREAD;
22 
23 import android.Manifest;
24 import android.annotation.NonNull;
25 import android.annotation.RequiresPermission;
26 import android.app.AppOpsManager;
27 import android.app.PendingIntent;
28 import android.compat.annotation.UnsupportedAppUsage;
29 import android.content.ContentResolver;
30 import android.content.Context;
31 import android.content.pm.PackageManager;
32 import android.database.Cursor;
33 import android.database.sqlite.SQLiteException;
34 import android.net.Uri;
35 import android.os.AsyncResult;
36 import android.os.Binder;
37 import android.os.Build;
38 import android.os.Handler;
39 import android.os.Looper;
40 import android.os.Message;
41 import android.provider.Telephony;
42 import android.telephony.SmsCbMessage;
43 import android.telephony.SmsManager;
44 import android.telephony.SmsMessage;
45 import android.telephony.emergency.EmergencyNumber;
46 import android.util.LocalLog;
47 import android.util.Log;
48 
49 import com.android.internal.annotations.VisibleForTesting;
50 import com.android.internal.telephony.cdma.CdmaSmsBroadcastConfigInfo;
51 import com.android.internal.telephony.flags.FeatureFlags;
52 import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo;
53 import com.android.internal.telephony.uicc.IccConstants;
54 import com.android.internal.telephony.uicc.IccFileHandler;
55 import com.android.internal.telephony.uicc.IccUtils;
56 import com.android.internal.telephony.uicc.UiccController;
57 import com.android.internal.telephony.uicc.UiccProfile;
58 import com.android.internal.util.HexDump;
59 import com.android.telephony.Rlog;
60 
61 import java.io.FileDescriptor;
62 import java.io.PrintWriter;
63 import java.util.ArrayList;
64 import java.util.Arrays;
65 import java.util.List;
66 import java.util.concurrent.atomic.AtomicBoolean;
67 
68 /**
69  * IccSmsInterfaceManager to provide an inter-process communication to
70  * access Sms in Icc.
71  */
72 public class IccSmsInterfaceManager {
73     static final String LOG_TAG = "IccSmsInterfaceManager";
74     static final boolean DBG = true;
75 
76     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
77     private CellBroadcastRangeManager mCellBroadcastRangeManager =
78             new CellBroadcastRangeManager();
79     private CdmaBroadcastRangeManager mCdmaBroadcastRangeManager =
80             new CdmaBroadcastRangeManager();
81 
82     private static final int EVENT_LOAD_DONE = 1;
83     private static final int EVENT_UPDATE_DONE = 2;
84     protected static final int EVENT_SET_BROADCAST_ACTIVATION_DONE = 3;
85     protected static final int EVENT_SET_BROADCAST_CONFIG_DONE = 4;
86     private static final int EVENT_GET_SMSC_DONE = 5;
87     private static final int EVENT_SET_SMSC_DONE = 6;
88     private static final int SMS_CB_CODE_SCHEME_MIN = 0;
89     private static final int SMS_CB_CODE_SCHEME_MAX = 255;
90     public static final int SMS_MESSAGE_PRIORITY_NOT_SPECIFIED = -1;
91     public static final int SMS_MESSAGE_PERIOD_NOT_SPECIFIED = -1;
92 
93     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
94     protected Phone mPhone;
95     @UnsupportedAppUsage
96     final protected Context mContext;
97     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
98     final protected AppOpsManager mAppOps;
99     @VisibleForTesting
100     public SmsDispatchersController mDispatchersController;
101     private SmsPermissions mSmsPermissions;
102 
103     private final LocalLog mCellBroadcastLocalLog = new LocalLog(64);
104 
105     private static final class Request {
106         AtomicBoolean mStatus = new AtomicBoolean(false);
107         Object mResult = null;
108     }
109 
110     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
111     protected Handler mHandler = new Handler() {
112         @Override
113         public void handleMessage(Message msg) {
114             AsyncResult ar = (AsyncResult) msg.obj;
115             Request request = (Request) ar.userObj;
116 
117             switch (msg.what) {
118                 case EVENT_UPDATE_DONE:
119                 case EVENT_SET_BROADCAST_ACTIVATION_DONE:
120                 case EVENT_SET_BROADCAST_CONFIG_DONE:
121                 case EVENT_SET_SMSC_DONE:
122                     notifyPending(request, ar.exception == null);
123                     break;
124                 case EVENT_LOAD_DONE:
125                     List<SmsRawData> smsRawDataList = null;
126                     if (ar.exception == null) {
127                         smsRawDataList = buildValidRawData((ArrayList<byte[]>) ar.result);
128                         //Mark SMS as read after importing it from card.
129                         markMessagesAsRead((ArrayList<byte[]>) ar.result);
130                     } else {
131                         if (Rlog.isLoggable("SMS", Log.DEBUG)) {
132                             loge("Cannot load Sms records");
133                         }
134                     }
135                     notifyPending(request, smsRawDataList);
136                     break;
137                 case EVENT_GET_SMSC_DONE:
138                     String smsc = null;
139                     if (ar.exception == null) {
140                         smsc = (String) ar.result;
141                     } else {
142                         loge("Cannot read SMSC");
143                     }
144                     notifyPending(request, smsc);
145                     break;
146             }
147         }
148 
149         private void notifyPending(Request request, Object result) {
150             if (request != null) {
151                 synchronized (request) {
152                     request.mResult = result;
153                     request.mStatus.set(true);
154                     request.notifyAll();
155                 }
156             }
157         }
158     };
159 
IccSmsInterfaceManager(Phone phone, @NonNull FeatureFlags featureFlags)160     protected IccSmsInterfaceManager(Phone phone, @NonNull FeatureFlags featureFlags) {
161         this(phone, phone.getContext(),
162                 (AppOpsManager) phone.getContext().getSystemService(Context.APP_OPS_SERVICE),
163                 new SmsDispatchersController(
164                         phone, phone.mSmsStorageMonitor, phone.mSmsUsageMonitor, featureFlags),
165                 new SmsPermissions(phone, phone.getContext(),
166                         (AppOpsManager) phone.getContext().getSystemService(
167                                 Context.APP_OPS_SERVICE)));
168     }
169 
170     @VisibleForTesting
IccSmsInterfaceManager( Phone phone, Context context, AppOpsManager appOps, SmsDispatchersController dispatchersController, SmsPermissions smsPermissions)171     public IccSmsInterfaceManager(
172             Phone phone, Context context, AppOpsManager appOps,
173             SmsDispatchersController dispatchersController, SmsPermissions smsPermissions) {
174         mPhone = phone;
175         mContext = context;
176         mAppOps = appOps;
177         mDispatchersController = dispatchersController;
178         mSmsPermissions = smsPermissions;
179     }
180 
181     /**
182      * PhoneFactory Dependencies for testing.
183      */
184     @VisibleForTesting
185     public interface PhoneFactoryProxy {
getPhone(int index)186         Phone getPhone(int index);
getDefaultPhone()187         Phone getDefaultPhone();
getPhones()188         Phone[] getPhones();
189     }
190 
191     private PhoneFactoryProxy mPhoneFactoryProxy = new PhoneFactoryProxy() {
192         @Override
193         public Phone getPhone(int index) {
194             return PhoneFactory.getPhone(index);
195         }
196 
197         @Override
198         public Phone getDefaultPhone() {
199             return PhoneFactory.getDefaultPhone();
200         }
201 
202         @Override
203         public Phone[] getPhones() {
204             return PhoneFactory.getPhones();
205         }
206     };
207 
208     /**
209      * Overrides PhoneFactory dependencies for testing.
210      */
211     @VisibleForTesting
setPhoneFactoryProxy(PhoneFactoryProxy proxy)212     public void setPhoneFactoryProxy(PhoneFactoryProxy proxy) {
213         mPhoneFactoryProxy = proxy;
214     }
215 
enforceNotOnHandlerThread(String methodName)216     private void enforceNotOnHandlerThread(String methodName) {
217         if (Looper.myLooper() == mHandler.getLooper()) {
218             throw new RuntimeException("This method " + methodName + " will deadlock if called from"
219                     + " the handler's thread.");
220         }
221     }
222 
markMessagesAsRead(ArrayList<byte[]> messages)223     protected void markMessagesAsRead(ArrayList<byte[]> messages) {
224         if (messages == null) {
225             return;
226         }
227 
228         //IccFileHandler can be null, if icc card is absent.
229         IccFileHandler fh = mPhone.getIccFileHandler();
230         if (fh == null) {
231             //shouldn't really happen, as messages are marked as read, only
232             //after importing it from icc.
233             if (Rlog.isLoggable("SMS", Log.DEBUG)) {
234                 loge("markMessagesAsRead - aborting, no icc card present.");
235             }
236             return;
237         }
238 
239         int count = messages.size();
240 
241         for (int i = 0; i < count; i++) {
242             byte[] ba = messages.get(i);
243             if ((ba[0] & 0x07) == STATUS_ON_ICC_UNREAD) {
244                 int n = ba.length;
245                 byte[] nba = new byte[n - 1];
246                 System.arraycopy(ba, 1, nba, 0, n - 1);
247                 byte[] record = makeSmsRecordData(STATUS_ON_ICC_READ, nba);
248                 fh.updateEFLinearFixed(IccConstants.EF_SMS, i + 1, record, null, null);
249                 if (Rlog.isLoggable("SMS", Log.DEBUG)) {
250                     log("SMS " + (i + 1) + " marked as read");
251                 }
252             }
253         }
254     }
255 
256     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
enforceReceiveAndSend(String message)257     protected void enforceReceiveAndSend(String message) {
258         mContext.enforceCallingOrSelfPermission(
259                 Manifest.permission.RECEIVE_SMS, message);
260         mContext.enforceCallingOrSelfPermission(
261                 Manifest.permission.SEND_SMS, message);
262     }
263 
264     /**
265      * Enforce the permission for access messages on ICC
266      */
enforceAccessMessageOnICC(String message)267     private void enforceAccessMessageOnICC(String message) {
268         mContext.enforceCallingOrSelfPermission(
269                 Manifest.permission.ACCESS_MESSAGES_ON_ICC, message);
270     }
271 
272     /**
273      * Update the specified message on the Icc.
274      *
275      * @param index record index of message to update
276      * @param status new message status (STATUS_ON_ICC_READ,
277      *                  STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT,
278      *                  STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE)
279      * @param pdu the raw PDU to store
280      * @return success or not
281      *
282      */
283 
284     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
285     public boolean
updateMessageOnIccEf(String callingPackage, int index, int status, byte[] pdu)286     updateMessageOnIccEf(String callingPackage, int index, int status, byte[] pdu) {
287         if (DBG) log("updateMessageOnIccEf: index=" + index +
288                 " status=" + status + " ==> " +
289                 "("+ Arrays.toString(pdu) + ")");
290         enforceReceiveAndSend("Updating message on Icc");
291         enforceAccessMessageOnICC("Updating message on Icc");
292         enforceNotOnHandlerThread("updateMessageOnIccEf");
293         if (mAppOps.noteOp(AppOpsManager.OPSTR_WRITE_ICC_SMS, Binder.getCallingUid(),
294                 callingPackage) != AppOpsManager.MODE_ALLOWED) {
295             return false;
296         }
297         Request updateRequest = new Request();
298         synchronized (updateRequest) {
299             Message response = mHandler.obtainMessage(EVENT_UPDATE_DONE, updateRequest);
300 
301             if ((status & 0x01) == STATUS_ON_ICC_FREE) {
302                 // RIL_REQUEST_DELETE_SMS_ON_SIM vs RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM
303                 // Special case FREE: call deleteSmsOnSim/Ruim instead of
304                 // manipulating the record
305                 // Will eventually fail if icc card is not present.
306                 if (PhoneConstants.PHONE_TYPE_GSM == mPhone.getPhoneType()) {
307                     mPhone.mCi.deleteSmsOnSim(index, response);
308                 } else {
309                     mPhone.mCi.deleteSmsOnRuim(index, response);
310                 }
311             } else {
312                 //IccFilehandler can be null if ICC card is not present.
313                 IccFileHandler fh = mPhone.getIccFileHandler();
314                 if (fh == null) {
315                     response.recycle();
316                     return false; /* is false */
317                 }
318                 byte[] record = makeSmsRecordData(status, pdu);
319                 fh.updateEFLinearFixed(
320                         IccConstants.EF_SMS,
321                         index, record, null, response);
322             }
323             waitForResult(updateRequest);
324         }
325         return (boolean) updateRequest.mResult;
326     }
327 
328     /**
329      * Copies a raw SMS PDU to the ICC.
330      *
331      * @param callingPackage the package name of the calling app.
332      * @param status message status. One of these status:
333      *               <code>STATUS_ON_ICC_READ</code>
334      *               <code>STATUS_ON_ICC_UNREAD</code>
335      *               <code>STATUS_ON_ICC_SENT</code>
336      *               <code>STATUS_ON_ICC_UNSENT</code>
337      * @param pdu the raw PDU to store.
338      * @param smsc the SMSC for this message. Null means use default.
339      * @return true for success. Otherwise false.
340      */
341     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
copyMessageToIccEf(String callingPackage, int status, byte[] pdu, byte[] smsc)342     public boolean copyMessageToIccEf(String callingPackage, int status, byte[] pdu, byte[] smsc) {
343         //NOTE smsc not used in RUIM
344         if (DBG) log("copyMessageToIccEf: status=" + status + " ==> " +
345                 "pdu=("+ Arrays.toString(pdu) +
346                 "), smsc=(" + Arrays.toString(smsc) +")");
347         enforceReceiveAndSend("Copying message to Icc");
348         enforceNotOnHandlerThread("copyMessageToIccEf");
349         if (mAppOps.noteOp(AppOpsManager.OPSTR_WRITE_ICC_SMS, Binder.getCallingUid(),
350                 callingPackage) != AppOpsManager.MODE_ALLOWED) {
351             return false;
352         }
353         Request copyRequest = new Request();
354         synchronized (copyRequest) {
355             Message response = mHandler.obtainMessage(EVENT_UPDATE_DONE, copyRequest);
356 
357             //RIL_REQUEST_WRITE_SMS_TO_SIM vs RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM
358             if (PhoneConstants.PHONE_TYPE_GSM == mPhone.getPhoneType()) {
359                 mPhone.mCi.writeSmsToSim(status, IccUtils.bytesToHexString(smsc),
360                         IccUtils.bytesToHexString(pdu), response);
361             } else {
362                 mPhone.mCi.writeSmsToRuim(status, pdu, response);
363             }
364 
365             waitForResult(copyRequest);
366         }
367         return (boolean) copyRequest.mResult;
368     }
369 
370     /**
371      * Retrieves all messages currently stored on Icc.
372      *
373      * @return list of SmsRawData of all sms on Icc
374      */
375 
376     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
getAllMessagesFromIccEf(String callingPackage)377     public List<SmsRawData> getAllMessagesFromIccEf(String callingPackage) {
378         if (DBG) log("getAllMessagesFromEF");
379 
380         mContext.enforceCallingOrSelfPermission(
381                 Manifest.permission.RECEIVE_SMS,
382                 "Reading messages from Icc");
383         enforceAccessMessageOnICC("Reading messages from Icc");
384         enforceNotOnHandlerThread("getAllMessagesFromIccEf");
385         if (mAppOps.noteOp(AppOpsManager.OPSTR_READ_ICC_SMS, Binder.getCallingUid(),
386                 callingPackage) != AppOpsManager.MODE_ALLOWED) {
387             return new ArrayList<SmsRawData>();
388         }
389         Request getRequest = new Request();
390         synchronized (getRequest) {
391 
392             IccFileHandler fh = mPhone.getIccFileHandler();
393             if (fh == null) {
394                 loge("Cannot load Sms records. No icc card?");
395                 return null;
396             }
397 
398             Message response = mHandler.obtainMessage(EVENT_LOAD_DONE, getRequest);
399             fh.loadEFLinearFixedAll(IccConstants.EF_SMS, response);
400 
401             waitForResult(getRequest);
402         }
403         return (List<SmsRawData>) getRequest.mResult;
404     }
405 
406     /**
407      * A permissions check before passing to {@link IccSmsInterfaceManager#sendDataInternal}.
408      * This method checks if the calling package or itself has the permission to send the data sms.
409      */
sendDataWithSelfPermissions(String callingPackage, String callingAttributionTag, String destAddr, String scAddr, int destPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean isForVvm)410     public void sendDataWithSelfPermissions(String callingPackage, String callingAttributionTag,
411             String destAddr, String scAddr, int destPort, byte[] data, PendingIntent sentIntent,
412             PendingIntent deliveryIntent, boolean isForVvm) {
413         if (!mSmsPermissions.checkCallingOrSelfCanSendSms(callingPackage, callingAttributionTag,
414                 "Sending SMS message")) {
415             returnUnspecifiedFailure(sentIntent);
416             return;
417         }
418         sendDataInternal(callingPackage, destAddr, scAddr, destPort, data, sentIntent,
419                 deliveryIntent, isForVvm);
420     }
421 
422     /**
423      * @deprecated Use {@link #sendData(String, String, String, String, int, byte[], PendingIntent,
424      * PendingIntent)} instead.
425      */
426     @Deprecated
427     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
sendData(String callingPackage, String destAddr, String scAddr, int destPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent)428     public void sendData(String callingPackage, String destAddr, String scAddr, int destPort,
429             byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) {
430         sendData(callingPackage, null, destAddr, scAddr, destPort, data,
431                 sentIntent, deliveryIntent);
432     }
433 
434     /**
435      * A permissions check before passing to {@link IccSmsInterfaceManager#sendDataInternal}.
436      * This method checks only if the calling package has the permission to send the data sms.
437      */
sendData(String callingPackage, String callingAttributionTag, String destAddr, String scAddr, int destPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent)438     public void sendData(String callingPackage, String callingAttributionTag,
439             String destAddr, String scAddr, int destPort, byte[] data, PendingIntent sentIntent,
440             PendingIntent deliveryIntent) {
441         if (!mSmsPermissions.checkCallingCanSendSms(callingPackage, callingAttributionTag,
442                 "Sending SMS message")) {
443             returnUnspecifiedFailure(sentIntent);
444             return;
445         }
446         sendDataInternal(callingPackage, destAddr, scAddr, destPort, data, sentIntent,
447                 deliveryIntent, false /* isForVvm */);
448     }
449 
450     /**
451      * Send a data based SMS to a specific application port.
452      *
453      * @param callingPackage the package name of the calling app
454      * @param destAddr the address to send the message to
455      * @param scAddr is the service center address or null to use
456      *  the current default SMSC
457      * @param destPort the port to deliver the message to
458      * @param data the body of the message to send
459      * @param sentIntent if not NULL this <code>PendingIntent</code> is
460      *  broadcast when the message is successfully sent, or failed.
461      *  The result code will be <code>Activity.RESULT_OK<code> for success,
462      *  or one of these errors:<br>
463      *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
464      *  <code>RESULT_ERROR_RADIO_OFF</code><br>
465      *  <code>RESULT_ERROR_NULL_PDU</code><br>
466      *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
467      *  the extra "errorCode" containing a radio technology specific value,
468      *  generally only useful for troubleshooting.<br>
469      *  The per-application based SMS control checks sentIntent. If sentIntent
470      *  is NULL the caller will be checked against all unknown applications,
471      *  which cause smaller number of SMS to be sent in checking period.
472      * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
473      *  broadcast when the message is delivered to the recipient.  The
474      *  raw pdu of the status report is in the extended data ("pdu").
475      */
476 
sendDataInternal(String callingPackage, String destAddr, String scAddr, int destPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean isForVvm)477     private void sendDataInternal(String callingPackage, String destAddr, String scAddr,
478             int destPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent,
479             boolean isForVvm) {
480         if (Rlog.isLoggable("SMS", Log.VERBOSE)) {
481             log("sendData: destAddr=" + destAddr + " scAddr=" + scAddr + " destPort="
482                     + destPort + " data='" + HexDump.toHexString(data)  + "' sentIntent="
483                     + sentIntent + " deliveryIntent=" + deliveryIntent + " isForVVM=" + isForVvm);
484         }
485         destAddr = filterDestAddress(destAddr);
486         mDispatchersController.sendData(callingPackage, destAddr, scAddr, destPort, data,
487                 sentIntent, deliveryIntent, isForVvm);
488     }
489 
490     /**
491      * A permissions check before passing to {@link IccSmsInterfaceManager#sendTextInternal}.
492      * This method checks only if the calling package has the permission to send the sms.
493      * Note: SEND_SMS permission should be checked by the caller of this method
494      */
sendText(String callingPackage, String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean persistMessageForNonDefaultSmsApp, long messageId, boolean skipShortCodeCheck)495     public void sendText(String callingPackage, String destAddr, String scAddr,
496             String text, PendingIntent sentIntent, PendingIntent deliveryIntent,
497             boolean persistMessageForNonDefaultSmsApp, long messageId, boolean skipShortCodeCheck) {
498         sendTextInternal(callingPackage, destAddr, scAddr, text, sentIntent, deliveryIntent,
499                 persistMessageForNonDefaultSmsApp, SMS_MESSAGE_PRIORITY_NOT_SPECIFIED,
500                 false /* expectMore */, SMS_MESSAGE_PERIOD_NOT_SPECIFIED, false /* isForVvm */,
501                 messageId, skipShortCodeCheck);
502     }
503 
504     /**
505      * A permissions check before passing to {@link IccSmsInterfaceManager#sendTextInternal}.
506      * This method checks if the calling package or itself has the permission to send the sms.
507      */
sendTextWithSelfPermissions(String callingPackage, String callingAttributeTag, String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean persistMessage, boolean isForVvm)508     public void sendTextWithSelfPermissions(String callingPackage, String callingAttributeTag,
509             String destAddr, String scAddr, String text, PendingIntent sentIntent,
510             PendingIntent deliveryIntent, boolean persistMessage, boolean isForVvm) {
511         if (!mSmsPermissions.checkCallingOrSelfCanSendSms(callingPackage, callingAttributeTag,
512                 "Sending SMS message")) {
513             returnUnspecifiedFailure(sentIntent);
514             return;
515         }
516         sendTextInternal(callingPackage, destAddr, scAddr, text, sentIntent, deliveryIntent,
517                 persistMessage, SMS_MESSAGE_PRIORITY_NOT_SPECIFIED, false /* expectMore */,
518                 SMS_MESSAGE_PERIOD_NOT_SPECIFIED, isForVvm, 0L /* messageId */);
519     }
520 
521 
sendTextInternal(String callingPackage, String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean persistMessageForNonDefaultSmsApp, int priority, boolean expectMore, int validityPeriod, boolean isForVvm, long messageId)522     private void sendTextInternal(String callingPackage, String destAddr, String scAddr,
523             String text, PendingIntent sentIntent, PendingIntent deliveryIntent,
524             boolean persistMessageForNonDefaultSmsApp, int priority, boolean expectMore,
525             int validityPeriod, boolean isForVvm, long messageId) {
526         sendTextInternal(callingPackage, destAddr, scAddr, text, sentIntent, deliveryIntent,
527                 persistMessageForNonDefaultSmsApp, priority, expectMore, validityPeriod, isForVvm,
528                 messageId, false);
529     }
530 
531     /**
532      * Send a text based SMS.
533      *
534      * @param destAddr the address to send the message to
535      * @param scAddr is the service center address or null to use
536      *  the current default SMSC
537      * @param text the body of the message to send
538      * @param sentIntent if not NULL this <code>PendingIntent</code> is
539      *  broadcast when the message is successfully sent, or failed.
540      *  The result code will be <code>Activity.RESULT_OK<code> for success,
541      *  or one of these errors:<br>
542      *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
543      *  <code>RESULT_ERROR_RADIO_OFF</code><br>
544      *  <code>RESULT_ERROR_NULL_PDU</code><br>
545      *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
546      *  the extra "errorCode" containing a radio technology specific value,
547      *  generally only useful for troubleshooting.<br>
548      *  The per-application based SMS control checks sentIntent. If sentIntent
549      *  is NULL the caller will be checked against all unknown applications,
550      *  which cause smaller number of SMS to be sent in checking period.
551      * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
552      *  broadcast when the message is delivered to the recipient.  The
553      *  raw pdu of the status report is in the extended data ("pdu").
554      * @param persistMessageForNonDefaultSmsApp whether the sent message should
555      *  be automatically persisted in the SMS db. It only affects messages sent
556      *  by a non-default SMS app. Currently only the carrier app can set this
557      *  parameter to false to skip auto message persistence.
558      * @param priority Priority level of the message
559      *  Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1
560      *  ---------------------------------
561      *  PRIORITY      | Level of Priority
562      *  ---------------------------------
563      *      '00'      |     Normal
564      *      '01'      |     Interactive
565      *      '10'      |     Urgent
566      *      '11'      |     Emergency
567      *  ----------------------------------
568      *  Any Other values including negative considered as Invalid Priority Indicator of the message.
569      * @param expectMore is a boolean to indicate the sending messages through same link or not.
570      * @param validityPeriod Validity Period of the message in mins.
571      *  Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
572      *  Validity Period(Minimum) -> 5 mins
573      *  Validity Period(Maximum) -> 635040 mins(i.e.63 weeks).
574      *  Any Other values including negative considered as Invalid Validity Period of the message.
575      * @param messageId An id that uniquely identifies the message requested to be sent.
576      *                 Used for logging and diagnostics purposes. The id may be 0.
577      * @param skipShortCodeCheck Skip check for short code type destination address.
578      */
579 
sendTextInternal(String callingPackage, String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean persistMessageForNonDefaultSmsApp, int priority, boolean expectMore, int validityPeriod, boolean isForVvm, long messageId, boolean skipShortCodeCheck)580     private void sendTextInternal(String callingPackage, String destAddr, String scAddr,
581             String text, PendingIntent sentIntent, PendingIntent deliveryIntent,
582             boolean persistMessageForNonDefaultSmsApp, int priority, boolean expectMore,
583             int validityPeriod, boolean isForVvm, long messageId, boolean skipShortCodeCheck) {
584         if (Rlog.isLoggable("SMS", Log.VERBOSE)) {
585             log("sendText: destAddr=" + destAddr + " scAddr=" + scAddr
586                     + " text='" + text + "' sentIntent=" + sentIntent + " deliveryIntent="
587                     + deliveryIntent + " priority=" + priority + " expectMore=" + expectMore
588                     + " validityPeriod=" + validityPeriod + " isForVVM=" + isForVvm
589                     + " " + SmsController.formatCrossStackMessageId(messageId));
590         }
591         notifyIfOutgoingEmergencySms(destAddr);
592         destAddr = filterDestAddress(destAddr);
593         mDispatchersController.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent,
594                 null/*messageUri*/, callingPackage, persistMessageForNonDefaultSmsApp,
595                 priority, expectMore, validityPeriod, isForVvm, messageId, skipShortCodeCheck);
596     }
597 
598     /**
599      * Send a text based SMS with Messaging Options.
600      *
601      * @param destAddr the address to send the message to
602      * @param scAddr is the service center address or null to use
603      *  the current default SMSC
604      * @param text the body of the message to send
605      * @param sentIntent if not NULL this <code>PendingIntent</code> is
606      *  broadcast when the message is successfully sent, or failed.
607      *  The result code will be <code>Activity.RESULT_OK<code> for success,
608      *  or one of these errors:<br>
609      *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
610      *  <code>RESULT_ERROR_RADIO_OFF</code><br>
611      *  <code>RESULT_ERROR_NULL_PDU</code><br>
612      *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
613      *  the extra "errorCode" containing a radio technology specific value,
614      *  generally only useful for troubleshooting.<br>
615      *  The per-application based SMS control checks sentIntent. If sentIntent
616      *  is NULL the caller will be checked against all unknown applications,
617      *  which cause smaller number of SMS to be sent in checking period.
618      * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
619      *  broadcast when the message is delivered to the recipient.  The
620      *  raw pdu of the status report is in the extended data ("pdu").
621      * @param persistMessageForNonDefaultSmsApp whether the sent message should
622      *  be automatically persisted in the SMS db. It only affects messages sent
623      *  by a non-default SMS app. Currently only the carrier app can set this
624      *  parameter to false to skip auto message persistence.
625      * @param priority Priority level of the message
626      *  Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1
627      *  ---------------------------------
628      *  PRIORITY      | Level of Priority
629      *  ---------------------------------
630      *      '00'      |     Normal
631      *      '01'      |     Interactive
632      *      '10'      |     Urgent
633      *      '11'      |     Emergency
634      *  ----------------------------------
635      *  Any Other values including negative considered as Invalid Priority Indicator of the message.
636      * @param expectMore is a boolean to indicate the sending messages through same link or not.
637      * @param validityPeriod Validity Period of the message in mins.
638      *  Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
639      *  Validity Period(Minimum) -> 5 mins
640      *  Validity Period(Maximum) -> 635040 mins(i.e.63 weeks).
641      *  Any Other values including negative considered as Invalid Validity Period of the message.
642      */
643 
sendTextWithOptions(String callingPackage, String callingAttributionTag, String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean persistMessageForNonDefaultSmsApp, int priority, boolean expectMore, int validityPeriod)644     public void sendTextWithOptions(String callingPackage, String callingAttributionTag,
645             String destAddr, String scAddr, String text, PendingIntent sentIntent,
646             PendingIntent deliveryIntent, boolean persistMessageForNonDefaultSmsApp, int priority,
647             boolean expectMore, int validityPeriod) {
648         if (!mSmsPermissions.checkCallingCanSendText(persistMessageForNonDefaultSmsApp,
649                     callingPackage, callingAttributionTag, "Sending SMS message")) {
650             returnUnspecifiedFailure(sentIntent);
651             return;
652         }
653         sendTextInternal(callingPackage, destAddr, scAddr, text, sentIntent, deliveryIntent,
654                 persistMessageForNonDefaultSmsApp, priority, expectMore, validityPeriod,
655                 false /* isForVvm */, 0L /* messageId */);
656     }
657 
658     /**
659      * Inject an SMS PDU into the android application framework.
660      *
661      * @param pdu is the byte array of pdu to be injected into android application framework
662      * @param format is the format of SMS pdu (3gpp or 3gpp2)
663      * @param receivedIntent if not NULL this <code>PendingIntent</code> is
664      *  broadcast when the message is successfully received by the
665      *  android application framework. This intent is broadcasted at
666      *  the same time an SMS received from radio is acknowledged back.
667      */
668     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
injectSmsPdu(byte[] pdu, String format, PendingIntent receivedIntent)669     public void injectSmsPdu(byte[] pdu, String format, PendingIntent receivedIntent) {
670         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
671                 != PackageManager.PERMISSION_GRANTED) {
672             mSmsPermissions.enforceCallerIsImsAppOrCarrierApp("injectSmsPdu");
673         }
674 
675         if (Rlog.isLoggable("SMS", Log.VERBOSE)) {
676             log("pdu: " + IccUtils.bytesToHexString(pdu)
677                     + "\n format=" + format
678                     + "\n receivedIntent=" + receivedIntent);
679         }
680         mDispatchersController.injectSmsPdu(pdu, format, false /* isOverIms */,
681                 result -> {
682                     if (receivedIntent != null) {
683                         try {
684                             receivedIntent.send(result);
685                         } catch (PendingIntent.CanceledException e) {
686                             loge("receivedIntent cancelled.");
687                         }
688                     }
689                 }
690         );
691     }
692 
693     /**
694      * Send a multi-part text based SMS.
695      *
696      * @param destAddr the address to send the message to
697      * @param scAddr is the service center address or null to use
698      *   the current default SMSC
699      * @param parts an <code>ArrayList</code> of strings that, in order,
700      *   comprise the original message
701      * @param sentIntents if not null, an <code>ArrayList</code> of
702      *   <code>PendingIntent</code>s (one for each message part) that is
703      *   broadcast when the corresponding message part has been sent.
704      *   The result code will be <code>Activity.RESULT_OK<code> for success,
705      *   or one of these errors:
706      *   <code>RESULT_ERROR_GENERIC_FAILURE</code>
707      *   <code>RESULT_ERROR_RADIO_OFF</code>
708      *   <code>RESULT_ERROR_NULL_PDU</code>.
709      *  The per-application based SMS control checks sentIntent. If sentIntent
710      *  is NULL the caller will be checked against all unknown applications,
711      *  which cause smaller number of SMS to be sent in checking period.
712      * @param deliveryIntents if not null, an <code>ArrayList</code> of
713      *   <code>PendingIntent</code>s (one for each message part) that is
714      *   broadcast when the corresponding message part has been delivered
715      *   to the recipient.  The raw pdu of the status report is in the
716      *   extended data ("pdu").
717      * @param messageId An id that uniquely identifies the message requested to be sent.
718      *                 Used for logging and diagnostics purposes. The id may be 0.
719      */
720 
sendMultipartText(String callingPackage, String callingAttributionTag, String destAddr, String scAddr, List<String> parts, List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents, boolean persistMessageForNonDefaultSmsApp, long messageId)721     public void sendMultipartText(String callingPackage, String callingAttributionTag,
722             String destAddr, String scAddr, List<String> parts, List<PendingIntent> sentIntents,
723             List<PendingIntent> deliveryIntents, boolean persistMessageForNonDefaultSmsApp,
724             long messageId) {
725         sendMultipartTextWithOptions(callingPackage, callingAttributionTag, destAddr, scAddr, parts,
726                 sentIntents, deliveryIntents, persistMessageForNonDefaultSmsApp,
727                 SMS_MESSAGE_PRIORITY_NOT_SPECIFIED, false /* expectMore */,
728                 SMS_MESSAGE_PERIOD_NOT_SPECIFIED,
729                 messageId);
730     }
731 
732     /**
733      * Send a multi-part text based SMS with Messaging Options.
734      *
735      * @param destAddr the address to send the message to
736      * @param scAddr is the service center address or null to use
737      *   the current default SMSC
738      * @param parts an <code>ArrayList</code> of strings that, in order,
739      *   comprise the original message
740      * @param sentIntents if not null, an <code>ArrayList</code> of
741      *   <code>PendingIntent</code>s (one for each message part) that is
742      *   broadcast when the corresponding message part has been sent.
743      *   The result code will be <code>Activity.RESULT_OK<code> for success,
744      *   or one of these errors:
745      *   <code>RESULT_ERROR_GENERIC_FAILURE</code>
746      *   <code>RESULT_ERROR_RADIO_OFF</code>
747      *   <code>RESULT_ERROR_NULL_PDU</code>.
748      *  The per-application based SMS control checks sentIntent. If sentIntent
749      *  is NULL the caller will be checked against all unknown applications,
750      *  which cause smaller number of SMS to be sent in checking period.
751      * @param deliveryIntents if not null, an <code>ArrayList</code> of
752      *   <code>PendingIntent</code>s (one for each message part) that is
753      *   broadcast when the corresponding message part has been delivered
754      *   to the recipient.  The raw pdu of the status report is in the
755      *   extended data ("pdu").
756      * @param persistMessageForNonDefaultSmsApp whether the sent message should
757      *   be automatically persisted in the SMS db. It only affects messages sent
758      *   by a non-default SMS app. Currently only the carrier app can set this
759      *   parameter to false to skip auto message persistence.
760      * @param priority Priority level of the message
761      *  Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1
762      *  ---------------------------------
763      *  PRIORITY      | Level of Priority
764      *  ---------------------------------
765      *      '00'      |     Normal
766      *      '01'      |     Interactive
767      *      '10'      |     Urgent
768      *      '11'      |     Emergency
769      *  ----------------------------------
770      *  Any Other values including negative considered as Invalid Priority Indicator of the message.
771      * @param expectMore is a boolean to indicate the sending messages through same link or not.
772      * @param validityPeriod Validity Period of the message in mins.
773      *  Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
774      *  Validity Period(Minimum) -> 5 mins
775      *  Validity Period(Maximum) -> 635040 mins(i.e.63 weeks).
776      *  Any Other values including negative considered as Invalid Validity Period of the message.
777      * @param messageId An id that uniquely identifies the message requested to be sent.
778      *                 Used for logging and diagnostics purposes. The id may be 0.
779      */
780 
sendMultipartTextWithOptions(String callingPackage, String callingAttributionTag, String destAddr, String scAddr, List<String> parts, List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents, boolean persistMessageForNonDefaultSmsApp, int priority, boolean expectMore, int validityPeriod, long messageId)781     public void sendMultipartTextWithOptions(String callingPackage, String callingAttributionTag,
782             String destAddr, String scAddr, List<String> parts, List<PendingIntent> sentIntents,
783             List<PendingIntent> deliveryIntents, boolean persistMessageForNonDefaultSmsApp,
784             int priority, boolean expectMore, int validityPeriod, long messageId) {
785         if (!mSmsPermissions.checkCallingCanSendText(persistMessageForNonDefaultSmsApp,
786                 callingPackage, callingAttributionTag, "Sending SMS message")) {
787             returnUnspecifiedFailure(sentIntents);
788             return;
789         }
790         if (Rlog.isLoggable("SMS", Log.VERBOSE)) {
791             int i = 0;
792             for (String part : parts) {
793                 log("sendMultipartTextWithOptions: destAddr=" + destAddr + ", srAddr=" + scAddr
794                         + ", part[" + (i++) + "]=" + part
795                         + " " + SmsController.formatCrossStackMessageId(messageId));
796             }
797         }
798         notifyIfOutgoingEmergencySms(destAddr);
799         destAddr = filterDestAddress(destAddr);
800 
801         if (parts.size() > 1 && parts.size() < 10 && !SmsMessage.hasEmsSupport()) {
802             for (int i = 0; i < parts.size(); i++) {
803                 // If EMS is not supported, we have to break down EMS into single segment SMS
804                 // and add page info " x/y".
805                 String singlePart = parts.get(i);
806                 if (SmsMessage.shouldAppendPageNumberAsPrefix()) {
807                     singlePart = String.valueOf(i + 1) + '/' + parts.size() + ' ' + singlePart;
808                 } else {
809                     singlePart = singlePart.concat(' ' + String.valueOf(i + 1) + '/'
810                             + parts.size());
811                 }
812 
813                 PendingIntent singleSentIntent = null;
814                 if (sentIntents != null && sentIntents.size() > i) {
815                     singleSentIntent = sentIntents.get(i);
816                 }
817 
818                 PendingIntent singleDeliveryIntent = null;
819                 if (deliveryIntents != null && deliveryIntents.size() > i) {
820                     singleDeliveryIntent = deliveryIntents.get(i);
821                 }
822 
823                 mDispatchersController.sendText(destAddr, scAddr, singlePart, singleSentIntent,
824                         singleDeliveryIntent, null /* messageUri */, callingPackage,
825                         persistMessageForNonDefaultSmsApp, priority, expectMore, validityPeriod,
826                         false /* isForVvm */, messageId);
827             }
828             return;
829         }
830 
831         mDispatchersController.sendMultipartText(destAddr,
832                                       scAddr,
833                                       (ArrayList<String>) parts,
834                                       (ArrayList<PendingIntent>) sentIntents,
835                                       (ArrayList<PendingIntent>) deliveryIntents,
836                                       null, callingPackage, persistMessageForNonDefaultSmsApp,
837                                           priority, expectMore, validityPeriod, messageId);
838 
839     }
840 
841     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
getPremiumSmsPermission(String packageName)842     public int getPremiumSmsPermission(String packageName) {
843         return mDispatchersController.getPremiumSmsPermission(packageName);
844     }
845 
846 
847     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
setPremiumSmsPermission(String packageName, int permission)848     public void setPremiumSmsPermission(String packageName, int permission) {
849         mDispatchersController.setPremiumSmsPermission(packageName, permission);
850     }
851 
852     /**
853      * create SmsRawData lists from all sms record byte[]
854      * Use null to indicate "free" record
855      *
856      * @param messages List of message records from EF_SMS.
857      * @return SmsRawData list of all in-used records
858      */
buildValidRawData(ArrayList<byte[]> messages)859     protected ArrayList<SmsRawData> buildValidRawData(ArrayList<byte[]> messages) {
860         int count = messages.size();
861         ArrayList<SmsRawData> ret;
862 
863         ret = new ArrayList<SmsRawData>(count);
864 
865         for (int i = 0; i < count; i++) {
866             byte[] ba = messages.get(i);
867             if ((ba[0] & 0x01) == STATUS_ON_ICC_FREE) {
868                 ret.add(null);
869             } else {
870                 ret.add(new SmsRawData(messages.get(i)));
871             }
872         }
873 
874         return ret;
875     }
876 
877     /**
878      * Generates an EF_SMS record from status and raw PDU.
879      *
880      * @param status Message status.  See TS 51.011 10.5.3.
881      * @param pdu Raw message PDU.
882      * @return byte array for the record.
883      */
makeSmsRecordData(int status, byte[] pdu)884     protected byte[] makeSmsRecordData(int status, byte[] pdu) {
885         byte[] data;
886         if (PhoneConstants.PHONE_TYPE_GSM == mPhone.getPhoneType()) {
887             data = new byte[SmsManager.SMS_RECORD_LENGTH];
888         } else {
889             data = new byte[SmsManager.CDMA_SMS_RECORD_LENGTH];
890         }
891 
892         // Status bits for this record.  See TS 51.011 10.5.3
893         data[0] = (byte) (status & 0x07);
894 
895         System.arraycopy(pdu, 0, data, 1, pdu.length);
896 
897         // Pad out with 0xFF's.
898         for (int j = pdu.length+1; j < data.length; j++) {
899             data[j] = -1;
900         }
901 
902         return data;
903     }
904 
905     /**
906      * Gets the SMSC address from (U)SIM.
907      *
908      * @return the SMSC address string, null if failed.
909      */
getSmscAddressFromIccEf(String callingPackage)910     public String getSmscAddressFromIccEf(String callingPackage) {
911         if (!mSmsPermissions.checkCallingOrSelfCanGetSmscAddress(
912                 callingPackage, "getSmscAddressFromIccEf")) {
913             loge("Caller do not have permission to call GetSmscAddress");
914             return null;
915         }
916         enforceNotOnHandlerThread("getSmscAddressFromIccEf");
917         Request getRequest = new Request();
918         synchronized (getRequest) {
919             Message response = mHandler.obtainMessage(EVENT_GET_SMSC_DONE, getRequest);
920             mPhone.mCi.getSmscAddress(response);
921             waitForResult(getRequest);
922         }
923         return (String) getRequest.mResult;
924     }
925 
926     /**
927      * Sets the SMSC address on (U)SIM.
928      *
929      * @param smsc the SMSC address string.
930      * @return true for success, false otherwise.
931      */
setSmscAddressOnIccEf(String callingPackage, String smsc)932     public boolean setSmscAddressOnIccEf(String callingPackage, String smsc) {
933         if (!mSmsPermissions.checkCallingOrSelfCanSetSmscAddress(
934                 callingPackage, "setSmscAddressOnIccEf")) {
935             loge("Caller do not have permission to call SetSmscAddress");
936             return false;
937         }
938         enforceNotOnHandlerThread("setSmscAddressOnIccEf");
939         Request setRequest = new Request();
940         synchronized (setRequest) {
941             Message response = mHandler.obtainMessage(EVENT_SET_SMSC_DONE, setRequest);
942             mPhone.mCi.setSmscAddress(smsc, response);
943             waitForResult(setRequest);
944         }
945         return (boolean) setRequest.mResult;
946     }
947 
enableCellBroadcast(int messageIdentifier, int ranType)948     public boolean enableCellBroadcast(int messageIdentifier, int ranType) {
949         return enableCellBroadcastRange(messageIdentifier, messageIdentifier, ranType);
950     }
951 
disableCellBroadcast(int messageIdentifier, int ranType)952     public boolean disableCellBroadcast(int messageIdentifier, int ranType) {
953         return disableCellBroadcastRange(messageIdentifier, messageIdentifier, ranType);
954     }
955 
enableCellBroadcastRange(int startMessageId, int endMessageId, int ranType)956     public boolean enableCellBroadcastRange(int startMessageId, int endMessageId, int ranType) {
957         mContext.enforceCallingPermission(android.Manifest.permission.RECEIVE_EMERGENCY_BROADCAST,
958                 "enabling cell broadcast range [" + startMessageId + "-" + endMessageId + "]. "
959                         + "ranType=" + ranType);
960         if (ranType == SmsCbMessage.MESSAGE_FORMAT_3GPP) {
961             return enableGsmBroadcastRange(startMessageId, endMessageId);
962         } else if (ranType == SmsCbMessage.MESSAGE_FORMAT_3GPP2) {
963             return enableCdmaBroadcastRange(startMessageId, endMessageId);
964         } else {
965             throw new IllegalArgumentException("Not a supported RAN Type");
966         }
967     }
968 
disableCellBroadcastRange(int startMessageId, int endMessageId, int ranType)969     public boolean disableCellBroadcastRange(int startMessageId, int endMessageId, int ranType) {
970         mContext.enforceCallingPermission(android.Manifest.permission.RECEIVE_EMERGENCY_BROADCAST,
971                 "disabling cell broadcast range [" + startMessageId + "-" + endMessageId
972                         + "]. ranType=" + ranType);
973         if (ranType == SmsCbMessage.MESSAGE_FORMAT_3GPP) {
974             return disableGsmBroadcastRange(startMessageId, endMessageId);
975         } else if (ranType == SmsCbMessage.MESSAGE_FORMAT_3GPP2)  {
976             return disableCdmaBroadcastRange(startMessageId, endMessageId);
977         } else {
978             throw new IllegalArgumentException("Not a supported RAN Type");
979         }
980     }
981 
982     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
enableGsmBroadcastRange(int startMessageId, int endMessageId)983     synchronized public boolean enableGsmBroadcastRange(int startMessageId, int endMessageId) {
984 
985         mContext.enforceCallingPermission(android.Manifest.permission.RECEIVE_EMERGENCY_BROADCAST,
986                 "Enabling cell broadcast SMS");
987 
988         String client = mContext.getPackageManager().getNameForUid(
989                 Binder.getCallingUid());
990 
991         String msg;
992         if (!mCellBroadcastRangeManager.enableRange(startMessageId, endMessageId, client)) {
993             msg = "Failed to add GSM cell broadcast channels range " + startMessageId
994                     + " to " + endMessageId;
995             log(msg);
996             mCellBroadcastLocalLog.log(msg);
997             return false;
998         }
999 
1000         if (DBG) {
1001             msg = "Added GSM cell broadcast channels range " + startMessageId
1002                     + " to " + endMessageId;
1003             log(msg);
1004             mCellBroadcastLocalLog.log(msg);
1005         }
1006 
1007         setCellBroadcastActivation(!mCellBroadcastRangeManager.isEmpty());
1008 
1009         return true;
1010     }
1011 
1012     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
disableGsmBroadcastRange(int startMessageId, int endMessageId)1013     synchronized public boolean disableGsmBroadcastRange(int startMessageId, int endMessageId) {
1014 
1015         mContext.enforceCallingPermission(android.Manifest.permission.RECEIVE_EMERGENCY_BROADCAST,
1016                 "Disabling cell broadcast SMS");
1017 
1018         String client = mContext.getPackageManager().getNameForUid(
1019                 Binder.getCallingUid());
1020 
1021         String msg;
1022         if (!mCellBroadcastRangeManager.disableRange(startMessageId, endMessageId, client)) {
1023             msg = "Failed to remove GSM cell broadcast channels range " + startMessageId
1024                     + " to " + endMessageId;
1025             log(msg);
1026             mCellBroadcastLocalLog.log(msg);
1027             return false;
1028         }
1029 
1030         if (DBG) {
1031             msg = "Removed GSM cell broadcast channels range " + startMessageId
1032                     + " to " + endMessageId;
1033             log(msg);
1034             mCellBroadcastLocalLog.log(msg);
1035         }
1036 
1037         setCellBroadcastActivation(!mCellBroadcastRangeManager.isEmpty());
1038 
1039         return true;
1040     }
1041 
1042     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
enableCdmaBroadcastRange(int startMessageId, int endMessageId)1043     synchronized public boolean enableCdmaBroadcastRange(int startMessageId, int endMessageId) {
1044 
1045         mContext.enforceCallingPermission(android.Manifest.permission.RECEIVE_EMERGENCY_BROADCAST,
1046                 "Enabling cdma broadcast SMS");
1047 
1048         String client = mContext.getPackageManager().getNameForUid(
1049                 Binder.getCallingUid());
1050 
1051         String msg;
1052         if (!mCdmaBroadcastRangeManager.enableRange(startMessageId, endMessageId, client)) {
1053             msg = "Failed to add cdma broadcast channels range " + startMessageId + " to "
1054                     + endMessageId;
1055             log(msg);
1056             mCellBroadcastLocalLog.log(msg);
1057             return false;
1058         }
1059 
1060         if (DBG) {
1061             msg = "Added cdma broadcast channels range " + startMessageId + " to " + endMessageId;
1062             log(msg);
1063             mCellBroadcastLocalLog.log(msg);
1064         }
1065 
1066         setCdmaBroadcastActivation(!mCdmaBroadcastRangeManager.isEmpty());
1067 
1068         return true;
1069     }
1070 
1071     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
disableCdmaBroadcastRange(int startMessageId, int endMessageId)1072     synchronized public boolean disableCdmaBroadcastRange(int startMessageId, int endMessageId) {
1073 
1074         mContext.enforceCallingPermission(android.Manifest.permission.RECEIVE_EMERGENCY_BROADCAST,
1075                 "Disabling cell broadcast SMS");
1076 
1077         String client = mContext.getPackageManager().getNameForUid(
1078                 Binder.getCallingUid());
1079 
1080         String msg;
1081         if (!mCdmaBroadcastRangeManager.disableRange(startMessageId, endMessageId, client)) {
1082             msg = "Failed to remove cdma broadcast channels range " + startMessageId + " to "
1083                     + endMessageId;
1084             log(msg);
1085             mCellBroadcastLocalLog.log(msg);
1086             return false;
1087         }
1088 
1089         if (DBG) {
1090             msg = "Removed cdma broadcast channels range " + startMessageId + " to " + endMessageId;
1091             log(msg);
1092             mCellBroadcastLocalLog.log(msg);
1093         }
1094 
1095         setCdmaBroadcastActivation(!mCdmaBroadcastRangeManager.isEmpty());
1096 
1097         return true;
1098     }
1099 
1100     /**
1101      * Reset all cell broadcast ranges. Previously enabled ranges will become invalid after this.
1102      */
1103     @RequiresPermission(android.Manifest.permission.MODIFY_CELL_BROADCASTS)
resetAllCellBroadcastRanges()1104     public void resetAllCellBroadcastRanges() {
1105         mContext.enforceCallingPermission(android.Manifest.permission.MODIFY_CELL_BROADCASTS,
1106                 "resetAllCellBroadcastRanges");
1107         mCdmaBroadcastRangeManager.clearRanges();
1108         mCellBroadcastRangeManager.clearRanges();
1109         log("Cell broadcast ranges reset.");
1110     }
1111 
1112     class CellBroadcastRangeManager extends IntRangeManager {
1113         private ArrayList<SmsBroadcastConfigInfo> mConfigList =
1114                 new ArrayList<SmsBroadcastConfigInfo>();
1115 
1116         /**
1117          * Called when the list of enabled ranges has changed. This will be
1118          * followed by zero or more calls to {@link #addRange} followed by
1119          * a call to {@link #finishUpdate}.
1120          */
startUpdate()1121         protected void startUpdate() {
1122             mConfigList.clear();
1123         }
1124 
1125         /**
1126          * Called after {@link #startUpdate} to indicate a range of enabled
1127          * values.
1128          * @param startId the first id included in the range
1129          * @param endId the last id included in the range
1130          */
addRange(int startId, int endId, boolean selected)1131         protected void addRange(int startId, int endId, boolean selected) {
1132             mConfigList.add(new SmsBroadcastConfigInfo(startId, endId,
1133                         SMS_CB_CODE_SCHEME_MIN, SMS_CB_CODE_SCHEME_MAX, selected));
1134         }
1135 
1136         /**
1137          * Called to indicate the end of a range update started by the
1138          * previous call to {@link #startUpdate}.
1139          * @return true if successful, false otherwise
1140          */
finishUpdate()1141         protected boolean finishUpdate() {
1142             if (mConfigList.isEmpty()) {
1143                 return true;
1144             } else {
1145                 SmsBroadcastConfigInfo[] configs =
1146                         mConfigList.toArray(new SmsBroadcastConfigInfo[mConfigList.size()]);
1147                 return setCellBroadcastConfig(configs);
1148             }
1149         }
1150     }
1151 
1152     class CdmaBroadcastRangeManager extends IntRangeManager {
1153         private ArrayList<CdmaSmsBroadcastConfigInfo> mConfigList =
1154                 new ArrayList<CdmaSmsBroadcastConfigInfo>();
1155 
1156         /**
1157          * Called when the list of enabled ranges has changed. This will be
1158          * followed by zero or more calls to {@link #addRange} followed by a
1159          * call to {@link #finishUpdate}.
1160          */
startUpdate()1161         protected void startUpdate() {
1162             mConfigList.clear();
1163         }
1164 
1165         /**
1166          * Called after {@link #startUpdate} to indicate a range of enabled
1167          * values.
1168          * @param startId the first id included in the range
1169          * @param endId the last id included in the range
1170          */
addRange(int startId, int endId, boolean selected)1171         protected void addRange(int startId, int endId, boolean selected) {
1172             mConfigList.add(new CdmaSmsBroadcastConfigInfo(startId, endId,
1173                     1, selected));
1174         }
1175 
1176         /**
1177          * Called to indicate the end of a range update started by the previous
1178          * call to {@link #startUpdate}.
1179          * @return true if successful, false otherwise
1180          */
finishUpdate()1181         protected boolean finishUpdate() {
1182             if (mConfigList.isEmpty()) {
1183                 return true;
1184             } else {
1185                 CdmaSmsBroadcastConfigInfo[] configs =
1186                         mConfigList.toArray(new CdmaSmsBroadcastConfigInfo[mConfigList.size()]);
1187                 return setCdmaBroadcastConfig(configs);
1188             }
1189         }
1190     }
1191 
1192     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
setCellBroadcastConfig(SmsBroadcastConfigInfo[] configs)1193     private boolean setCellBroadcastConfig(SmsBroadcastConfigInfo[] configs) {
1194         if (DBG) {
1195             log("Calling setGsmBroadcastConfig with " + configs.length + " configurations");
1196         }
1197         enforceNotOnHandlerThread("setCellBroadcastConfig");
1198         Request setRequest = new Request();
1199         synchronized (setRequest) {
1200             Message response = mHandler.obtainMessage(EVENT_SET_BROADCAST_CONFIG_DONE, setRequest);
1201 
1202             mPhone.mCi.setGsmBroadcastConfig(configs, response);
1203 
1204             waitForResult(setRequest);
1205         }
1206 
1207         return (boolean) setRequest.mResult;
1208     }
1209 
setCellBroadcastActivation(boolean activate)1210     private boolean setCellBroadcastActivation(boolean activate) {
1211         if (DBG) {
1212             log("Calling setCellBroadcastActivation(" + activate + ')');
1213         }
1214 
1215         enforceNotOnHandlerThread("setCellBroadcastConfig");
1216         Request setRequest = new Request();
1217         synchronized (setRequest) {
1218             Message response = mHandler.obtainMessage(EVENT_SET_BROADCAST_ACTIVATION_DONE,
1219                     setRequest);
1220 
1221             mPhone.mCi.setGsmBroadcastActivation(activate, response);
1222             waitForResult(setRequest);
1223         }
1224 
1225         return (boolean) setRequest.mResult;
1226     }
1227 
1228     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
setCdmaBroadcastConfig(CdmaSmsBroadcastConfigInfo[] configs)1229     private boolean setCdmaBroadcastConfig(CdmaSmsBroadcastConfigInfo[] configs) {
1230         if (DBG) {
1231             log("Calling setCdmaBroadcastConfig with " + configs.length + " configurations");
1232         }
1233 
1234         enforceNotOnHandlerThread("setCdmaBroadcastConfig");
1235         Request setRequest = new Request();
1236         synchronized (setRequest) {
1237             Message response = mHandler.obtainMessage(EVENT_SET_BROADCAST_CONFIG_DONE, setRequest);
1238 
1239             mPhone.mCi.setCdmaBroadcastConfig(configs, response);
1240 
1241             waitForResult(setRequest);
1242         }
1243 
1244         return (boolean) setRequest.mResult;
1245     }
1246 
setCdmaBroadcastActivation(boolean activate)1247     private boolean setCdmaBroadcastActivation(boolean activate) {
1248         if (DBG) {
1249             log("Calling setCdmaBroadcastActivation(" + activate + ")");
1250         }
1251 
1252         enforceNotOnHandlerThread("setCdmaBroadcastActivation");
1253         Request setRequest = new Request();
1254         synchronized (setRequest) {
1255             Message response = mHandler.obtainMessage(EVENT_SET_BROADCAST_ACTIVATION_DONE,
1256                     setRequest);
1257 
1258             mPhone.mCi.setCdmaBroadcastActivation(activate, response);
1259 
1260             waitForResult(setRequest);
1261         }
1262 
1263         return (boolean) setRequest.mResult;
1264     }
1265 
1266     @UnsupportedAppUsage
log(String msg)1267     protected void log(String msg) {
1268         Rlog.d(LOG_TAG, msg);
1269     }
1270 
loge(String msg)1271     protected void loge(String msg) {
1272         Rlog.e(LOG_TAG, msg);
1273     }
1274 
loge(String msg, Throwable e)1275     protected void loge(String msg, Throwable e) {
1276         Rlog.e(LOG_TAG, msg, e);
1277     }
1278 
1279     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
isImsSmsSupported()1280     public boolean isImsSmsSupported() {
1281         return mDispatchersController.isIms();
1282     }
1283 
1284     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
getImsSmsFormat()1285     public String getImsSmsFormat() {
1286         return mDispatchersController.getImsSmsFormat();
1287     }
1288 
1289     /**
1290      * @deprecated Use {@link #sendStoredText(String, String, Uri, String, PendingIntent,
1291      * PendingIntent)} instead
1292      */
1293     @Deprecated
1294     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
sendStoredText(String callingPkg, Uri messageUri, String scAddress, PendingIntent sentIntent, PendingIntent deliveryIntent)1295     public void sendStoredText(String callingPkg, Uri messageUri, String scAddress,
1296             PendingIntent sentIntent, PendingIntent deliveryIntent) {
1297         sendStoredText(callingPkg, null, messageUri, scAddress, sentIntent, deliveryIntent);
1298     }
1299 
sendStoredText(String callingPkg, String callingAttributionTag, Uri messageUri, String scAddress, PendingIntent sentIntent, PendingIntent deliveryIntent)1300     public void sendStoredText(String callingPkg, String callingAttributionTag,
1301             Uri messageUri, String scAddress, PendingIntent sentIntent,
1302             PendingIntent deliveryIntent) {
1303         if (!mSmsPermissions.checkCallingCanSendSms(callingPkg, callingAttributionTag,
1304                 "Sending SMS message")) {
1305             returnUnspecifiedFailure(sentIntent);
1306             return;
1307         }
1308         if (Rlog.isLoggable("SMS", Log.VERBOSE)) {
1309             log("sendStoredText: scAddr=" + scAddress + " messageUri=" + messageUri
1310                     + " sentIntent=" + sentIntent + " deliveryIntent=" + deliveryIntent);
1311         }
1312         final ContentResolver resolver = mContext.getContentResolver();
1313         if (!isFailedOrDraft(resolver, messageUri)) {
1314             loge("sendStoredText: not FAILED or DRAFT message");
1315             returnUnspecifiedFailure(sentIntent);
1316             return;
1317         }
1318         final String[] textAndAddress = loadTextAndAddress(resolver, messageUri);
1319         if (textAndAddress == null) {
1320             loge("sendStoredText: can not load text");
1321             returnUnspecifiedFailure(sentIntent);
1322             return;
1323         }
1324         notifyIfOutgoingEmergencySms(textAndAddress[1]);
1325         textAndAddress[1] = filterDestAddress(textAndAddress[1]);
1326         mDispatchersController.sendText(textAndAddress[1], scAddress, textAndAddress[0],
1327                 sentIntent, deliveryIntent, messageUri, callingPkg,
1328                 true /* persistMessageForNonDefaultSmsApp */, SMS_MESSAGE_PRIORITY_NOT_SPECIFIED,
1329                 false /* expectMore */, SMS_MESSAGE_PERIOD_NOT_SPECIFIED, false /* isForVvm */,
1330                 0L /* messageId */);
1331     }
1332 
1333     /**
1334      * @deprecated Use {@link #sendStoredMultipartText(String, String, Uri, String, List, List)}
1335      * instead
1336      */
1337     @Deprecated
1338     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
sendStoredMultipartText(String callingPkg, Uri messageUri, String scAddress, List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents)1339     public void sendStoredMultipartText(String callingPkg, Uri messageUri, String scAddress,
1340             List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) {
1341         sendStoredMultipartText(callingPkg, null, messageUri, scAddress, sentIntents,
1342                 deliveryIntents);
1343     }
1344 
sendStoredMultipartText(String callingPkg, String callingAttributionTag, Uri messageUri, String scAddress, List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents)1345     public void sendStoredMultipartText(String callingPkg,
1346             String callingAttributionTag, Uri messageUri, String scAddress,
1347             List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) {
1348         if (!mSmsPermissions.checkCallingCanSendSms(callingPkg, callingAttributionTag,
1349                 "Sending SMS message")) {
1350             returnUnspecifiedFailure(sentIntents);
1351             return;
1352         }
1353         final ContentResolver resolver = mContext.getContentResolver();
1354         if (!isFailedOrDraft(resolver, messageUri)) {
1355             loge("sendStoredMultipartText: not FAILED or DRAFT message");
1356             returnUnspecifiedFailure(sentIntents);
1357             return;
1358         }
1359         final String[] textAndAddress = loadTextAndAddress(resolver, messageUri);
1360         if (textAndAddress == null) {
1361             loge("sendStoredMultipartText: can not load text");
1362             returnUnspecifiedFailure(sentIntents);
1363             return;
1364         }
1365         final ArrayList<String> parts = SmsManager.getDefault().divideMessage(textAndAddress[0]);
1366         if (parts == null || parts.size() < 1) {
1367             loge("sendStoredMultipartText: can not divide text");
1368             returnUnspecifiedFailure(sentIntents);
1369             return;
1370         }
1371         notifyIfOutgoingEmergencySms(textAndAddress[1]);
1372         textAndAddress[1] = filterDestAddress(textAndAddress[1]);
1373 
1374         if (parts.size() > 1 && parts.size() < 10 && !SmsMessage.hasEmsSupport()) {
1375             for (int i = 0; i < parts.size(); i++) {
1376                 // If EMS is not supported, we have to break down EMS into single segment SMS
1377                 // and add page info " x/y".
1378                 String singlePart = parts.get(i);
1379                 if (SmsMessage.shouldAppendPageNumberAsPrefix()) {
1380                     singlePart = String.valueOf(i + 1) + '/' + parts.size() + ' ' + singlePart;
1381                 } else {
1382                     singlePart = singlePart.concat(' ' + String.valueOf(i + 1) + '/'
1383                             + parts.size());
1384                 }
1385 
1386                 PendingIntent singleSentIntent = null;
1387                 if (sentIntents != null && sentIntents.size() > i) {
1388                     singleSentIntent = sentIntents.get(i);
1389                 }
1390 
1391                 PendingIntent singleDeliveryIntent = null;
1392                 if (deliveryIntents != null && deliveryIntents.size() > i) {
1393                     singleDeliveryIntent = deliveryIntents.get(i);
1394                 }
1395 
1396                 mDispatchersController.sendText(textAndAddress[1], scAddress, singlePart,
1397                         singleSentIntent, singleDeliveryIntent, messageUri, callingPkg,
1398                         true  /* persistMessageForNonDefaultSmsApp */,
1399                         SMS_MESSAGE_PRIORITY_NOT_SPECIFIED,
1400                         false /* expectMore */, SMS_MESSAGE_PERIOD_NOT_SPECIFIED,
1401                         false /* isForVvm */, 0L /* messageId */);
1402             }
1403             return;
1404         }
1405 
1406         mDispatchersController.sendMultipartText(
1407                 textAndAddress[1], // destAddress
1408                 scAddress,
1409                 parts,
1410                 (ArrayList<PendingIntent>) sentIntents,
1411                 (ArrayList<PendingIntent>) deliveryIntents,
1412                 messageUri,
1413                 callingPkg,
1414                 true  /* persistMessageForNonDefaultSmsApp */,
1415                 SMS_MESSAGE_PRIORITY_NOT_SPECIFIED,
1416                 false /* expectMore */,
1417                 SMS_MESSAGE_PERIOD_NOT_SPECIFIED,
1418                 0L /* messageId */);
1419     }
1420 
getSmsCapacityOnIcc(String callingPackage, String callingFeatureId)1421     public int getSmsCapacityOnIcc(String callingPackage, String callingFeatureId) {
1422         if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
1423                 mContext, mPhone.getSubId(), callingPackage, callingFeatureId,
1424                 "getSmsCapacityOnIcc")) {
1425             return 0;
1426         }
1427 
1428         int numberOnIcc = 0;
1429         if (mPhone.getIccRecordsLoaded()) {
1430             final UiccProfile uiccProfile = UiccController.getInstance()
1431                     .getUiccProfileForPhone(mPhone.getPhoneId());
1432             if(uiccProfile != null) {
1433                 numberOnIcc = uiccProfile.getIccRecords().getSmsCapacityOnIcc();
1434             } else {
1435                 loge("uiccProfile is null");
1436             }
1437         } else {
1438             loge("getSmsCapacityOnIcc - aborting, no icc card present.");
1439         }
1440 
1441         log("getSmsCapacityOnIcc().numberOnIcc = " + numberOnIcc);
1442         return numberOnIcc;
1443     }
1444 
isFailedOrDraft(ContentResolver resolver, Uri messageUri)1445     private boolean isFailedOrDraft(ContentResolver resolver, Uri messageUri) {
1446         // Clear the calling identity and query the database using the phone user id
1447         // Otherwise the AppOps check in TelephonyProvider would complain about mismatch
1448         // between the calling uid and the package uid
1449         final long identity = Binder.clearCallingIdentity();
1450         Cursor cursor = null;
1451         try {
1452             cursor = resolver.query(
1453                     messageUri,
1454                     new String[]{ Telephony.Sms.TYPE },
1455                     null/*selection*/,
1456                     null/*selectionArgs*/,
1457                     null/*sortOrder*/);
1458             if (cursor != null && cursor.moveToFirst()) {
1459                 final int type = cursor.getInt(0);
1460                 return type == Telephony.Sms.MESSAGE_TYPE_DRAFT
1461                         || type == Telephony.Sms.MESSAGE_TYPE_FAILED;
1462             }
1463         } catch (SQLiteException e) {
1464             loge("isFailedOrDraft: query message type failed", e);
1465         } finally {
1466             if (cursor != null) {
1467                 cursor.close();
1468             }
1469             Binder.restoreCallingIdentity(identity);
1470         }
1471         return false;
1472     }
1473 
1474     // Return an array including both the SMS text (0) and address (1)
loadTextAndAddress(ContentResolver resolver, Uri messageUri)1475     private String[] loadTextAndAddress(ContentResolver resolver, Uri messageUri) {
1476         // Clear the calling identity and query the database using the phone user id
1477         // Otherwise the AppOps check in TelephonyProvider would complain about mismatch
1478         // between the calling uid and the package uid
1479         final long identity = Binder.clearCallingIdentity();
1480         Cursor cursor = null;
1481         try {
1482             cursor = resolver.query(
1483                     messageUri,
1484                     new String[]{
1485                             Telephony.Sms.BODY,
1486                             Telephony.Sms.ADDRESS
1487                     },
1488                     null/*selection*/,
1489                     null/*selectionArgs*/,
1490                     null/*sortOrder*/);
1491             if (cursor != null && cursor.moveToFirst()) {
1492                 return new String[]{ cursor.getString(0), cursor.getString(1) };
1493             }
1494         } catch (SQLiteException e) {
1495             loge("loadText: query message text failed", e);
1496         } finally {
1497             if (cursor != null) {
1498                 cursor.close();
1499             }
1500             Binder.restoreCallingIdentity(identity);
1501         }
1502         return null;
1503     }
1504 
1505     @VisibleForTesting
notifyIfOutgoingEmergencySms(String destAddr)1506     public void notifyIfOutgoingEmergencySms(String destAddr) {
1507         Phone[] allPhones = mPhoneFactoryProxy.getPhones();
1508         EmergencyNumber emergencyNumber = mPhone.getEmergencyNumberTracker().getEmergencyNumber(
1509                 destAddr);
1510         if (emergencyNumber != null) {
1511             mPhone.notifyOutgoingEmergencySms(emergencyNumber);
1512         } else if (allPhones.length > 1) {
1513             // If there are multiple active SIMs, check all instances:
1514             for (Phone phone : allPhones) {
1515                 // If the current iteration was already checked, skip:
1516                 if (phone.getPhoneId() == mPhone.getPhoneId()) {
1517                     continue;
1518                 }
1519                 emergencyNumber = phone.getEmergencyNumberTracker()
1520                         .getEmergencyNumber(destAddr);
1521                 if (emergencyNumber != null) {
1522                     mPhone.notifyOutgoingEmergencySms(emergencyNumber);
1523                     break;
1524                 }
1525             }
1526         }
1527     }
1528 
returnUnspecifiedFailure(PendingIntent pi)1529     private void returnUnspecifiedFailure(PendingIntent pi) {
1530         if (pi != null) {
1531             try {
1532                 pi.send(SmsManager.RESULT_ERROR_GENERIC_FAILURE);
1533             } catch (PendingIntent.CanceledException e) {
1534                 // ignore
1535             }
1536         }
1537     }
1538 
returnUnspecifiedFailure(List<PendingIntent> pis)1539     private void returnUnspecifiedFailure(List<PendingIntent> pis) {
1540         if (pis == null) {
1541             return;
1542         }
1543         for (PendingIntent pi : pis) {
1544             returnUnspecifiedFailure(pi);
1545         }
1546     }
1547 
1548     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
filterDestAddress(String destAddr)1549     private String filterDestAddress(String destAddr) {
1550         String result = SmsNumberUtils.filterDestAddr(mContext, mPhone.getSubId(), destAddr);
1551         return result != null ? result : destAddr;
1552     }
1553 
waitForResult(Request request)1554     private void waitForResult(Request request) {
1555         synchronized (request) {
1556             while (!request.mStatus.get()) {
1557                 try {
1558                     request.wait();
1559                 } catch (InterruptedException e) {
1560                     log("Interrupted while waiting for result");
1561                 }
1562             }
1563         }
1564     }
1565 
1566     /**
1567      * Get InboundSmsHandler for the phone.
1568      */
getInboundSmsHandler(boolean is3gpp2)1569     public InboundSmsHandler getInboundSmsHandler(boolean is3gpp2) {
1570         return mDispatchersController.getInboundSmsHandler(is3gpp2);
1571     }
1572 
dump(FileDescriptor fd, PrintWriter pw, String[] args)1573     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1574         pw.println("Enabled GSM channels: " + mCellBroadcastRangeManager);
1575         pw.println("Enabled CDMA channels: " + mCdmaBroadcastRangeManager);
1576         pw.println("CellBroadcast log:");
1577         mCellBroadcastLocalLog.dump(fd, pw, args);
1578         pw.println("SMS dispatcher controller log:");
1579         mDispatchersController.dump(fd, pw, args);
1580         pw.flush();
1581     }
1582 }
1583