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