Home | History | Annotate | Download | only in telephony
      1 /*
      2  * Copyright (C) 2013 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 android.Manifest.permission;
     20 import android.app.AppOpsManager;
     21 import android.content.ComponentName;
     22 import android.content.Context;
     23 import android.content.Intent;
     24 import android.content.IntentFilter;
     25 import android.content.pm.ActivityInfo;
     26 import android.content.pm.ApplicationInfo;
     27 import android.content.pm.PackageInfo;
     28 import android.content.pm.PackageManager;
     29 import android.content.pm.PackageManager.NameNotFoundException;
     30 import android.content.pm.ResolveInfo;
     31 import android.content.pm.ServiceInfo;
     32 import android.content.res.Resources;
     33 import android.net.Uri;
     34 import android.os.Binder;
     35 import android.os.Debug;
     36 import android.os.Process;
     37 import android.os.UserHandle;
     38 import android.provider.Settings;
     39 import android.provider.Telephony;
     40 import android.provider.Telephony.Sms.Intents;
     41 import android.telephony.Rlog;
     42 import android.telephony.SmsManager;
     43 import android.telephony.TelephonyManager;
     44 import android.util.Log;
     45 
     46 import com.android.internal.content.PackageMonitor;
     47 import com.android.internal.logging.MetricsLogger;
     48 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
     49 
     50 import java.util.Collection;
     51 import java.util.HashMap;
     52 import java.util.List;
     53 
     54 /**
     55  * Class for managing the primary application that we will deliver SMS/MMS messages to
     56  *
     57  * {@hide}
     58  */
     59 public final class SmsApplication {
     60     static final String LOG_TAG = "SmsApplication";
     61     private static final String PHONE_PACKAGE_NAME = "com.android.phone";
     62     private static final String BLUETOOTH_PACKAGE_NAME = "com.android.bluetooth";
     63     private static final String MMS_SERVICE_PACKAGE_NAME = "com.android.mms.service";
     64     private static final String TELEPHONY_PROVIDER_PACKAGE_NAME = "com.android.providers.telephony";
     65 
     66     private static final String SCHEME_SMS = "sms";
     67     private static final String SCHEME_SMSTO = "smsto";
     68     private static final String SCHEME_MMS = "mms";
     69     private static final String SCHEME_MMSTO = "mmsto";
     70     private static final boolean DEBUG_MULTIUSER = false;
     71 
     72     private static SmsPackageMonitor sSmsPackageMonitor = null;
     73 
     74     public static class SmsApplicationData {
     75         /**
     76          * Name of this SMS app for display.
     77          */
     78         private String mApplicationName;
     79 
     80         /**
     81          * Package name for this SMS app.
     82          */
     83         public String mPackageName;
     84 
     85         /**
     86          * The class name of the SMS_DELIVER_ACTION receiver in this app.
     87          */
     88         private String mSmsReceiverClass;
     89 
     90         /**
     91          * The class name of the WAP_PUSH_DELIVER_ACTION receiver in this app.
     92          */
     93         private String mMmsReceiverClass;
     94 
     95         /**
     96          * The class name of the ACTION_RESPOND_VIA_MESSAGE intent in this app.
     97          */
     98         private String mRespondViaMessageClass;
     99 
    100         /**
    101          * The class name of the ACTION_SENDTO intent in this app.
    102          */
    103         private String mSendToClass;
    104 
    105         /**
    106          * The class name of the ACTION_DEFAULT_SMS_PACKAGE_CHANGED receiver in this app.
    107          */
    108         private String mSmsAppChangedReceiverClass;
    109 
    110         /**
    111          * The class name of the ACTION_EXTERNAL_PROVIDER_CHANGE receiver in this app.
    112          */
    113         private String mProviderChangedReceiverClass;
    114 
    115         /**
    116          * The class name of the SIM_FULL_ACTION receiver in this app.
    117          */
    118         private String mSimFullReceiverClass;
    119 
    120         /**
    121          * The user-id for this application
    122          */
    123         private int mUid;
    124 
    125         /**
    126          * Returns true if this SmsApplicationData is complete (all intents handled).
    127          * @return
    128          */
    129         public boolean isComplete() {
    130             return (mSmsReceiverClass != null && mMmsReceiverClass != null
    131                     && mRespondViaMessageClass != null && mSendToClass != null);
    132         }
    133 
    134         public SmsApplicationData(String packageName, int uid) {
    135             mPackageName = packageName;
    136             mUid = uid;
    137         }
    138 
    139         public String getApplicationName(Context context) {
    140             if (mApplicationName == null) {
    141                 PackageManager pm = context.getPackageManager();
    142                 ApplicationInfo appInfo;
    143                 try {
    144                     appInfo = pm.getApplicationInfoAsUser(mPackageName, 0,
    145                             UserHandle.getUserId(mUid));
    146                 } catch (NameNotFoundException e) {
    147                     return null;
    148                 }
    149                 if (appInfo != null) {
    150                     CharSequence label  = pm.getApplicationLabel(appInfo);
    151                     mApplicationName = (label == null) ? null : label.toString();
    152                 }
    153             }
    154             return mApplicationName;
    155         }
    156 
    157         @Override
    158         public String toString() {
    159             return " mPackageName: " + mPackageName
    160                     + " mSmsReceiverClass: " + mSmsReceiverClass
    161                     + " mMmsReceiverClass: " + mMmsReceiverClass
    162                     + " mRespondViaMessageClass: " + mRespondViaMessageClass
    163                     + " mSendToClass: " + mSendToClass
    164                     + " mSmsAppChangedClass: " + mSmsAppChangedReceiverClass
    165                     + " mProviderChangedReceiverClass: " + mProviderChangedReceiverClass
    166                     + " mSimFullReceiverClass: " + mSimFullReceiverClass
    167                     + " mUid: " + mUid;
    168         }
    169     }
    170 
    171     /**
    172      * Returns the userId of the Context object, if called from a system app,
    173      * otherwise it returns the caller's userId
    174      * @param context The context object passed in by the caller.
    175      * @return
    176      */
    177     private static int getIncomingUserId(Context context) {
    178         int contextUserId = context.getUserId();
    179         final int callingUid = Binder.getCallingUid();
    180         if (DEBUG_MULTIUSER) {
    181             Log.i(LOG_TAG, "getIncomingUserHandle caller=" + callingUid + ", myuid="
    182                     + android.os.Process.myUid() + "\n\t" + Debug.getCallers(4));
    183         }
    184         if (UserHandle.getAppId(callingUid)
    185                 < android.os.Process.FIRST_APPLICATION_UID) {
    186             return contextUserId;
    187         } else {
    188             return UserHandle.getUserId(callingUid);
    189         }
    190     }
    191 
    192     /**
    193      * Returns the list of available SMS apps defined as apps that are registered for both the
    194      * SMS_RECEIVED_ACTION (SMS) and WAP_PUSH_RECEIVED_ACTION (MMS) broadcasts (and their broadcast
    195      * receivers are enabled)
    196      *
    197      * Requirements to be an SMS application:
    198      * Implement SMS_DELIVER_ACTION broadcast receiver.
    199      * Require BROADCAST_SMS permission.
    200      *
    201      * Implement WAP_PUSH_DELIVER_ACTION broadcast receiver.
    202      * Require BROADCAST_WAP_PUSH permission.
    203      *
    204      * Implement RESPOND_VIA_MESSAGE intent.
    205      * Support smsto Uri scheme.
    206      * Require SEND_RESPOND_VIA_MESSAGE permission.
    207      *
    208      * Implement ACTION_SENDTO intent.
    209      * Support smsto Uri scheme.
    210      */
    211     public static Collection<SmsApplicationData> getApplicationCollection(Context context) {
    212         int userId = getIncomingUserId(context);
    213         final long token = Binder.clearCallingIdentity();
    214         try {
    215             return getApplicationCollectionInternal(context, userId);
    216         } finally {
    217             Binder.restoreCallingIdentity(token);
    218         }
    219     }
    220 
    221     private static Collection<SmsApplicationData> getApplicationCollectionInternal(
    222             Context context, int userId) {
    223         PackageManager packageManager = context.getPackageManager();
    224 
    225         // Get the list of apps registered for SMS
    226         Intent intent = new Intent(Intents.SMS_DELIVER_ACTION);
    227         List<ResolveInfo> smsReceivers = packageManager.queryBroadcastReceiversAsUser(intent, 0,
    228                 userId);
    229 
    230         HashMap<String, SmsApplicationData> receivers = new HashMap<String, SmsApplicationData>();
    231 
    232         // Add one entry to the map for every sms receiver (ignoring duplicate sms receivers)
    233         for (ResolveInfo resolveInfo : smsReceivers) {
    234             final ActivityInfo activityInfo = resolveInfo.activityInfo;
    235             if (activityInfo == null) {
    236                 continue;
    237             }
    238             if (!permission.BROADCAST_SMS.equals(activityInfo.permission)) {
    239                 continue;
    240             }
    241             final String packageName = activityInfo.packageName;
    242             if (!receivers.containsKey(packageName)) {
    243                 final SmsApplicationData smsApplicationData = new SmsApplicationData(packageName,
    244                         activityInfo.applicationInfo.uid);
    245                 smsApplicationData.mSmsReceiverClass = activityInfo.name;
    246                 receivers.put(packageName, smsApplicationData);
    247             }
    248         }
    249 
    250         // Update any existing entries with mms receiver class
    251         intent = new Intent(Intents.WAP_PUSH_DELIVER_ACTION);
    252         intent.setDataAndType(null, "application/vnd.wap.mms-message");
    253         List<ResolveInfo> mmsReceivers = packageManager.queryBroadcastReceiversAsUser(intent, 0,
    254                 userId);
    255         for (ResolveInfo resolveInfo : mmsReceivers) {
    256             final ActivityInfo activityInfo = resolveInfo.activityInfo;
    257             if (activityInfo == null) {
    258                 continue;
    259             }
    260             if (!permission.BROADCAST_WAP_PUSH.equals(activityInfo.permission)) {
    261                 continue;
    262             }
    263             final String packageName = activityInfo.packageName;
    264             final SmsApplicationData smsApplicationData = receivers.get(packageName);
    265             if (smsApplicationData != null) {
    266                 smsApplicationData.mMmsReceiverClass = activityInfo.name;
    267             }
    268         }
    269 
    270         // Update any existing entries with respond via message intent class.
    271         intent = new Intent(TelephonyManager.ACTION_RESPOND_VIA_MESSAGE,
    272                 Uri.fromParts(SCHEME_SMSTO, "", null));
    273         List<ResolveInfo> respondServices = packageManager.queryIntentServicesAsUser(intent, 0,
    274                 userId);
    275         for (ResolveInfo resolveInfo : respondServices) {
    276             final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
    277             if (serviceInfo == null) {
    278                 continue;
    279             }
    280             if (!permission.SEND_RESPOND_VIA_MESSAGE.equals(serviceInfo.permission)) {
    281                 continue;
    282             }
    283             final String packageName = serviceInfo.packageName;
    284             final SmsApplicationData smsApplicationData = receivers.get(packageName);
    285             if (smsApplicationData != null) {
    286                 smsApplicationData.mRespondViaMessageClass = serviceInfo.name;
    287             }
    288         }
    289 
    290         // Update any existing entries with supports send to.
    291         intent = new Intent(Intent.ACTION_SENDTO,
    292                 Uri.fromParts(SCHEME_SMSTO, "", null));
    293         List<ResolveInfo> sendToActivities = packageManager.queryIntentActivitiesAsUser(intent, 0,
    294                 userId);
    295         for (ResolveInfo resolveInfo : sendToActivities) {
    296             final ActivityInfo activityInfo = resolveInfo.activityInfo;
    297             if (activityInfo == null) {
    298                 continue;
    299             }
    300             final String packageName = activityInfo.packageName;
    301             final SmsApplicationData smsApplicationData = receivers.get(packageName);
    302             if (smsApplicationData != null) {
    303                 smsApplicationData.mSendToClass = activityInfo.name;
    304             }
    305         }
    306 
    307         // Update any existing entries with the default sms changed handler.
    308         intent = new Intent(Telephony.Sms.Intents.ACTION_DEFAULT_SMS_PACKAGE_CHANGED);
    309         List<ResolveInfo> smsAppChangedReceivers =
    310                 packageManager.queryBroadcastReceiversAsUser(intent, 0, userId);
    311         if (DEBUG_MULTIUSER) {
    312             Log.i(LOG_TAG, "getApplicationCollectionInternal smsAppChangedActivities=" +
    313                     smsAppChangedReceivers);
    314         }
    315         for (ResolveInfo resolveInfo : smsAppChangedReceivers) {
    316             final ActivityInfo activityInfo = resolveInfo.activityInfo;
    317             if (activityInfo == null) {
    318                 continue;
    319             }
    320             final String packageName = activityInfo.packageName;
    321             final SmsApplicationData smsApplicationData = receivers.get(packageName);
    322             if (DEBUG_MULTIUSER) {
    323                 Log.i(LOG_TAG, "getApplicationCollectionInternal packageName=" +
    324                         packageName + " smsApplicationData: " + smsApplicationData +
    325                         " activityInfo.name: " + activityInfo.name);
    326             }
    327             if (smsApplicationData != null) {
    328                 smsApplicationData.mSmsAppChangedReceiverClass = activityInfo.name;
    329             }
    330         }
    331 
    332         // Update any existing entries with the external provider changed handler.
    333         intent = new Intent(Telephony.Sms.Intents.ACTION_EXTERNAL_PROVIDER_CHANGE);
    334         List<ResolveInfo> providerChangedReceivers =
    335                 packageManager.queryBroadcastReceiversAsUser(intent, 0, userId);
    336         if (DEBUG_MULTIUSER) {
    337             Log.i(LOG_TAG, "getApplicationCollectionInternal providerChangedActivities=" +
    338                     providerChangedReceivers);
    339         }
    340         for (ResolveInfo resolveInfo : providerChangedReceivers) {
    341             final ActivityInfo activityInfo = resolveInfo.activityInfo;
    342             if (activityInfo == null) {
    343                 continue;
    344             }
    345             final String packageName = activityInfo.packageName;
    346             final SmsApplicationData smsApplicationData = receivers.get(packageName);
    347             if (DEBUG_MULTIUSER) {
    348                 Log.i(LOG_TAG, "getApplicationCollectionInternal packageName=" +
    349                         packageName + " smsApplicationData: " + smsApplicationData +
    350                         " activityInfo.name: " + activityInfo.name);
    351             }
    352             if (smsApplicationData != null) {
    353                 smsApplicationData.mProviderChangedReceiverClass = activityInfo.name;
    354             }
    355         }
    356 
    357         // Update any existing entries with the sim full handler.
    358         intent = new Intent(Intents.SIM_FULL_ACTION);
    359         List<ResolveInfo> simFullReceivers =
    360                 packageManager.queryBroadcastReceiversAsUser(intent, 0, userId);
    361         if (DEBUG_MULTIUSER) {
    362             Log.i(LOG_TAG, "getApplicationCollectionInternal simFullReceivers="
    363                     + simFullReceivers);
    364         }
    365         for (ResolveInfo resolveInfo : simFullReceivers) {
    366             final ActivityInfo activityInfo = resolveInfo.activityInfo;
    367             if (activityInfo == null) {
    368                 continue;
    369             }
    370             final String packageName = activityInfo.packageName;
    371             final SmsApplicationData smsApplicationData = receivers.get(packageName);
    372             if (DEBUG_MULTIUSER) {
    373                 Log.i(LOG_TAG, "getApplicationCollectionInternal packageName="
    374                         + packageName + " smsApplicationData: " + smsApplicationData
    375                         + " activityInfo.name: " + activityInfo.name);
    376             }
    377             if (smsApplicationData != null) {
    378                 smsApplicationData.mSimFullReceiverClass = activityInfo.name;
    379             }
    380         }
    381 
    382         // Remove any entries for which we did not find all required intents.
    383         for (ResolveInfo resolveInfo : smsReceivers) {
    384             final ActivityInfo activityInfo = resolveInfo.activityInfo;
    385             if (activityInfo == null) {
    386                 continue;
    387             }
    388             final String packageName = activityInfo.packageName;
    389             final SmsApplicationData smsApplicationData = receivers.get(packageName);
    390             if (smsApplicationData != null) {
    391                 if (!smsApplicationData.isComplete()) {
    392                     receivers.remove(packageName);
    393                 }
    394             }
    395         }
    396         return receivers.values();
    397     }
    398 
    399     /**
    400      * Checks to see if we have a valid installed SMS application for the specified package name
    401      * @return Data for the specified package name or null if there isn't one
    402      */
    403     private static SmsApplicationData getApplicationForPackage(
    404             Collection<SmsApplicationData> applications, String packageName) {
    405         if (packageName == null) {
    406             return null;
    407         }
    408         // Is there an entry in the application list for the specified package?
    409         for (SmsApplicationData application : applications) {
    410             if (application.mPackageName.contentEquals(packageName)) {
    411                 return application;
    412             }
    413         }
    414         return null;
    415     }
    416 
    417     /**
    418      * Get the application we will use for delivering SMS/MMS messages.
    419      *
    420      * We return the preferred sms application with the following order of preference:
    421      * (1) User selected SMS app (if selected, and if still valid)
    422      * (2) Android Messaging (if installed)
    423      * (3) The currently configured highest priority broadcast receiver
    424      * (4) Null
    425      */
    426     private static SmsApplicationData getApplication(Context context, boolean updateIfNeeded,
    427             int userId) {
    428         TelephonyManager tm = (TelephonyManager)
    429                 context.getSystemService(Context.TELEPHONY_SERVICE);
    430         if (!tm.isSmsCapable()) {
    431             // No phone, no SMS
    432             return null;
    433         }
    434 
    435         Collection<SmsApplicationData> applications = getApplicationCollectionInternal(context,
    436                 userId);
    437         if (DEBUG_MULTIUSER) {
    438             Log.i(LOG_TAG, "getApplication userId=" + userId);
    439         }
    440         // Determine which application receives the broadcast
    441         String defaultApplication = Settings.Secure.getStringForUser(context.getContentResolver(),
    442                 Settings.Secure.SMS_DEFAULT_APPLICATION, userId);
    443         if (DEBUG_MULTIUSER) {
    444             Log.i(LOG_TAG, "getApplication defaultApp=" + defaultApplication);
    445         }
    446 
    447         SmsApplicationData applicationData = null;
    448         if (defaultApplication != null) {
    449             applicationData = getApplicationForPackage(applications, defaultApplication);
    450         }
    451         if (DEBUG_MULTIUSER) {
    452             Log.i(LOG_TAG, "getApplication appData=" + applicationData);
    453         }
    454         // Picking a new SMS app requires AppOps and Settings.Secure permissions, so we only do
    455         // this if the caller asked us to.
    456         if (updateIfNeeded && applicationData == null) {
    457             // Try to find the default SMS package for this device
    458             Resources r = context.getResources();
    459             String defaultPackage =
    460                     r.getString(com.android.internal.R.string.default_sms_application);
    461             applicationData = getApplicationForPackage(applications, defaultPackage);
    462 
    463             if (applicationData == null) {
    464                 // Are there any applications?
    465                 if (applications.size() != 0) {
    466                     applicationData = (SmsApplicationData)applications.toArray()[0];
    467                 }
    468             }
    469 
    470             // If we found a new default app, update the setting
    471             if (applicationData != null) {
    472                 setDefaultApplicationInternal(applicationData.mPackageName, context, userId);
    473             }
    474         }
    475 
    476         // If we found a package, make sure AppOps permissions are set up correctly
    477         if (applicationData != null) {
    478             AppOpsManager appOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
    479 
    480             // We can only call checkOp if we are privileged (updateIfNeeded) or if the app we
    481             // are checking is for our current uid. Doing this check from the unprivileged current
    482             // SMS app allows us to tell the current SMS app that it is not in a good state and
    483             // needs to ask to be the current SMS app again to work properly.
    484             if (updateIfNeeded || applicationData.mUid == android.os.Process.myUid()) {
    485                 // Verify that the SMS app has permissions
    486                 int mode = appOps.checkOp(AppOpsManager.OP_WRITE_SMS, applicationData.mUid,
    487                         applicationData.mPackageName);
    488                 if (mode != AppOpsManager.MODE_ALLOWED) {
    489                     Rlog.e(LOG_TAG, applicationData.mPackageName + " lost OP_WRITE_SMS: " +
    490                             (updateIfNeeded ? " (fixing)" : " (no permission to fix)"));
    491                     if (updateIfNeeded) {
    492                         appOps.setMode(AppOpsManager.OP_WRITE_SMS, applicationData.mUid,
    493                                 applicationData.mPackageName, AppOpsManager.MODE_ALLOWED);
    494                     } else {
    495                         // We can not return a package if permissions are not set up correctly
    496                         applicationData = null;
    497                     }
    498                 }
    499             }
    500 
    501             // We can only verify the phone and BT app's permissions from a privileged caller
    502             if (updateIfNeeded) {
    503                 // Ensure this component is still configured as the preferred activity. Usually the
    504                 // current SMS app will already be the preferred activity - but checking whether or
    505                 // not this is true is just as expensive as reconfiguring the preferred activity so
    506                 // we just reconfigure every time.
    507                 PackageManager packageManager = context.getPackageManager();
    508                 configurePreferredActivity(packageManager, new ComponentName(
    509                         applicationData.mPackageName, applicationData.mSendToClass),
    510                         userId);
    511                 // Assign permission to special system apps
    512                 assignWriteSmsPermissionToSystemApp(context, packageManager, appOps,
    513                         PHONE_PACKAGE_NAME);
    514                 assignWriteSmsPermissionToSystemApp(context, packageManager, appOps,
    515                         BLUETOOTH_PACKAGE_NAME);
    516                 assignWriteSmsPermissionToSystemApp(context, packageManager, appOps,
    517                         MMS_SERVICE_PACKAGE_NAME);
    518                 assignWriteSmsPermissionToSystemApp(context, packageManager, appOps,
    519                         TELEPHONY_PROVIDER_PACKAGE_NAME);
    520                 // Give WRITE_SMS AppOps permission to UID 1001 which contains multiple
    521                 // apps, all of them should be able to write to telephony provider.
    522                 // This is to allow the proxy package permission check in telephony provider
    523                 // to pass.
    524                 assignWriteSmsPermissionToSystemUid(appOps, Process.PHONE_UID);
    525             }
    526         }
    527         if (DEBUG_MULTIUSER) {
    528             Log.i(LOG_TAG, "getApplication returning appData=" + applicationData);
    529         }
    530         return applicationData;
    531     }
    532 
    533     /**
    534      * Sets the specified package as the default SMS/MMS application. The caller of this method
    535      * needs to have permission to set AppOps and write to secure settings.
    536      */
    537     public static void setDefaultApplication(String packageName, Context context) {
    538         TelephonyManager tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
    539         if (!tm.isSmsCapable()) {
    540             // No phone, no SMS
    541             return;
    542         }
    543 
    544         final int userId = getIncomingUserId(context);
    545         final long token = Binder.clearCallingIdentity();
    546         try {
    547             setDefaultApplicationInternal(packageName, context, userId);
    548         } finally {
    549             Binder.restoreCallingIdentity(token);
    550         }
    551     }
    552 
    553     private static void setDefaultApplicationInternal(String packageName, Context context,
    554             int userId) {
    555         // Get old package name
    556         String oldPackageName = Settings.Secure.getStringForUser(context.getContentResolver(),
    557                 Settings.Secure.SMS_DEFAULT_APPLICATION, userId);
    558 
    559         if (DEBUG_MULTIUSER) {
    560             Log.i(LOG_TAG, "setDefaultApplicationInternal old=" + oldPackageName +
    561                     " new=" + packageName);
    562         }
    563 
    564         if (packageName != null && oldPackageName != null && packageName.equals(oldPackageName)) {
    565             // No change
    566             return;
    567         }
    568 
    569         // We only make the change if the new package is valid
    570         PackageManager packageManager = context.getPackageManager();
    571         Collection<SmsApplicationData> applications = getApplicationCollection(context);
    572         SmsApplicationData oldAppData = oldPackageName != null ?
    573                 getApplicationForPackage(applications, oldPackageName) : null;
    574         SmsApplicationData applicationData = getApplicationForPackage(applications, packageName);
    575         if (applicationData != null) {
    576             // Ignore OP_WRITE_SMS for the previously configured default SMS app.
    577             AppOpsManager appOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
    578             if (oldPackageName != null) {
    579                 try {
    580                     PackageInfo info = packageManager.getPackageInfoAsUser(oldPackageName,
    581                             0, userId);
    582                     appOps.setMode(AppOpsManager.OP_WRITE_SMS, info.applicationInfo.uid,
    583                             oldPackageName, AppOpsManager.MODE_IGNORED);
    584                 } catch (NameNotFoundException e) {
    585                     Rlog.w(LOG_TAG, "Old SMS package not found: " + oldPackageName);
    586                 }
    587             }
    588 
    589             // Update the secure setting.
    590             Settings.Secure.putStringForUser(context.getContentResolver(),
    591                     Settings.Secure.SMS_DEFAULT_APPLICATION, applicationData.mPackageName,
    592                     userId);
    593 
    594             // Configure this as the preferred activity for SENDTO sms/mms intents
    595             configurePreferredActivity(packageManager, new ComponentName(
    596                     applicationData.mPackageName, applicationData.mSendToClass), userId);
    597 
    598             // Allow OP_WRITE_SMS for the newly configured default SMS app.
    599             appOps.setMode(AppOpsManager.OP_WRITE_SMS, applicationData.mUid,
    600                     applicationData.mPackageName, AppOpsManager.MODE_ALLOWED);
    601 
    602             // Assign permission to special system apps
    603             assignWriteSmsPermissionToSystemApp(context, packageManager, appOps,
    604                     PHONE_PACKAGE_NAME);
    605             assignWriteSmsPermissionToSystemApp(context, packageManager, appOps,
    606                     BLUETOOTH_PACKAGE_NAME);
    607             assignWriteSmsPermissionToSystemApp(context, packageManager, appOps,
    608                     MMS_SERVICE_PACKAGE_NAME);
    609             assignWriteSmsPermissionToSystemApp(context, packageManager, appOps,
    610                     TELEPHONY_PROVIDER_PACKAGE_NAME);
    611             // Give WRITE_SMS AppOps permission to UID 1001 which contains multiple
    612             // apps, all of them should be able to write to telephony provider.
    613             // This is to allow the proxy package permission check in telephony provider
    614             // to pass.
    615             assignWriteSmsPermissionToSystemUid(appOps, Process.PHONE_UID);
    616 
    617             if (DEBUG_MULTIUSER) {
    618                 Log.i(LOG_TAG, "setDefaultApplicationInternal oldAppData=" + oldAppData);
    619             }
    620             if (oldAppData != null && oldAppData.mSmsAppChangedReceiverClass != null) {
    621                 // Notify the old sms app that it's no longer the default
    622                 final Intent oldAppIntent =
    623                         new Intent(Telephony.Sms.Intents.ACTION_DEFAULT_SMS_PACKAGE_CHANGED);
    624                 final ComponentName component = new ComponentName(oldAppData.mPackageName,
    625                         oldAppData.mSmsAppChangedReceiverClass);
    626                 oldAppIntent.setComponent(component);
    627                 oldAppIntent.putExtra(Telephony.Sms.Intents.EXTRA_IS_DEFAULT_SMS_APP, false);
    628                 if (DEBUG_MULTIUSER) {
    629                     Log.i(LOG_TAG, "setDefaultApplicationInternal old=" + oldAppData.mPackageName);
    630                 }
    631                 context.sendBroadcast(oldAppIntent);
    632             }
    633             // Notify the new sms app that it's now the default (if the new sms app has a receiver
    634             // to handle the changed default sms intent).
    635             if (DEBUG_MULTIUSER) {
    636                 Log.i(LOG_TAG, "setDefaultApplicationInternal new applicationData=" +
    637                         applicationData);
    638             }
    639             if (applicationData.mSmsAppChangedReceiverClass != null) {
    640                 final Intent intent =
    641                         new Intent(Telephony.Sms.Intents.ACTION_DEFAULT_SMS_PACKAGE_CHANGED);
    642                 final ComponentName component = new ComponentName(applicationData.mPackageName,
    643                         applicationData.mSmsAppChangedReceiverClass);
    644                 intent.setComponent(component);
    645                 intent.putExtra(Telephony.Sms.Intents.EXTRA_IS_DEFAULT_SMS_APP, true);
    646                 if (DEBUG_MULTIUSER) {
    647                     Log.i(LOG_TAG, "setDefaultApplicationInternal new=" + packageName);
    648                 }
    649                 context.sendBroadcast(intent);
    650             }
    651             MetricsLogger.action(context, MetricsEvent.ACTION_DEFAULT_SMS_APP_CHANGED,
    652                     applicationData.mPackageName);
    653         }
    654     }
    655 
    656     /**
    657      * Assign WRITE_SMS AppOps permission to some special system apps.
    658      *
    659      * @param context The context
    660      * @param packageManager The package manager instance
    661      * @param appOps The AppOps manager instance
    662      * @param packageName The package name of the system app
    663      */
    664     private static void assignWriteSmsPermissionToSystemApp(Context context,
    665             PackageManager packageManager, AppOpsManager appOps, String packageName) {
    666         // First check package signature matches the caller's package signature.
    667         // Since this class is only used internally by the system, this check makes sure
    668         // the package signature matches system signature.
    669         final int result = packageManager.checkSignatures(context.getPackageName(), packageName);
    670         if (result != PackageManager.SIGNATURE_MATCH) {
    671             Rlog.e(LOG_TAG, packageName + " does not have system signature");
    672             return;
    673         }
    674         try {
    675             PackageInfo info = packageManager.getPackageInfo(packageName, 0);
    676             int mode = appOps.checkOp(AppOpsManager.OP_WRITE_SMS, info.applicationInfo.uid,
    677                     packageName);
    678             if (mode != AppOpsManager.MODE_ALLOWED) {
    679                 Rlog.w(LOG_TAG, packageName + " does not have OP_WRITE_SMS:  (fixing)");
    680                 appOps.setMode(AppOpsManager.OP_WRITE_SMS, info.applicationInfo.uid,
    681                         packageName, AppOpsManager.MODE_ALLOWED);
    682             }
    683         } catch (NameNotFoundException e) {
    684             // No whitelisted system app on this device
    685             Rlog.e(LOG_TAG, "Package not found: " + packageName);
    686         }
    687 
    688     }
    689 
    690     private static void assignWriteSmsPermissionToSystemUid(AppOpsManager appOps, int uid) {
    691         appOps.setUidMode(AppOpsManager.OP_WRITE_SMS, uid, AppOpsManager.MODE_ALLOWED);
    692     }
    693 
    694     /**
    695      * Tracks package changes and ensures that the default SMS app is always configured to be the
    696      * preferred activity for SENDTO sms/mms intents.
    697      */
    698     private static final class SmsPackageMonitor extends PackageMonitor {
    699         final Context mContext;
    700 
    701         public SmsPackageMonitor(Context context) {
    702             super();
    703             mContext = context;
    704         }
    705 
    706         @Override
    707         public void onPackageDisappeared(String packageName, int reason) {
    708             onPackageChanged();
    709         }
    710 
    711         @Override
    712         public void onPackageAppeared(String packageName, int reason) {
    713             onPackageChanged();
    714         }
    715 
    716         @Override
    717         public void onPackageModified(String packageName) {
    718             onPackageChanged();
    719         }
    720 
    721         private void onPackageChanged() {
    722             PackageManager packageManager = mContext.getPackageManager();
    723             Context userContext = mContext;
    724             final int userId = getSendingUserId();
    725             if (userId != UserHandle.USER_SYSTEM) {
    726                 try {
    727                     userContext = mContext.createPackageContextAsUser(mContext.getPackageName(), 0,
    728                             new UserHandle(userId));
    729                 } catch (NameNotFoundException nnfe) {
    730                     if (DEBUG_MULTIUSER) {
    731                         Log.w(LOG_TAG, "Unable to create package context for user " + userId);
    732                     }
    733                 }
    734             }
    735             // Ensure this component is still configured as the preferred activity
    736             ComponentName componentName = getDefaultSendToApplication(userContext, true);
    737             if (componentName != null) {
    738                 configurePreferredActivity(packageManager, componentName, userId);
    739             }
    740         }
    741     }
    742 
    743     public static void initSmsPackageMonitor(Context context) {
    744         sSmsPackageMonitor = new SmsPackageMonitor(context);
    745         sSmsPackageMonitor.register(context, context.getMainLooper(), UserHandle.ALL, false);
    746     }
    747 
    748     private static void configurePreferredActivity(PackageManager packageManager,
    749             ComponentName componentName, int userId) {
    750         // Add the four activity preferences we want to direct to this app.
    751         replacePreferredActivity(packageManager, componentName, userId, SCHEME_SMS);
    752         replacePreferredActivity(packageManager, componentName, userId, SCHEME_SMSTO);
    753         replacePreferredActivity(packageManager, componentName, userId, SCHEME_MMS);
    754         replacePreferredActivity(packageManager, componentName, userId, SCHEME_MMSTO);
    755     }
    756 
    757     /**
    758      * Updates the ACTION_SENDTO activity to the specified component for the specified scheme.
    759      */
    760     private static void replacePreferredActivity(PackageManager packageManager,
    761             ComponentName componentName, int userId, String scheme) {
    762         // Build the set of existing activities that handle this scheme
    763         Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.fromParts(scheme, "", null));
    764         List<ResolveInfo> resolveInfoList = packageManager.queryIntentActivitiesAsUser(
    765                 intent, PackageManager.MATCH_DEFAULT_ONLY | PackageManager.GET_RESOLVED_FILTER,
    766                 userId);
    767 
    768         // Build the set of ComponentNames for these activities
    769         final int n = resolveInfoList.size();
    770         ComponentName[] set = new ComponentName[n];
    771         for (int i = 0; i < n; i++) {
    772             ResolveInfo info = resolveInfoList.get(i);
    773             set[i] = new ComponentName(info.activityInfo.packageName, info.activityInfo.name);
    774         }
    775 
    776         // Update the preferred SENDTO activity for the specified scheme
    777         IntentFilter intentFilter = new IntentFilter();
    778         intentFilter.addAction(Intent.ACTION_SENDTO);
    779         intentFilter.addCategory(Intent.CATEGORY_DEFAULT);
    780         intentFilter.addDataScheme(scheme);
    781         packageManager.replacePreferredActivityAsUser(intentFilter,
    782                 IntentFilter.MATCH_CATEGORY_SCHEME + IntentFilter.MATCH_ADJUSTMENT_NORMAL,
    783                 set, componentName, userId);
    784     }
    785 
    786     /**
    787      * Returns SmsApplicationData for this package if this package is capable of being set as the
    788      * default SMS application.
    789      */
    790     public static SmsApplicationData getSmsApplicationData(String packageName, Context context) {
    791         Collection<SmsApplicationData> applications = getApplicationCollection(context);
    792         return getApplicationForPackage(applications, packageName);
    793     }
    794 
    795     /**
    796      * Gets the default SMS application
    797      * @param context context from the calling app
    798      * @param updateIfNeeded update the default app if there is no valid default app configured.
    799      * @return component name of the app and class to deliver SMS messages to
    800      */
    801     public static ComponentName getDefaultSmsApplication(Context context, boolean updateIfNeeded) {
    802         int userId = getIncomingUserId(context);
    803         final long token = Binder.clearCallingIdentity();
    804         try {
    805             ComponentName component = null;
    806             SmsApplicationData smsApplicationData = getApplication(context, updateIfNeeded,
    807                     userId);
    808             if (smsApplicationData != null) {
    809                 component = new ComponentName(smsApplicationData.mPackageName,
    810                         smsApplicationData.mSmsReceiverClass);
    811             }
    812             return component;
    813         } finally {
    814             Binder.restoreCallingIdentity(token);
    815         }
    816     }
    817 
    818     /**
    819      * Gets the default MMS application
    820      * @param context context from the calling app
    821      * @param updateIfNeeded update the default app if there is no valid default app configured.
    822      * @return component name of the app and class to deliver MMS messages to
    823      */
    824     public static ComponentName getDefaultMmsApplication(Context context, boolean updateIfNeeded) {
    825         int userId = getIncomingUserId(context);
    826         final long token = Binder.clearCallingIdentity();
    827         try {
    828             ComponentName component = null;
    829             SmsApplicationData smsApplicationData = getApplication(context, updateIfNeeded,
    830                     userId);
    831             if (smsApplicationData != null) {
    832                 component = new ComponentName(smsApplicationData.mPackageName,
    833                         smsApplicationData.mMmsReceiverClass);
    834             }
    835             return component;
    836         } finally {
    837             Binder.restoreCallingIdentity(token);
    838         }
    839     }
    840 
    841     /**
    842      * Gets the default Respond Via Message application
    843      * @param context context from the calling app
    844      * @param updateIfNeeded update the default app if there is no valid default app configured.
    845      * @return component name of the app and class to direct Respond Via Message intent to
    846      */
    847     public static ComponentName getDefaultRespondViaMessageApplication(Context context,
    848             boolean updateIfNeeded) {
    849         int userId = getIncomingUserId(context);
    850         final long token = Binder.clearCallingIdentity();
    851         try {
    852             ComponentName component = null;
    853             SmsApplicationData smsApplicationData = getApplication(context, updateIfNeeded,
    854                     userId);
    855             if (smsApplicationData != null) {
    856                 component = new ComponentName(smsApplicationData.mPackageName,
    857                         smsApplicationData.mRespondViaMessageClass);
    858             }
    859             return component;
    860         } finally {
    861             Binder.restoreCallingIdentity(token);
    862         }
    863     }
    864 
    865     /**
    866      * Gets the default Send To (smsto) application.
    867      * <p>
    868      * Caller must pass in the correct user context if calling from a singleton service.
    869      * @param context context from the calling app
    870      * @param updateIfNeeded update the default app if there is no valid default app configured.
    871      * @return component name of the app and class to direct SEND_TO (smsto) intent to
    872      */
    873     public static ComponentName getDefaultSendToApplication(Context context,
    874             boolean updateIfNeeded) {
    875         int userId = getIncomingUserId(context);
    876         final long token = Binder.clearCallingIdentity();
    877         try {
    878             ComponentName component = null;
    879             SmsApplicationData smsApplicationData = getApplication(context, updateIfNeeded,
    880                     userId);
    881             if (smsApplicationData != null) {
    882                 component = new ComponentName(smsApplicationData.mPackageName,
    883                         smsApplicationData.mSendToClass);
    884             }
    885             return component;
    886         } finally {
    887             Binder.restoreCallingIdentity(token);
    888         }
    889     }
    890 
    891     /**
    892      * Gets the default application that handles external changes to the SmsProvider and
    893      * MmsProvider.
    894      * @param context context from the calling app
    895      * @param updateIfNeeded update the default app if there is no valid default app configured.
    896      * @return component name of the app and class to deliver change intents to
    897      */
    898     public static ComponentName getDefaultExternalTelephonyProviderChangedApplication(
    899             Context context, boolean updateIfNeeded) {
    900         int userId = getIncomingUserId(context);
    901         final long token = Binder.clearCallingIdentity();
    902         try {
    903             ComponentName component = null;
    904             SmsApplicationData smsApplicationData = getApplication(context, updateIfNeeded,
    905                     userId);
    906             if (smsApplicationData != null
    907                     && smsApplicationData.mProviderChangedReceiverClass != null) {
    908                 component = new ComponentName(smsApplicationData.mPackageName,
    909                         smsApplicationData.mProviderChangedReceiverClass);
    910             }
    911             return component;
    912         } finally {
    913             Binder.restoreCallingIdentity(token);
    914         }
    915     }
    916 
    917     /**
    918      * Gets the default application that handles sim full event.
    919      * @param context context from the calling app
    920      * @param updateIfNeeded update the default app if there is no valid default app configured.
    921      * @return component name of the app and class to deliver change intents to
    922      */
    923     public static ComponentName getDefaultSimFullApplication(
    924             Context context, boolean updateIfNeeded) {
    925         int userId = getIncomingUserId(context);
    926         final long token = Binder.clearCallingIdentity();
    927         try {
    928             ComponentName component = null;
    929             SmsApplicationData smsApplicationData = getApplication(context, updateIfNeeded,
    930                     userId);
    931             if (smsApplicationData != null
    932                     && smsApplicationData.mSimFullReceiverClass != null) {
    933                 component = new ComponentName(smsApplicationData.mPackageName,
    934                         smsApplicationData.mSimFullReceiverClass);
    935             }
    936             return component;
    937         } finally {
    938             Binder.restoreCallingIdentity(token);
    939         }
    940     }
    941 
    942     /**
    943      * Returns whether need to write the SMS message to SMS database for this package.
    944      * <p>
    945      * Caller must pass in the correct user context if calling from a singleton service.
    946      */
    947     public static boolean shouldWriteMessageForPackage(String packageName, Context context) {
    948         if (SmsManager.getDefault().getAutoPersisting()) {
    949             return true;
    950         }
    951         return !isDefaultSmsApplication(context, packageName);
    952     }
    953 
    954     /**
    955      * Check if a package is default sms app (or equivalent, like bluetooth)
    956      *
    957      * @param context context from the calling app
    958      * @param packageName the name of the package to be checked
    959      * @return true if the package is default sms app or bluetooth
    960      */
    961     public static boolean isDefaultSmsApplication(Context context, String packageName) {
    962         if (packageName == null) {
    963             return false;
    964         }
    965         final String defaultSmsPackage = getDefaultSmsApplicationPackageName(context);
    966         if ((defaultSmsPackage != null && defaultSmsPackage.equals(packageName))
    967                 || BLUETOOTH_PACKAGE_NAME.equals(packageName)) {
    968             return true;
    969         }
    970         return false;
    971     }
    972 
    973     private static String getDefaultSmsApplicationPackageName(Context context) {
    974         final ComponentName component = getDefaultSmsApplication(context, false);
    975         if (component != null) {
    976             return component.getPackageName();
    977         }
    978         return null;
    979     }
    980 }
    981