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.content.ContentResolver;
27 import android.content.Context;
28 import android.content.Intent;
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.Message;
37 import android.os.UserManager;
38 import android.provider.Telephony;
39 import android.service.carrier.CarrierMessagingService;
40 import android.telephony.Rlog;
41 import android.telephony.SmsManager;
42 import android.telephony.SmsMessage;
43 import android.telephony.TelephonyManager;
44 import android.util.Log;
45 
46 import com.android.internal.telephony.cdma.CdmaSmsBroadcastConfigInfo;
47 import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo;
48 import com.android.internal.telephony.uicc.IccConstants;
49 import com.android.internal.telephony.uicc.IccFileHandler;
50 import com.android.internal.telephony.uicc.IccUtils;
51 import com.android.internal.telephony.uicc.UiccController;
52 import com.android.internal.util.HexDump;
53 
54 import java.util.ArrayList;
55 import java.util.Arrays;
56 import java.util.List;
57 
58 /**
59  * IccSmsInterfaceManager to provide an inter-process communication to
60  * access Sms in Icc.
61  */
62 public class IccSmsInterfaceManager {
63     static final String LOG_TAG = "IccSmsInterfaceManager";
64     static final boolean DBG = true;
65 
66     protected final Object mLock = new Object();
67     protected boolean mSuccess;
68     private List<SmsRawData> mSms;
69 
70     private CellBroadcastRangeManager mCellBroadcastRangeManager =
71             new CellBroadcastRangeManager();
72     private CdmaBroadcastRangeManager mCdmaBroadcastRangeManager =
73             new CdmaBroadcastRangeManager();
74 
75     private static final int EVENT_LOAD_DONE = 1;
76     private static final int EVENT_UPDATE_DONE = 2;
77     protected static final int EVENT_SET_BROADCAST_ACTIVATION_DONE = 3;
78     protected static final int EVENT_SET_BROADCAST_CONFIG_DONE = 4;
79     private static final int SMS_CB_CODE_SCHEME_MIN = 0;
80     private static final int SMS_CB_CODE_SCHEME_MAX = 255;
81 
82     protected Phone mPhone;
83     final protected Context mContext;
84     final protected AppOpsManager mAppOps;
85     final private UserManager mUserManager;
86     protected SMSDispatcher mDispatcher;
87 
88     protected Handler mHandler = new Handler() {
89         @Override
90         public void handleMessage(Message msg) {
91             AsyncResult ar;
92 
93             switch (msg.what) {
94                 case EVENT_UPDATE_DONE:
95                     ar = (AsyncResult) msg.obj;
96                     synchronized (mLock) {
97                         mSuccess = (ar.exception == null);
98                         mLock.notifyAll();
99                     }
100                     break;
101                 case EVENT_LOAD_DONE:
102                     ar = (AsyncResult)msg.obj;
103                     synchronized (mLock) {
104                         if (ar.exception == null) {
105                             mSms = buildValidRawData((ArrayList<byte[]>) ar.result);
106                             //Mark SMS as read after importing it from card.
107                             markMessagesAsRead((ArrayList<byte[]>) ar.result);
108                         } else {
109                             if (Rlog.isLoggable("SMS", Log.DEBUG)) {
110                                 log("Cannot load Sms records");
111                             }
112                             mSms = null;
113                         }
114                         mLock.notifyAll();
115                     }
116                     break;
117                 case EVENT_SET_BROADCAST_ACTIVATION_DONE:
118                 case EVENT_SET_BROADCAST_CONFIG_DONE:
119                     ar = (AsyncResult) msg.obj;
120                     synchronized (mLock) {
121                         mSuccess = (ar.exception == null);
122                         mLock.notifyAll();
123                     }
124                     break;
125             }
126         }
127     };
128 
IccSmsInterfaceManager(Phone phone)129     protected IccSmsInterfaceManager(Phone phone) {
130         mPhone = phone;
131         mContext = phone.getContext();
132         mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
133         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
134         mDispatcher = new ImsSMSDispatcher(phone,
135                 phone.mSmsStorageMonitor, phone.mSmsUsageMonitor);
136     }
137 
markMessagesAsRead(ArrayList<byte[]> messages)138     protected void markMessagesAsRead(ArrayList<byte[]> messages) {
139         if (messages == null) {
140             return;
141         }
142 
143         //IccFileHandler can be null, if icc card is absent.
144         IccFileHandler fh = mPhone.getIccFileHandler();
145         if (fh == null) {
146             //shouldn't really happen, as messages are marked as read, only
147             //after importing it from icc.
148             if (Rlog.isLoggable("SMS", Log.DEBUG)) {
149                 log("markMessagesAsRead - aborting, no icc card present.");
150             }
151             return;
152         }
153 
154         int count = messages.size();
155 
156         for (int i = 0; i < count; i++) {
157              byte[] ba = messages.get(i);
158              if (ba[0] == STATUS_ON_ICC_UNREAD) {
159                  int n = ba.length;
160                  byte[] nba = new byte[n - 1];
161                  System.arraycopy(ba, 1, nba, 0, n - 1);
162                  byte[] record = makeSmsRecordData(STATUS_ON_ICC_READ, nba);
163                  fh.updateEFLinearFixed(IccConstants.EF_SMS, i + 1, record, null, null);
164                  if (Rlog.isLoggable("SMS", Log.DEBUG)) {
165                      log("SMS " + (i + 1) + " marked as read");
166                  }
167              }
168         }
169     }
170 
updatePhoneObject(Phone phone)171     protected void updatePhoneObject(Phone phone) {
172         mPhone = phone;
173         mDispatcher.updatePhoneObject(phone);
174     }
175 
enforceReceiveAndSend(String message)176     protected void enforceReceiveAndSend(String message) {
177         mContext.enforceCallingOrSelfPermission(
178                 Manifest.permission.RECEIVE_SMS, message);
179         mContext.enforceCallingOrSelfPermission(
180                 Manifest.permission.SEND_SMS, message);
181     }
182 
183     /**
184      * Update the specified message on the Icc.
185      *
186      * @param index record index of message to update
187      * @param status new message status (STATUS_ON_ICC_READ,
188      *                  STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT,
189      *                  STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE)
190      * @param pdu the raw PDU to store
191      * @return success or not
192      *
193      */
194 
195     public boolean
updateMessageOnIccEf(String callingPackage, int index, int status, byte[] pdu)196     updateMessageOnIccEf(String callingPackage, int index, int status, byte[] pdu) {
197         if (DBG) log("updateMessageOnIccEf: index=" + index +
198                 " status=" + status + " ==> " +
199                 "("+ Arrays.toString(pdu) + ")");
200         enforceReceiveAndSend("Updating message on Icc");
201         if (mAppOps.noteOp(AppOpsManager.OP_WRITE_ICC_SMS, Binder.getCallingUid(),
202                 callingPackage) != AppOpsManager.MODE_ALLOWED) {
203             return false;
204         }
205         synchronized(mLock) {
206             mSuccess = false;
207             Message response = mHandler.obtainMessage(EVENT_UPDATE_DONE);
208 
209             if (status == STATUS_ON_ICC_FREE) {
210                 // RIL_REQUEST_DELETE_SMS_ON_SIM vs RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM
211                 // Special case FREE: call deleteSmsOnSim/Ruim instead of
212                 // manipulating the record
213                 // Will eventually fail if icc card is not present.
214                 if (PhoneConstants.PHONE_TYPE_GSM == mPhone.getPhoneType()) {
215                     mPhone.mCi.deleteSmsOnSim(index, response);
216                 } else {
217                     mPhone.mCi.deleteSmsOnRuim(index, response);
218                 }
219             } else {
220                 //IccFilehandler can be null if ICC card is not present.
221                 IccFileHandler fh = mPhone.getIccFileHandler();
222                 if (fh == null) {
223                     response.recycle();
224                     return mSuccess; /* is false */
225                 }
226                 byte[] record = makeSmsRecordData(status, pdu);
227                 fh.updateEFLinearFixed(
228                         IccConstants.EF_SMS,
229                         index, record, null, response);
230             }
231             try {
232                 mLock.wait();
233             } catch (InterruptedException e) {
234                 log("interrupted while trying to update by index");
235             }
236         }
237         return mSuccess;
238     }
239 
240     /**
241      * Copy a raw SMS PDU to the Icc.
242      *
243      * @param pdu the raw PDU to store
244      * @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD,
245      *               STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT)
246      * @return success or not
247      *
248      */
copyMessageToIccEf(String callingPackage, int status, byte[] pdu, byte[] smsc)249     public boolean copyMessageToIccEf(String callingPackage, int status, byte[] pdu, byte[] smsc) {
250         //NOTE smsc not used in RUIM
251         if (DBG) log("copyMessageToIccEf: status=" + status + " ==> " +
252                 "pdu=("+ Arrays.toString(pdu) +
253                 "), smsc=(" + Arrays.toString(smsc) +")");
254         enforceReceiveAndSend("Copying message to Icc");
255         if (mAppOps.noteOp(AppOpsManager.OP_WRITE_ICC_SMS, Binder.getCallingUid(),
256                 callingPackage) != AppOpsManager.MODE_ALLOWED) {
257             return false;
258         }
259         synchronized(mLock) {
260             mSuccess = false;
261             Message response = mHandler.obtainMessage(EVENT_UPDATE_DONE);
262 
263             //RIL_REQUEST_WRITE_SMS_TO_SIM vs RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM
264             if (PhoneConstants.PHONE_TYPE_GSM == mPhone.getPhoneType()) {
265                 mPhone.mCi.writeSmsToSim(status, IccUtils.bytesToHexString(smsc),
266                         IccUtils.bytesToHexString(pdu), response);
267             } else {
268                 mPhone.mCi.writeSmsToRuim(status, IccUtils.bytesToHexString(pdu),
269                         response);
270             }
271 
272             try {
273                 mLock.wait();
274             } catch (InterruptedException e) {
275                 log("interrupted while trying to update by index");
276             }
277         }
278         return mSuccess;
279     }
280 
281     /**
282      * Retrieves all messages currently stored on Icc.
283      *
284      * @return list of SmsRawData of all sms on Icc
285      */
286 
getAllMessagesFromIccEf(String callingPackage)287     public List<SmsRawData> getAllMessagesFromIccEf(String callingPackage) {
288         if (DBG) log("getAllMessagesFromEF");
289 
290         mContext.enforceCallingOrSelfPermission(
291                 Manifest.permission.RECEIVE_SMS,
292                 "Reading messages from Icc");
293         if (mAppOps.noteOp(AppOpsManager.OP_READ_ICC_SMS, Binder.getCallingUid(),
294                 callingPackage) != AppOpsManager.MODE_ALLOWED) {
295             return new ArrayList<SmsRawData>();
296         }
297         synchronized(mLock) {
298 
299             IccFileHandler fh = mPhone.getIccFileHandler();
300             if (fh == null) {
301                 Rlog.e(LOG_TAG, "Cannot load Sms records. No icc card?");
302                 mSms = null;
303                 return mSms;
304             }
305 
306             Message response = mHandler.obtainMessage(EVENT_LOAD_DONE);
307             fh.loadEFLinearFixedAll(IccConstants.EF_SMS, response);
308 
309             try {
310                 mLock.wait();
311             } catch (InterruptedException e) {
312                 log("interrupted while trying to load from the Icc");
313             }
314         }
315         return mSms;
316     }
317 
318     /**
319      * A permissions check before passing to {@link IccSmsInterfaceManager#sendDataInternal}.
320      * This method checks if the calling package or itself has the permission to send the data sms.
321      */
sendDataWithSelfPermissions(String callingPackage, String destAddr, String scAddr, int destPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent)322     public void sendDataWithSelfPermissions(String callingPackage, String destAddr, String scAddr,
323             int destPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) {
324         mPhone.getContext().enforceCallingOrSelfPermission(
325                 Manifest.permission.SEND_SMS,
326                 "Sending SMS message");
327         sendDataInternal(callingPackage, destAddr, scAddr, destPort, data, sentIntent,
328                 deliveryIntent);
329     }
330 
331     /**
332      * A permissions check before passing to {@link IccSmsInterfaceManager#sendDataInternal}.
333      * This method checks only if the calling package has the permission to send the data sms.
334      */
sendData(String callingPackage, String destAddr, String scAddr, int destPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent)335     public void sendData(String callingPackage, String destAddr, String scAddr, int destPort,
336             byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) {
337         mPhone.getContext().enforceCallingPermission(
338                 Manifest.permission.SEND_SMS,
339                 "Sending SMS message");
340         sendDataInternal(callingPackage, destAddr, scAddr, destPort, data, sentIntent,
341                 deliveryIntent);
342     }
343 
344     /**
345      * Send a data based SMS to a specific application port.
346      *
347      * @param destAddr the address to send the message to
348      * @param scAddr is the service center address or null to use
349      *  the current default SMSC
350      * @param destPort the port to deliver the message to
351      * @param data the body of the message to send
352      * @param sentIntent if not NULL this <code>PendingIntent</code> is
353      *  broadcast when the message is successfully sent, or failed.
354      *  The result code will be <code>Activity.RESULT_OK<code> for success,
355      *  or one of these errors:<br>
356      *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
357      *  <code>RESULT_ERROR_RADIO_OFF</code><br>
358      *  <code>RESULT_ERROR_NULL_PDU</code><br>
359      *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
360      *  the extra "errorCode" containing a radio technology specific value,
361      *  generally only useful for troubleshooting.<br>
362      *  The per-application based SMS control checks sentIntent. If sentIntent
363      *  is NULL the caller will be checked against all unknown applications,
364      *  which cause smaller number of SMS to be sent in checking period.
365      * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
366      *  broadcast when the message is delivered to the recipient.  The
367      *  raw pdu of the status report is in the extended data ("pdu").
368      */
369 
sendDataInternal(String callingPackage, String destAddr, String scAddr, int destPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent)370     private void sendDataInternal(String callingPackage, String destAddr, String scAddr,
371             int destPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) {
372         if (Rlog.isLoggable("SMS", Log.VERBOSE)) {
373             log("sendData: destAddr=" + destAddr + " scAddr=" + scAddr + " destPort=" +
374                 destPort + " data='"+ HexDump.toHexString(data)  + "' sentIntent=" +
375                 sentIntent + " deliveryIntent=" + deliveryIntent);
376         }
377         if (mAppOps.noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(),
378                 callingPackage) != AppOpsManager.MODE_ALLOWED) {
379             return;
380         }
381         destAddr = filterDestAddress(destAddr);
382         mDispatcher.sendData(destAddr, scAddr, destPort, data, sentIntent, deliveryIntent);
383     }
384 
385     /**
386      * A permissions check before passing to {@link IccSmsInterfaceManager#sendTextInternal}.
387      * This method checks only if the calling package has the permission to send the sms.
388      */
sendText(String callingPackage, String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean persistMessageForNonDefaultSmsApp)389     public void sendText(String callingPackage, String destAddr, String scAddr,
390             String text, PendingIntent sentIntent, PendingIntent deliveryIntent,
391             boolean persistMessageForNonDefaultSmsApp) {
392         mPhone.getContext().enforceCallingPermission(
393                 Manifest.permission.SEND_SMS,
394                 "Sending SMS message");
395         sendTextInternal(callingPackage, destAddr, scAddr, text, sentIntent, deliveryIntent,
396             persistMessageForNonDefaultSmsApp);
397     }
398 
399     /**
400      * A permissions check before passing to {@link IccSmsInterfaceManager#sendTextInternal}.
401      * This method checks if the calling package or itself has the permission to send the sms.
402      */
sendTextWithSelfPermissions(String callingPackage, String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean persistMessage)403     public void sendTextWithSelfPermissions(String callingPackage, String destAddr, String scAddr,
404             String text, PendingIntent sentIntent, PendingIntent deliveryIntent,
405             boolean persistMessage) {
406         mPhone.getContext().enforceCallingOrSelfPermission(
407                 Manifest.permission.SEND_SMS,
408                 "Sending SMS message");
409         sendTextInternal(callingPackage, destAddr, scAddr, text, sentIntent, deliveryIntent,
410             persistMessage);
411     }
412 
413     /**
414      * Send a text based SMS.
415      *
416      * @param destAddr the address to send the message to
417      * @param scAddr is the service center address or null to use
418      *  the current default SMSC
419      * @param text the body of the message to send
420      * @param sentIntent if not NULL this <code>PendingIntent</code> is
421      *  broadcast when the message is successfully sent, or failed.
422      *  The result code will be <code>Activity.RESULT_OK<code> for success,
423      *  or one of these errors:<br>
424      *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
425      *  <code>RESULT_ERROR_RADIO_OFF</code><br>
426      *  <code>RESULT_ERROR_NULL_PDU</code><br>
427      *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
428      *  the extra "errorCode" containing a radio technology specific value,
429      *  generally only useful for troubleshooting.<br>
430      *  The per-application based SMS control checks sentIntent. If sentIntent
431      *  is NULL the caller will be checked against all unknown applications,
432      *  which cause smaller number of SMS to be sent in checking period.
433      * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
434      *  broadcast when the message is delivered to the recipient.  The
435      *  raw pdu of the status report is in the extended data ("pdu").
436      */
437 
sendTextInternal(String callingPackage, String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean persistMessageForNonDefaultSmsApp)438     private void sendTextInternal(String callingPackage, String destAddr, String scAddr,
439             String text, PendingIntent sentIntent, PendingIntent deliveryIntent,
440             boolean persistMessageForNonDefaultSmsApp) {
441         if (Rlog.isLoggable("SMS", Log.VERBOSE)) {
442             log("sendText: destAddr=" + destAddr + " scAddr=" + scAddr +
443                 " text='"+ text + "' sentIntent=" +
444                 sentIntent + " deliveryIntent=" + deliveryIntent);
445         }
446         if (mAppOps.noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(),
447                 callingPackage) != AppOpsManager.MODE_ALLOWED) {
448             return;
449         }
450         if (!persistMessageForNonDefaultSmsApp) {
451             enforcePrivilegedAppPermissions();
452         }
453         destAddr = filterDestAddress(destAddr);
454         mDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent,
455                 null/*messageUri*/, callingPackage, persistMessageForNonDefaultSmsApp);
456     }
457 
458     /**
459      * Inject an SMS PDU into the android application framework.
460      *
461      * @param pdu is the byte array of pdu to be injected into android application framework
462      * @param format is the format of SMS pdu (3gpp or 3gpp2)
463      * @param receivedIntent if not NULL this <code>PendingIntent</code> is
464      *  broadcast when the message is successfully received by the
465      *  android application framework. This intent is broadcasted at
466      *  the same time an SMS received from radio is acknowledged back.
467      */
injectSmsPdu(byte[] pdu, String format, PendingIntent receivedIntent)468     public void injectSmsPdu(byte[] pdu, String format, PendingIntent receivedIntent) {
469         enforcePrivilegedAppPermissions();
470         if (Rlog.isLoggable("SMS", Log.VERBOSE)) {
471             log("pdu: " + pdu +
472                 "\n format=" + format +
473                 "\n receivedIntent=" + receivedIntent);
474         }
475         mDispatcher.injectSmsPdu(pdu, format, receivedIntent);
476     }
477 
478     /**
479      * Send a multi-part text based SMS.
480      *
481      * @param destAddr the address to send the message to
482      * @param scAddr is the service center address or null to use
483      *   the current default SMSC
484      * @param parts an <code>ArrayList</code> of strings that, in order,
485      *   comprise the original message
486      * @param sentIntents if not null, an <code>ArrayList</code> of
487      *   <code>PendingIntent</code>s (one for each message part) that is
488      *   broadcast when the corresponding message part has been sent.
489      *   The result code will be <code>Activity.RESULT_OK<code> for success,
490      *   or one of these errors:
491      *   <code>RESULT_ERROR_GENERIC_FAILURE</code>
492      *   <code>RESULT_ERROR_RADIO_OFF</code>
493      *   <code>RESULT_ERROR_NULL_PDU</code>.
494      *  The per-application based SMS control checks sentIntent. If sentIntent
495      *  is NULL the caller will be checked against all unknown applications,
496      *  which cause smaller number of SMS to be sent in checking period.
497      * @param deliveryIntents if not null, an <code>ArrayList</code> of
498      *   <code>PendingIntent</code>s (one for each message part) that is
499      *   broadcast when the corresponding message part has been delivered
500      *   to the recipient.  The raw pdu of the status report is in the
501      *   extended data ("pdu").
502      */
503 
sendMultipartText(String callingPackage, String destAddr, String scAddr, List<String> parts, List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents, boolean persistMessageForNonDefaultSmsApp)504     public void sendMultipartText(String callingPackage, String destAddr, String scAddr,
505             List<String> parts, List<PendingIntent> sentIntents,
506             List<PendingIntent> deliveryIntents, boolean persistMessageForNonDefaultSmsApp) {
507         mPhone.getContext().enforceCallingPermission(
508                 Manifest.permission.SEND_SMS,
509                 "Sending SMS message");
510         if (!persistMessageForNonDefaultSmsApp) {
511             // Only allow carrier app or carrier ims to skip auto message persistence.
512             enforcePrivilegedAppPermissions();
513         }
514         if (Rlog.isLoggable("SMS", Log.VERBOSE)) {
515             int i = 0;
516             for (String part : parts) {
517                 log("sendMultipartText: destAddr=" + destAddr + ", srAddr=" + scAddr +
518                         ", part[" + (i++) + "]=" + part);
519             }
520         }
521         if (mAppOps.noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(),
522                 callingPackage) != AppOpsManager.MODE_ALLOWED) {
523             return;
524         }
525 
526         destAddr = filterDestAddress(destAddr);
527 
528         if (parts.size() > 1 && parts.size() < 10 && !SmsMessage.hasEmsSupport()) {
529             for (int i = 0; i < parts.size(); i++) {
530                 // If EMS is not supported, we have to break down EMS into single segment SMS
531                 // and add page info " x/y".
532                 String singlePart = parts.get(i);
533                 if (SmsMessage.shouldAppendPageNumberAsPrefix()) {
534                     singlePart = String.valueOf(i + 1) + '/' + parts.size() + ' ' + singlePart;
535                 } else {
536                     singlePart = singlePart.concat(' ' + String.valueOf(i + 1) + '/' + parts.size());
537                 }
538 
539                 PendingIntent singleSentIntent = null;
540                 if (sentIntents != null && sentIntents.size() > i) {
541                     singleSentIntent = sentIntents.get(i);
542                 }
543 
544                 PendingIntent singleDeliveryIntent = null;
545                 if (deliveryIntents != null && deliveryIntents.size() > i) {
546                     singleDeliveryIntent = deliveryIntents.get(i);
547                 }
548 
549                 mDispatcher.sendText(destAddr, scAddr, singlePart,
550                         singleSentIntent, singleDeliveryIntent,
551                         null/*messageUri*/, callingPackage,
552                         persistMessageForNonDefaultSmsApp);
553             }
554             return;
555         }
556 
557         mDispatcher.sendMultipartText(destAddr, scAddr, (ArrayList<String>) parts,
558                 (ArrayList<PendingIntent>) sentIntents, (ArrayList<PendingIntent>) deliveryIntents,
559                 null/*messageUri*/, callingPackage, persistMessageForNonDefaultSmsApp);
560     }
561 
562 
getPremiumSmsPermission(String packageName)563     public int getPremiumSmsPermission(String packageName) {
564         return mDispatcher.getPremiumSmsPermission(packageName);
565     }
566 
567 
setPremiumSmsPermission(String packageName, int permission)568     public void setPremiumSmsPermission(String packageName, int permission) {
569         mDispatcher.setPremiumSmsPermission(packageName, permission);
570     }
571 
572     /**
573      * create SmsRawData lists from all sms record byte[]
574      * Use null to indicate "free" record
575      *
576      * @param messages List of message records from EF_SMS.
577      * @return SmsRawData list of all in-used records
578      */
buildValidRawData(ArrayList<byte[]> messages)579     protected ArrayList<SmsRawData> buildValidRawData(ArrayList<byte[]> messages) {
580         int count = messages.size();
581         ArrayList<SmsRawData> ret;
582 
583         ret = new ArrayList<SmsRawData>(count);
584 
585         for (int i = 0; i < count; i++) {
586             byte[] ba = messages.get(i);
587             if (ba[0] == STATUS_ON_ICC_FREE) {
588                 ret.add(null);
589             } else {
590                 ret.add(new SmsRawData(messages.get(i)));
591             }
592         }
593 
594         return ret;
595     }
596 
597     /**
598      * Generates an EF_SMS record from status and raw PDU.
599      *
600      * @param status Message status.  See TS 51.011 10.5.3.
601      * @param pdu Raw message PDU.
602      * @return byte array for the record.
603      */
makeSmsRecordData(int status, byte[] pdu)604     protected byte[] makeSmsRecordData(int status, byte[] pdu) {
605         byte[] data;
606         if (PhoneConstants.PHONE_TYPE_GSM == mPhone.getPhoneType()) {
607             data = new byte[SmsManager.SMS_RECORD_LENGTH];
608         } else {
609             data = new byte[SmsManager.CDMA_SMS_RECORD_LENGTH];
610         }
611 
612         // Status bits for this record.  See TS 51.011 10.5.3
613         data[0] = (byte)(status & 7);
614 
615         System.arraycopy(pdu, 0, data, 1, pdu.length);
616 
617         // Pad out with 0xFF's.
618         for (int j = pdu.length+1; j < data.length; j++) {
619             data[j] = -1;
620         }
621 
622         return data;
623     }
624 
enableCellBroadcast(int messageIdentifier, int ranType)625     public boolean enableCellBroadcast(int messageIdentifier, int ranType) {
626         return enableCellBroadcastRange(messageIdentifier, messageIdentifier, ranType);
627     }
628 
disableCellBroadcast(int messageIdentifier, int ranType)629     public boolean disableCellBroadcast(int messageIdentifier, int ranType) {
630         return disableCellBroadcastRange(messageIdentifier, messageIdentifier, ranType);
631     }
632 
enableCellBroadcastRange(int startMessageId, int endMessageId, int ranType)633     public boolean enableCellBroadcastRange(int startMessageId, int endMessageId, int ranType) {
634         if (ranType == SmsManager.CELL_BROADCAST_RAN_TYPE_GSM) {
635             return enableGsmBroadcastRange(startMessageId, endMessageId);
636         } else if (ranType == SmsManager.CELL_BROADCAST_RAN_TYPE_CDMA) {
637             return enableCdmaBroadcastRange(startMessageId, endMessageId);
638         } else {
639             throw new IllegalArgumentException("Not a supportted RAN Type");
640         }
641     }
642 
disableCellBroadcastRange(int startMessageId, int endMessageId, int ranType)643     public boolean disableCellBroadcastRange(int startMessageId, int endMessageId, int ranType) {
644         if (ranType == SmsManager.CELL_BROADCAST_RAN_TYPE_GSM ) {
645             return disableGsmBroadcastRange(startMessageId, endMessageId);
646         } else if (ranType == SmsManager.CELL_BROADCAST_RAN_TYPE_CDMA)  {
647             return disableCdmaBroadcastRange(startMessageId, endMessageId);
648         } else {
649             throw new IllegalArgumentException("Not a supportted RAN Type");
650         }
651     }
652 
enableGsmBroadcastRange(int startMessageId, int endMessageId)653     synchronized public boolean enableGsmBroadcastRange(int startMessageId, int endMessageId) {
654 
655         Context context = mPhone.getContext();
656 
657         context.enforceCallingPermission(
658                 "android.permission.RECEIVE_SMS",
659                 "Enabling cell broadcast SMS");
660 
661         String client = context.getPackageManager().getNameForUid(
662                 Binder.getCallingUid());
663 
664         if (!mCellBroadcastRangeManager.enableRange(startMessageId, endMessageId, client)) {
665             log("Failed to add GSM cell broadcast subscription for MID range " + startMessageId
666                     + " to " + endMessageId + " from client " + client);
667             return false;
668         }
669 
670         if (DBG)
671             log("Added GSM cell broadcast subscription for MID range " + startMessageId
672                     + " to " + endMessageId + " from client " + client);
673 
674         setCellBroadcastActivation(!mCellBroadcastRangeManager.isEmpty());
675 
676         return true;
677     }
678 
disableGsmBroadcastRange(int startMessageId, int endMessageId)679     synchronized public boolean disableGsmBroadcastRange(int startMessageId, int endMessageId) {
680 
681         Context context = mPhone.getContext();
682 
683         context.enforceCallingPermission(
684                 "android.permission.RECEIVE_SMS",
685                 "Disabling cell broadcast SMS");
686 
687         String client = context.getPackageManager().getNameForUid(
688                 Binder.getCallingUid());
689 
690         if (!mCellBroadcastRangeManager.disableRange(startMessageId, endMessageId, client)) {
691             log("Failed to remove GSM cell broadcast subscription for MID range " + startMessageId
692                     + " to " + endMessageId + " from client " + client);
693             return false;
694         }
695 
696         if (DBG)
697             log("Removed GSM cell broadcast subscription for MID range " + startMessageId
698                     + " to " + endMessageId + " from client " + client);
699 
700         setCellBroadcastActivation(!mCellBroadcastRangeManager.isEmpty());
701 
702         return true;
703     }
704 
enableCdmaBroadcastRange(int startMessageId, int endMessageId)705     synchronized public boolean enableCdmaBroadcastRange(int startMessageId, int endMessageId) {
706 
707         Context context = mPhone.getContext();
708 
709         context.enforceCallingPermission(
710                 "android.permission.RECEIVE_SMS",
711                 "Enabling cdma broadcast SMS");
712 
713         String client = context.getPackageManager().getNameForUid(
714                 Binder.getCallingUid());
715 
716         if (!mCdmaBroadcastRangeManager.enableRange(startMessageId, endMessageId, client)) {
717             log("Failed to add cdma broadcast subscription for MID range " + startMessageId
718                     + " to " + endMessageId + " from client " + client);
719             return false;
720         }
721 
722         if (DBG)
723             log("Added cdma broadcast subscription for MID range " + startMessageId
724                     + " to " + endMessageId + " from client " + client);
725 
726         setCdmaBroadcastActivation(!mCdmaBroadcastRangeManager.isEmpty());
727 
728         return true;
729     }
730 
disableCdmaBroadcastRange(int startMessageId, int endMessageId)731     synchronized public boolean disableCdmaBroadcastRange(int startMessageId, int endMessageId) {
732 
733         Context context = mPhone.getContext();
734 
735         context.enforceCallingPermission(
736                 "android.permission.RECEIVE_SMS",
737                 "Disabling cell broadcast SMS");
738 
739         String client = context.getPackageManager().getNameForUid(
740                 Binder.getCallingUid());
741 
742         if (!mCdmaBroadcastRangeManager.disableRange(startMessageId, endMessageId, client)) {
743             log("Failed to remove cdma broadcast subscription for MID range " + startMessageId
744                     + " to " + endMessageId + " from client " + client);
745             return false;
746         }
747 
748         if (DBG)
749             log("Removed cdma broadcast subscription for MID range " + startMessageId
750                     + " to " + endMessageId + " from client " + client);
751 
752         setCdmaBroadcastActivation(!mCdmaBroadcastRangeManager.isEmpty());
753 
754         return true;
755     }
756 
757     class CellBroadcastRangeManager extends IntRangeManager {
758         private ArrayList<SmsBroadcastConfigInfo> mConfigList =
759                 new ArrayList<SmsBroadcastConfigInfo>();
760 
761         /**
762          * Called when the list of enabled ranges has changed. This will be
763          * followed by zero or more calls to {@link #addRange} followed by
764          * a call to {@link #finishUpdate}.
765          */
startUpdate()766         protected void startUpdate() {
767             mConfigList.clear();
768         }
769 
770         /**
771          * Called after {@link #startUpdate} to indicate a range of enabled
772          * values.
773          * @param startId the first id included in the range
774          * @param endId the last id included in the range
775          */
addRange(int startId, int endId, boolean selected)776         protected void addRange(int startId, int endId, boolean selected) {
777             mConfigList.add(new SmsBroadcastConfigInfo(startId, endId,
778                         SMS_CB_CODE_SCHEME_MIN, SMS_CB_CODE_SCHEME_MAX, selected));
779         }
780 
781         /**
782          * Called to indicate the end of a range update started by the
783          * previous call to {@link #startUpdate}.
784          * @return true if successful, false otherwise
785          */
finishUpdate()786         protected boolean finishUpdate() {
787             if (mConfigList.isEmpty()) {
788                 return true;
789             } else {
790                 SmsBroadcastConfigInfo[] configs =
791                         mConfigList.toArray(new SmsBroadcastConfigInfo[mConfigList.size()]);
792                 return setCellBroadcastConfig(configs);
793             }
794         }
795     }
796 
797     class CdmaBroadcastRangeManager extends IntRangeManager {
798         private ArrayList<CdmaSmsBroadcastConfigInfo> mConfigList =
799                 new ArrayList<CdmaSmsBroadcastConfigInfo>();
800 
801         /**
802          * Called when the list of enabled ranges has changed. This will be
803          * followed by zero or more calls to {@link #addRange} followed by a
804          * call to {@link #finishUpdate}.
805          */
startUpdate()806         protected void startUpdate() {
807             mConfigList.clear();
808         }
809 
810         /**
811          * Called after {@link #startUpdate} to indicate a range of enabled
812          * values.
813          * @param startId the first id included in the range
814          * @param endId the last id included in the range
815          */
addRange(int startId, int endId, boolean selected)816         protected void addRange(int startId, int endId, boolean selected) {
817             mConfigList.add(new CdmaSmsBroadcastConfigInfo(startId, endId,
818                     1, selected));
819         }
820 
821         /**
822          * Called to indicate the end of a range update started by the previous
823          * call to {@link #startUpdate}.
824          * @return true if successful, false otherwise
825          */
finishUpdate()826         protected boolean finishUpdate() {
827             if (mConfigList.isEmpty()) {
828                 return true;
829             } else {
830                 CdmaSmsBroadcastConfigInfo[] configs =
831                         mConfigList.toArray(new CdmaSmsBroadcastConfigInfo[mConfigList.size()]);
832                 return setCdmaBroadcastConfig(configs);
833             }
834         }
835     }
836 
setCellBroadcastConfig(SmsBroadcastConfigInfo[] configs)837     private boolean setCellBroadcastConfig(SmsBroadcastConfigInfo[] configs) {
838         if (DBG)
839             log("Calling setGsmBroadcastConfig with " + configs.length + " configurations");
840 
841         synchronized (mLock) {
842             Message response = mHandler.obtainMessage(EVENT_SET_BROADCAST_CONFIG_DONE);
843 
844             mSuccess = false;
845             mPhone.mCi.setGsmBroadcastConfig(configs, response);
846 
847             try {
848                 mLock.wait();
849             } catch (InterruptedException e) {
850                 log("interrupted while trying to set cell broadcast config");
851             }
852         }
853 
854         return mSuccess;
855     }
856 
setCellBroadcastActivation(boolean activate)857     private boolean setCellBroadcastActivation(boolean activate) {
858         if (DBG)
859             log("Calling setCellBroadcastActivation(" + activate + ')');
860 
861         synchronized (mLock) {
862             Message response = mHandler.obtainMessage(EVENT_SET_BROADCAST_ACTIVATION_DONE);
863 
864             mSuccess = false;
865             mPhone.mCi.setGsmBroadcastActivation(activate, response);
866 
867             try {
868                 mLock.wait();
869             } catch (InterruptedException e) {
870                 log("interrupted while trying to set cell broadcast activation");
871             }
872         }
873 
874         return mSuccess;
875     }
876 
setCdmaBroadcastConfig(CdmaSmsBroadcastConfigInfo[] configs)877     private boolean setCdmaBroadcastConfig(CdmaSmsBroadcastConfigInfo[] configs) {
878         if (DBG)
879             log("Calling setCdmaBroadcastConfig with " + configs.length + " configurations");
880 
881         synchronized (mLock) {
882             Message response = mHandler.obtainMessage(EVENT_SET_BROADCAST_CONFIG_DONE);
883 
884             mSuccess = false;
885             mPhone.mCi.setCdmaBroadcastConfig(configs, response);
886 
887             try {
888                 mLock.wait();
889             } catch (InterruptedException e) {
890                 log("interrupted while trying to set cdma broadcast config");
891             }
892         }
893 
894         return mSuccess;
895     }
896 
setCdmaBroadcastActivation(boolean activate)897     private boolean setCdmaBroadcastActivation(boolean activate) {
898         if (DBG)
899             log("Calling setCdmaBroadcastActivation(" + activate + ")");
900 
901         synchronized (mLock) {
902             Message response = mHandler.obtainMessage(EVENT_SET_BROADCAST_ACTIVATION_DONE);
903 
904             mSuccess = false;
905             mPhone.mCi.setCdmaBroadcastActivation(activate, response);
906 
907             try {
908                 mLock.wait();
909             } catch (InterruptedException e) {
910                 log("interrupted while trying to set cdma broadcast activation");
911             }
912         }
913 
914         return mSuccess;
915     }
916 
log(String msg)917     protected void log(String msg) {
918         Log.d(LOG_TAG, "[IccSmsInterfaceManager] " + msg);
919     }
920 
isImsSmsSupported()921     public boolean isImsSmsSupported() {
922         return mDispatcher.isIms();
923     }
924 
getImsSmsFormat()925     public String getImsSmsFormat() {
926         return mDispatcher.getImsSmsFormat();
927     }
928 
sendStoredText(String callingPkg, Uri messageUri, String scAddress, PendingIntent sentIntent, PendingIntent deliveryIntent)929     public void sendStoredText(String callingPkg, Uri messageUri, String scAddress,
930             PendingIntent sentIntent, PendingIntent deliveryIntent) {
931         mPhone.getContext().enforceCallingPermission(Manifest.permission.SEND_SMS,
932                 "Sending SMS message");
933         if (Rlog.isLoggable("SMS", Log.VERBOSE)) {
934             log("sendStoredText: scAddr=" + scAddress + " messageUri=" + messageUri
935                     + " sentIntent=" + sentIntent + " deliveryIntent=" + deliveryIntent);
936         }
937         if (mAppOps.noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(), callingPkg)
938                 != AppOpsManager.MODE_ALLOWED) {
939             return;
940         }
941         final ContentResolver resolver = mPhone.getContext().getContentResolver();
942         if (!isFailedOrDraft(resolver, messageUri)) {
943             Log.e(LOG_TAG, "[IccSmsInterfaceManager]sendStoredText: not FAILED or DRAFT message");
944             returnUnspecifiedFailure(sentIntent);
945             return;
946         }
947         final String[] textAndAddress = loadTextAndAddress(resolver, messageUri);
948         if (textAndAddress == null) {
949             Log.e(LOG_TAG, "[IccSmsInterfaceManager]sendStoredText: can not load text");
950             returnUnspecifiedFailure(sentIntent);
951             return;
952         }
953         textAndAddress[1] = filterDestAddress(textAndAddress[1]);
954         mDispatcher.sendText(textAndAddress[1], scAddress, textAndAddress[0],
955                 sentIntent, deliveryIntent, messageUri, callingPkg,
956                 true /* persistMessageForNonDefaultSmsApp */);
957     }
958 
sendStoredMultipartText(String callingPkg, Uri messageUri, String scAddress, List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents)959     public void sendStoredMultipartText(String callingPkg, Uri messageUri, String scAddress,
960             List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) {
961         mPhone.getContext().enforceCallingPermission(Manifest.permission.SEND_SMS,
962                 "Sending SMS message");
963         if (mAppOps.noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(), callingPkg)
964                 != AppOpsManager.MODE_ALLOWED) {
965             return;
966         }
967         final ContentResolver resolver = mPhone.getContext().getContentResolver();
968         if (!isFailedOrDraft(resolver, messageUri)) {
969             Log.e(LOG_TAG, "[IccSmsInterfaceManager]sendStoredMultipartText: "
970                     + "not FAILED or DRAFT message");
971             returnUnspecifiedFailure(sentIntents);
972             return;
973         }
974         final String[] textAndAddress = loadTextAndAddress(resolver, messageUri);
975         if (textAndAddress == null) {
976             Log.e(LOG_TAG, "[IccSmsInterfaceManager]sendStoredMultipartText: can not load text");
977             returnUnspecifiedFailure(sentIntents);
978             return;
979         }
980         final ArrayList<String> parts = SmsManager.getDefault().divideMessage(textAndAddress[0]);
981         if (parts == null || parts.size() < 1) {
982             Log.e(LOG_TAG, "[IccSmsInterfaceManager]sendStoredMultipartText: can not divide text");
983             returnUnspecifiedFailure(sentIntents);
984             return;
985         }
986 
987         textAndAddress[1] = filterDestAddress(textAndAddress[1]);
988 
989         if (parts.size() > 1 && parts.size() < 10 && !SmsMessage.hasEmsSupport()) {
990             for (int i = 0; i < parts.size(); i++) {
991                 // If EMS is not supported, we have to break down EMS into single segment SMS
992                 // and add page info " x/y".
993                 String singlePart = parts.get(i);
994                 if (SmsMessage.shouldAppendPageNumberAsPrefix()) {
995                     singlePart = String.valueOf(i + 1) + '/' + parts.size() + ' ' + singlePart;
996                 } else {
997                     singlePart = singlePart.concat(' ' + String.valueOf(i + 1) + '/' + parts.size());
998                 }
999 
1000                 PendingIntent singleSentIntent = null;
1001                 if (sentIntents != null && sentIntents.size() > i) {
1002                     singleSentIntent = sentIntents.get(i);
1003                 }
1004 
1005                 PendingIntent singleDeliveryIntent = null;
1006                 if (deliveryIntents != null && deliveryIntents.size() > i) {
1007                     singleDeliveryIntent = deliveryIntents.get(i);
1008                 }
1009 
1010                 mDispatcher.sendText(textAndAddress[1], scAddress, singlePart,
1011                         singleSentIntent, singleDeliveryIntent, messageUri, callingPkg,
1012                         true  /* persistMessageForNonDefaultSmsApp */);
1013             }
1014             return;
1015         }
1016 
1017         mDispatcher.sendMultipartText(
1018                 textAndAddress[1], // destAddress
1019                 scAddress,
1020                 parts,
1021                 (ArrayList<PendingIntent>) sentIntents,
1022                 (ArrayList<PendingIntent>) deliveryIntents,
1023                 messageUri,
1024                 callingPkg,
1025                 true  /* persistMessageForNonDefaultSmsApp */);
1026     }
1027 
isFailedOrDraft(ContentResolver resolver, Uri messageUri)1028     private boolean isFailedOrDraft(ContentResolver resolver, Uri messageUri) {
1029         // Clear the calling identity and query the database using the phone user id
1030         // Otherwise the AppOps check in TelephonyProvider would complain about mismatch
1031         // between the calling uid and the package uid
1032         final long identity = Binder.clearCallingIdentity();
1033         Cursor cursor = null;
1034         try {
1035             cursor = resolver.query(
1036                     messageUri,
1037                     new String[]{ Telephony.Sms.TYPE },
1038                     null/*selection*/,
1039                     null/*selectionArgs*/,
1040                     null/*sortOrder*/);
1041             if (cursor != null && cursor.moveToFirst()) {
1042                 final int type = cursor.getInt(0);
1043                 return type == Telephony.Sms.MESSAGE_TYPE_DRAFT
1044                         || type == Telephony.Sms.MESSAGE_TYPE_FAILED;
1045             }
1046         } catch (SQLiteException e) {
1047             Log.e(LOG_TAG, "[IccSmsInterfaceManager]isFailedOrDraft: query message type failed", e);
1048         } finally {
1049             if (cursor != null) {
1050                 cursor.close();
1051             }
1052             Binder.restoreCallingIdentity(identity);
1053         }
1054         return false;
1055     }
1056 
1057     // Return an array including both the SMS text (0) and address (1)
loadTextAndAddress(ContentResolver resolver, Uri messageUri)1058     private String[] loadTextAndAddress(ContentResolver resolver, Uri messageUri) {
1059         // Clear the calling identity and query the database using the phone user id
1060         // Otherwise the AppOps check in TelephonyProvider would complain about mismatch
1061         // between the calling uid and the package uid
1062         final long identity = Binder.clearCallingIdentity();
1063         Cursor cursor = null;
1064         try {
1065             cursor = resolver.query(
1066                     messageUri,
1067                     new String[]{
1068                             Telephony.Sms.BODY,
1069                             Telephony.Sms.ADDRESS
1070                     },
1071                     null/*selection*/,
1072                     null/*selectionArgs*/,
1073                     null/*sortOrder*/);
1074             if (cursor != null && cursor.moveToFirst()) {
1075                 return new String[]{ cursor.getString(0), cursor.getString(1) };
1076             }
1077         } catch (SQLiteException e) {
1078             Log.e(LOG_TAG, "[IccSmsInterfaceManager]loadText: query message text failed", e);
1079         } finally {
1080             if (cursor != null) {
1081                 cursor.close();
1082             }
1083             Binder.restoreCallingIdentity(identity);
1084         }
1085         return null;
1086     }
1087 
returnUnspecifiedFailure(PendingIntent pi)1088     private void returnUnspecifiedFailure(PendingIntent pi) {
1089         if (pi != null) {
1090             try {
1091                 pi.send(SmsManager.RESULT_ERROR_GENERIC_FAILURE);
1092             } catch (PendingIntent.CanceledException e) {
1093                 // ignore
1094             }
1095         }
1096     }
1097 
returnUnspecifiedFailure(List<PendingIntent> pis)1098     private void returnUnspecifiedFailure(List<PendingIntent> pis) {
1099         if (pis == null) {
1100             return;
1101         }
1102         for (PendingIntent pi : pis) {
1103             returnUnspecifiedFailure(pi);
1104         }
1105     }
1106 
enforceCarrierPrivilege()1107     private void enforceCarrierPrivilege() {
1108         UiccController controller = UiccController.getInstance();
1109         if (controller == null || controller.getUiccCard(mPhone.getPhoneId()) == null) {
1110             throw new SecurityException("No Carrier Privilege: No UICC");
1111         }
1112         if (controller.getUiccCard(mPhone.getPhoneId()).getCarrierPrivilegeStatusForCurrentTransaction(
1113                 mContext.getPackageManager()) !=
1114                     TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
1115             throw new SecurityException("No Carrier Privilege.");
1116         }
1117     }
1118 
1119     /**
1120      * Enforces that the caller has {@link android.Manifest.permission#MODIFY_PHONE_STATE}
1121      * permission or is one of the following apps:
1122      * <ul>
1123      *     <li> IMS App
1124      *     <li> Carrier App
1125      * </ul>
1126      */
enforcePrivilegedAppPermissions()1127     private void enforcePrivilegedAppPermissions() {
1128         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
1129                 == PackageManager.PERMISSION_GRANTED) {
1130             return;
1131         }
1132 
1133         int callingUid = Binder.getCallingUid();
1134         String carrierImsPackage = CarrierSmsUtils.getCarrierImsPackageForIntent(mContext, mPhone,
1135                 new Intent(CarrierMessagingService.SERVICE_INTERFACE));
1136         try {
1137             if (carrierImsPackage != null
1138                     && callingUid == mContext.getPackageManager().getPackageUid(
1139                             carrierImsPackage, 0)) {
1140               return;
1141             }
1142         } catch (PackageManager.NameNotFoundException e) {
1143             if (Rlog.isLoggable("SMS", Log.DEBUG)) {
1144                 log("Cannot find configured carrier ims package");
1145             }
1146         }
1147 
1148         enforceCarrierPrivilege();
1149     }
1150 
filterDestAddress(String destAddr)1151     private String filterDestAddress(String destAddr) {
1152         String result  = null;
1153         result = SmsNumberUtils.filterDestAddr(mPhone, destAddr);
1154         return result != null ? result : destAddr;
1155     }
1156 
1157 }
1158