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