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