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