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