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