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