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