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