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