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