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