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