1 /* 2 * Copyright (C) 2017 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.ims; 18 19 import android.Manifest; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.app.ActivityManager; 23 import android.content.BroadcastReceiver; 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.PackageManager; 29 import android.content.pm.ResolveInfo; 30 import android.content.pm.ServiceInfo; 31 import android.os.AsyncResult; 32 import android.os.Handler; 33 import android.os.HandlerExecutor; 34 import android.os.HandlerThread; 35 import android.os.Looper; 36 import android.os.Message; 37 import android.os.PersistableBundle; 38 import android.os.RemoteException; 39 import android.os.UserHandle; 40 import android.os.UserManager; 41 import android.telephony.CarrierConfigManager; 42 import android.telephony.SubscriptionManager; 43 import android.telephony.TelephonyManager; 44 import android.telephony.ims.ImsService; 45 import android.telephony.ims.aidl.IImsConfig; 46 import android.telephony.ims.aidl.IImsRegistration; 47 import android.telephony.ims.feature.ImsFeature; 48 import android.telephony.ims.feature.MmTelFeature; 49 import android.telephony.ims.stub.ImsFeatureConfiguration; 50 import android.text.TextUtils; 51 import android.util.ArrayMap; 52 import android.util.ArraySet; 53 import android.util.LocalLog; 54 import android.util.Log; 55 import android.util.Pair; 56 import android.util.SparseArray; 57 import android.util.SparseIntArray; 58 59 import com.android.ims.ImsFeatureBinderRepository; 60 import com.android.ims.ImsFeatureContainer; 61 import com.android.ims.internal.IImsServiceFeatureCallback; 62 import com.android.internal.annotations.VisibleForTesting; 63 import com.android.internal.os.SomeArgs; 64 import com.android.internal.telephony.PhoneConfigurationManager; 65 import com.android.internal.telephony.flags.FeatureFlags; 66 import com.android.internal.telephony.util.WorkerThread; 67 import com.android.internal.util.IndentingPrintWriter; 68 69 import java.io.FileDescriptor; 70 import java.io.PrintWriter; 71 import java.util.ArrayList; 72 import java.util.Collections; 73 import java.util.HashMap; 74 import java.util.HashSet; 75 import java.util.List; 76 import java.util.Map; 77 import java.util.Objects; 78 import java.util.Set; 79 import java.util.concurrent.CompletableFuture; 80 import java.util.concurrent.LinkedBlockingQueue; 81 import java.util.concurrent.TimeUnit; 82 import java.util.stream.Collectors; 83 84 /** 85 * Creates a list of ImsServices that are available to bind to based on the Device configuration 86 * overlay values "config_ims_rcs_package" and "config_ims_mmtel_package" as well as Carrier 87 * Configuration value "config_ims_rcs_package_override_string" and 88 * "config_ims_mmtel_package_override_string". 89 * These ImsServices are then bound to in the following order for each mmtel and rcs feature: 90 * 91 * 1. Carrier Config defined override value per SIM. 92 * 2. Device overlay default value (including no SIM case). 93 * 94 * ImsManager can then retrieve the binding to the correct ImsService using 95 * {@link #listenForFeature} on a per-slot and per feature basis. 96 */ 97 98 public class ImsResolver implements ImsServiceController.ImsServiceControllerCallbacks { 99 100 private static final String TAG = "ImsResolver"; 101 private static final int GET_IMS_SERVICE_TIMEOUT_MS = 5000; 102 103 @VisibleForTesting 104 public static final String METADATA_EMERGENCY_MMTEL_FEATURE = 105 "android.telephony.ims.EMERGENCY_MMTEL_FEATURE"; 106 @VisibleForTesting 107 public static final String METADATA_MMTEL_FEATURE = "android.telephony.ims.MMTEL_FEATURE"; 108 @VisibleForTesting 109 public static final String METADATA_RCS_FEATURE = "android.telephony.ims.RCS_FEATURE"; 110 // Overrides the correctness permission check of android.permission.BIND_IMS_SERVICE for any 111 // ImsService that is connecting to the platform. 112 // This should ONLY be used for testing and should not be used in production ImsServices. 113 private static final String METADATA_OVERRIDE_PERM_CHECK = "override_bind_check"; 114 115 // Based on updates from PackageManager 116 private static final int HANDLER_ADD_PACKAGE = 0; 117 // Based on updates from PackageManager 118 private static final int HANDLER_REMOVE_PACKAGE = 1; 119 // Based on updates from CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED 120 private static final int HANDLER_CONFIG_CHANGED = 2; 121 // A query has been started for an ImsService to relay the features they support. 122 private static final int HANDLER_START_DYNAMIC_FEATURE_QUERY = 3; 123 // A dynamic query to request ImsService features has completed. 124 private static final int HANDLER_DYNAMIC_FEATURE_CHANGE = 4; 125 // Testing: Overrides the current configuration for ImsService binding 126 private static final int HANDLER_OVERRIDE_IMS_SERVICE_CONFIG = 5; 127 // Based on boot complete indication. When this happens, there may be ImsServices that are not 128 // direct boot aware that need to be started. 129 private static final int HANDLER_BOOT_COMPLETE = 6; 130 // Sent when the number of slots has dynamically changed on the device. We will need to 131 // resize available ImsServiceController slots and perform dynamic queries again. 132 private static final int HANDLER_MSIM_CONFIGURATION_CHANGE = 7; 133 // clear any carrier ImsService test overrides. 134 private static final int HANDLER_CLEAR_CARRIER_IMS_SERVICE_CONFIG = 8; 135 // the user has switched 136 private static final int HANDLER_USER_SWITCHED = 9; 137 // A dynamic query has failed permanently, remove the package from being tracked 138 private static final int HANDLER_REMOVE_PACKAGE_PERM_ERROR = 10; 139 140 // Delay between dynamic ImsService queries. 141 private static final int DELAY_DYNAMIC_QUERY_MS = 5000; 142 143 private static HandlerThread sHandlerThread; 144 145 private static ImsResolver sInstance; 146 147 /** 148 * Create the ImsResolver Service singleton instance. 149 */ make(Context context, String defaultMmTelPackageName, String defaultRcsPackageName, int numSlots, ImsFeatureBinderRepository repo, FeatureFlags featureFlags)150 public static void make(Context context, String defaultMmTelPackageName, 151 String defaultRcsPackageName, int numSlots, ImsFeatureBinderRepository repo, 152 FeatureFlags featureFlags) { 153 if (sInstance == null) { 154 if (featureFlags.threadShred()) { 155 sInstance = new ImsResolver(context, defaultMmTelPackageName, defaultRcsPackageName, 156 numSlots, repo, WorkerThread.get().getLooper(), featureFlags); 157 } else { 158 sHandlerThread = new HandlerThread(TAG); 159 sHandlerThread.start(); 160 sInstance = new ImsResolver(context, defaultMmTelPackageName, defaultRcsPackageName, 161 numSlots, repo, sHandlerThread.getLooper(), featureFlags); 162 } 163 } 164 } 165 166 /** 167 * @return The ImsResolver Service instance. May be {@code null} if no ImsResolver was created 168 * due to IMS not being supported. 169 */ getInstance()170 public static @Nullable ImsResolver getInstance() { 171 return sInstance; 172 } 173 174 private static class OverrideConfig { 175 public final String packageName; 176 public final int slotId; 177 public final int userId; 178 public final boolean isCarrierService; 179 public final int[] featureTypes; 180 OverrideConfig(String pkgName, int slotIndex, int userIndex, boolean isCarrier, int[] features)181 OverrideConfig(String pkgName, int slotIndex, int userIndex, boolean isCarrier, 182 int[] features) { 183 packageName = pkgName; 184 slotId = slotIndex; 185 userId = userIndex; 186 isCarrierService = isCarrier; 187 featureTypes = features; 188 } 189 } 190 191 /** 192 * Stores information about an ImsService, including the package name, class name, and features 193 * that the service supports. 194 */ 195 @VisibleForTesting 196 public static class ImsServiceInfo { 197 public final ComponentName name; 198 public final Set<UserHandle> users = new HashSet<>(); 199 // Determines if features were created from metadata in the manifest or through dynamic 200 // query. 201 public boolean featureFromMetadata = true; 202 public ImsServiceControllerFactory controllerFactory; 203 204 // Map slotId->Feature 205 private final HashSet<ImsFeatureConfiguration.FeatureSlotPair> mSupportedFeatures; 206 ImsServiceInfo(ComponentName componentName)207 public ImsServiceInfo(ComponentName componentName) { 208 name = componentName; 209 mSupportedFeatures = new HashSet<>(); 210 } 211 addFeatureForAllSlots(int numSlots, int feature)212 void addFeatureForAllSlots(int numSlots, int feature) { 213 for (int i = 0; i < numSlots; i++) { 214 mSupportedFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(i, feature)); 215 } 216 } 217 replaceFeatures(Set<ImsFeatureConfiguration.FeatureSlotPair> newFeatures)218 void replaceFeatures(Set<ImsFeatureConfiguration.FeatureSlotPair> newFeatures) { 219 mSupportedFeatures.clear(); 220 mSupportedFeatures.addAll(newFeatures); 221 } 222 223 @VisibleForTesting getSupportedFeatures()224 public Set<ImsFeatureConfiguration.FeatureSlotPair> getSupportedFeatures() { 225 return mSupportedFeatures; 226 } 227 228 @Override equals(Object o)229 public boolean equals(Object o) { 230 if (this == o) return true; 231 if (o == null || getClass() != o.getClass()) return false; 232 ImsServiceInfo that = (ImsServiceInfo) o; 233 return Objects.equals(name, that.name) && Objects.equals(users, that.users); 234 } 235 236 @Override hashCode()237 public int hashCode() { 238 return Objects.hash(name, users); 239 } 240 241 @Override toString()242 public String toString() { 243 return "[ImsServiceInfo] name=" 244 + name 245 + ", user=" 246 + users 247 + ",featureFromMetadata=" 248 + featureFromMetadata 249 + "," 250 + printFeatures(mSupportedFeatures); 251 } 252 } 253 254 private final BroadcastReceiver mUserReceiver = new BroadcastReceiver() { 255 @Override 256 public void onReceive(Context context, Intent intent) { 257 final String action = intent.getAction(); 258 final UserHandle handle = intent.getParcelableExtra(Intent.EXTRA_USER, 259 UserHandle.class); 260 switch (action) { 261 case Intent.ACTION_USER_SWITCHED -> 262 mHandler.obtainMessage(HANDLER_USER_SWITCHED, handle).sendToTarget(); 263 } 264 } 265 }; 266 267 // Receives broadcasts from the system involving changes to the installed applications. If 268 // an ImsService that we are configured to use is installed, we must bind to it. 269 private final BroadcastReceiver mAppChangedReceiver = new BroadcastReceiver() { 270 @Override 271 public void onReceive(Context context, Intent intent) { 272 final String action = intent.getAction(); 273 final String packageName = intent.getData().getSchemeSpecificPart(); 274 switch (action) { 275 case Intent.ACTION_PACKAGE_ADDED: 276 // intentional fall-through 277 case Intent.ACTION_PACKAGE_REPLACED: 278 // intentional fall-through 279 case Intent.ACTION_PACKAGE_CHANGED: 280 mHandler.obtainMessage(HANDLER_ADD_PACKAGE, packageName).sendToTarget(); 281 break; 282 case Intent.ACTION_PACKAGE_REMOVED: 283 mHandler.obtainMessage(HANDLER_REMOVE_PACKAGE, packageName).sendToTarget(); 284 break; 285 default: 286 return; 287 } 288 } 289 }; 290 291 // Receives the broadcast that a new Carrier Config has been loaded in order to possibly 292 // unbind from one service and bind to another. 293 private final BroadcastReceiver mConfigChangedReceiver = new BroadcastReceiver() { 294 @Override 295 public void onReceive(Context context, Intent intent) { 296 297 int slotId = intent.getIntExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, 298 SubscriptionManager.INVALID_SIM_SLOT_INDEX); 299 300 if (slotId == SubscriptionManager.INVALID_SIM_SLOT_INDEX) { 301 Log.i(TAG, "Received CCC for invalid slot id."); 302 return; 303 } 304 305 int subId = intent.getIntExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, 306 SubscriptionManager.INVALID_SUBSCRIPTION_ID); 307 int slotSimState = mTelephonyManagerProxy.getSimState(mContext, slotId); 308 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID 309 && (slotSimState != TelephonyManager.SIM_STATE_ABSENT 310 && slotSimState != TelephonyManager.SIM_STATE_NOT_READY)) { 311 // We only care about carrier config updates that happen when a slot is known to be 312 // absent, the subscription is disabled (not ready), or populated and the carrier 313 // config has been loaded. 314 Log.i(TAG, "Received CCC for slot " + slotId + " and sim state " 315 + slotSimState + ", ignoring."); 316 return; 317 } 318 319 Log.i(TAG, "Received Carrier Config Changed for SlotId: " + slotId + ", SubId: " 320 + subId + ", sim state: " + slotSimState); 321 322 mHandler.obtainMessage(HANDLER_CONFIG_CHANGED, slotId, subId).sendToTarget(); 323 } 324 }; 325 326 // Receives the broadcast that the device has finished booting (and the device is no longer 327 // encrypted). 328 private final BroadcastReceiver mBootCompleted = new BroadcastReceiver() { 329 @Override 330 public void onReceive(Context context, Intent intent) { 331 Log.i(TAG, "Received BOOT_COMPLETED"); 332 // Recalculate all cached services to pick up ones that have just been enabled since 333 // boot complete. 334 mHandler.obtainMessage(HANDLER_BOOT_COMPLETE, null).sendToTarget(); 335 } 336 }; 337 338 /** 339 * Testing interface used to mock ActivityManager in testing 340 */ 341 @VisibleForTesting 342 public interface ActivityManagerProxy { 343 /** 344 * @return The current user 345 */ getCurrentUser()346 UserHandle getCurrentUser(); 347 } 348 349 /** 350 * Testing interface used to mock SubscriptionManager in testing 351 */ 352 @VisibleForTesting 353 public interface SubscriptionManagerProxy { 354 /** 355 * Mock-able interface for {@link SubscriptionManager#getSubscriptionId(int)} used for 356 * testing. 357 */ getSubId(int slotId)358 int getSubId(int slotId); 359 /** 360 * Mock-able interface for {@link SubscriptionManager#getSlotIndex(int)} used for testing. 361 */ getSlotIndex(int subId)362 int getSlotIndex(int subId); 363 } 364 365 /** 366 * Testing interface used to stub out TelephonyManager dependencies. 367 */ 368 @VisibleForTesting 369 public interface TelephonyManagerProxy { 370 /** 371 * @return the SIM state for the slot ID specified. 372 */ getSimState(Context context, int slotId)373 int getSimState(Context context, int slotId); 374 } 375 376 private TelephonyManagerProxy mTelephonyManagerProxy = new TelephonyManagerProxy() { 377 @Override 378 public int getSimState(Context context, int slotId) { 379 TelephonyManager tm = context.getSystemService(TelephonyManager.class); 380 if (tm == null) { 381 return TelephonyManager.SIM_STATE_UNKNOWN; 382 } 383 return tm.getSimState(slotId); 384 } 385 }; 386 387 private SubscriptionManagerProxy mSubscriptionManagerProxy = new SubscriptionManagerProxy() { 388 @Override 389 public int getSubId(int slotId) { 390 return SubscriptionManager.getSubscriptionId(slotId); 391 } 392 393 @Override 394 public int getSlotIndex(int subId) { 395 return SubscriptionManager.getSlotIndex(subId); 396 } 397 }; 398 399 private ActivityManagerProxy mActivityManagerProxy = new ActivityManagerProxy() { 400 @Override 401 public UserHandle getCurrentUser() { 402 return UserHandle.of(ActivityManager.getCurrentUser()); 403 } 404 }; 405 406 /** 407 * Testing interface for injecting mock ImsServiceControllers. 408 */ 409 @VisibleForTesting 410 public interface ImsServiceControllerFactory { 411 /** 412 * @return the Service Interface String used for binding the ImsService. 413 */ getServiceInterface()414 String getServiceInterface(); 415 /** 416 * @return the ImsServiceController created using the context and componentName supplied. 417 */ create(Context context, ComponentName componentName, ImsServiceController.ImsServiceControllerCallbacks callbacks, ImsFeatureBinderRepository repo, FeatureFlags featureFlags)418 ImsServiceController create(Context context, ComponentName componentName, 419 ImsServiceController.ImsServiceControllerCallbacks callbacks, 420 ImsFeatureBinderRepository repo, FeatureFlags featureFlags); 421 } 422 423 private ImsServiceControllerFactory mImsServiceControllerFactory = 424 new ImsServiceControllerFactory() { 425 426 @Override 427 public String getServiceInterface() { 428 return ImsService.SERVICE_INTERFACE; 429 } 430 431 @Override 432 public ImsServiceController create(Context context, ComponentName componentName, 433 ImsServiceController.ImsServiceControllerCallbacks callbacks, 434 ImsFeatureBinderRepository repo, FeatureFlags featureFlags) { 435 return new ImsServiceController(context, componentName, callbacks, repo, 436 featureFlags); 437 } 438 }; 439 440 /** 441 * Used for testing. 442 */ 443 @VisibleForTesting 444 public interface ImsDynamicQueryManagerFactory { create(Context context, ImsServiceFeatureQueryManager.Listener listener)445 ImsServiceFeatureQueryManager create(Context context, 446 ImsServiceFeatureQueryManager.Listener listener); 447 } 448 449 private final ImsServiceControllerFactory mImsServiceControllerFactoryCompat = 450 new ImsServiceControllerFactory() { 451 @Override 452 public String getServiceInterface() { 453 return android.telephony.ims.compat.ImsService.SERVICE_INTERFACE; 454 } 455 456 @Override 457 public ImsServiceController create(Context context, ComponentName componentName, 458 ImsServiceController.ImsServiceControllerCallbacks callbacks, 459 ImsFeatureBinderRepository repo, FeatureFlags featureFlags) { 460 return new ImsServiceControllerCompat(context, componentName, callbacks, repo); 461 } 462 }; 463 464 private ImsDynamicQueryManagerFactory mDynamicQueryManagerFactory = 465 ImsServiceFeatureQueryManager::new; 466 467 private final CarrierConfigManager mCarrierConfigManager; 468 private final Context mContext; 469 // Special context created only for registering receivers for all users using UserHandle.ALL. 470 // The lifetime of a registered receiver is bounded by the lifetime of the context it's 471 // registered through, so we must retain the Context as long as we need the receiver to be 472 // active. 473 private final Context mReceiverContext; 474 private final ImsFeatureBinderRepository mRepo; 475 // Locks mBoundImsServicesByFeature only. Be careful to avoid deadlocks from 476 // ImsServiceController callbacks. 477 private final Object mBoundServicesLock = new Object(); 478 private int mNumSlots; 479 // Array index corresponds to slot, per slot there is a feature->package name mapping. 480 // should only be accessed from handler 481 private final SparseArray<Map<Integer, String>> mCarrierServices; 482 // Package name of the default device services, Maps ImsFeature -> packageName. 483 // Must synchronize on this object to access. 484 private final Map<Integer, String> mDeviceServices = new ArrayMap<>(); 485 // Persistent Logging 486 private final LocalLog mEventLog = new LocalLog(32); 487 488 private boolean mBootCompletedHandlerRan = false; 489 private boolean mCarrierConfigReceived = false; 490 491 // Synchronize all events on a handler to ensure that the cache includes the most recent 492 // version of the installed ImsServices. 493 private final Handler mHandler; 494 495 private final FeatureFlags mFeatureFlags; 496 497 private class ResolverHandler extends Handler { 498 ResolverHandler(Looper looper)499 ResolverHandler(Looper looper) { 500 super(looper); 501 } 502 503 @Override handleMessage(Message msg)504 public void handleMessage(Message msg) { 505 switch (msg.what) { 506 case HANDLER_ADD_PACKAGE: { 507 String packageName = (String) msg.obj; 508 maybeAddedImsService(packageName); 509 break; 510 } 511 case HANDLER_REMOVE_PACKAGE: { 512 String packageName = (String) msg.obj; 513 maybeRemovedImsService(packageName); 514 break; 515 } 516 case HANDLER_REMOVE_PACKAGE_PERM_ERROR: { 517 Pair<String, UserHandle> packageInfo = (Pair<String, UserHandle>) msg.obj; 518 maybeRemovedImsServiceForUser(packageInfo.first, packageInfo.second); 519 break; 520 } 521 case HANDLER_BOOT_COMPLETE: { 522 if (!mBootCompletedHandlerRan) { 523 mBootCompletedHandlerRan = true; 524 mEventLog.log("handling BOOT_COMPLETE"); 525 if (mCarrierConfigReceived) { 526 mEventLog.log("boot complete - reeval"); 527 // Re-evaluate bound services for all slots after requerying 528 //packagemanager 529 maybeAddedImsService(null /*packageName*/); 530 } else { 531 mEventLog.log("boot complete - update cache"); 532 // Do not bind any ImsServices yet, just update the cache to include new 533 // services. All will be re-evaluated after first carrier config changed 534 updateInstalledServicesCache(); 535 } 536 } 537 break; 538 } 539 case HANDLER_CONFIG_CHANGED: { 540 int slotId = msg.arg1; 541 int subId = msg.arg2; 542 // If the msim config has changed and there is a residual event for an invalid 543 // slot,ignore. 544 if (slotId >= mNumSlots) { 545 Log.w(TAG, "HANDLER_CONFIG_CHANGED for invalid slotid=" + slotId); 546 break; 547 } 548 mCarrierConfigReceived = true; 549 carrierConfigChanged(slotId, subId); 550 break; 551 } 552 case HANDLER_START_DYNAMIC_FEATURE_QUERY: { 553 ImsServiceInfo info = (ImsServiceInfo) msg.obj; 554 startDynamicQuery(info); 555 break; 556 } 557 case HANDLER_DYNAMIC_FEATURE_CHANGE: { 558 SomeArgs args = (SomeArgs) msg.obj; 559 ComponentName name = (ComponentName) args.arg1; 560 Set<ImsFeatureConfiguration.FeatureSlotPair> features = 561 (Set<ImsFeatureConfiguration.FeatureSlotPair>) args.arg2; 562 args.recycle(); 563 dynamicQueryComplete(name, features); 564 break; 565 } 566 case HANDLER_OVERRIDE_IMS_SERVICE_CONFIG: { 567 OverrideConfig config = (OverrideConfig) msg.obj; 568 setPackageNameUserOverride(config.packageName, config.userId); 569 Map<Integer, String> featureConfig = new HashMap<>(); 570 for (int featureType : config.featureTypes) { 571 featureConfig.put(featureType, config.packageName); 572 } 573 if (config.isCarrierService) { 574 overrideCarrierService(config.slotId, featureConfig); 575 } else { 576 overrideDeviceService(featureConfig); 577 } 578 break; 579 } 580 case HANDLER_MSIM_CONFIGURATION_CHANGE: { 581 AsyncResult result = (AsyncResult) msg.obj; 582 handleMsimConfigChange((Integer) result.result); 583 break; 584 } 585 case HANDLER_CLEAR_CARRIER_IMS_SERVICE_CONFIG: { 586 clearCarrierServiceOverrides(msg.arg1); 587 break; 588 } 589 case HANDLER_USER_SWITCHED: { 590 UserHandle handle = (UserHandle) msg.obj; 591 Log.i(TAG, "onUserSwitched=" + handle); 592 maybeAddedImsService(null); 593 } 594 default: 595 break; 596 } 597 } 598 } 599 600 private final HandlerExecutor mRunnableExecutor; 601 602 // Results from dynamic queries to ImsService regarding the features they support. 603 private final ImsServiceFeatureQueryManager.Listener mDynamicQueryListener = 604 new ImsServiceFeatureQueryManager.Listener() { 605 606 @Override 607 public void onComplete(ComponentName name, 608 Set<ImsFeatureConfiguration.FeatureSlotPair> features) { 609 Log.d(TAG, "onComplete called for name: " + name + printFeatures(features)); 610 handleFeaturesChanged(name, features); 611 } 612 613 @Override 614 public void onError(ComponentName name) { 615 Log.w(TAG, "onError: " + name + "returned with an error result"); 616 mEventLog.log("onError - dynamic query error for " + name); 617 scheduleQueryForFeatures(name, DELAY_DYNAMIC_QUERY_MS); 618 } 619 620 @Override 621 public void onPermanentError(ComponentName name, UserHandle user) { 622 Log.w(TAG, "onPermanentError: component=" + name); 623 mEventLog.log("onPermanentError - error for " + name); 624 if (!mFeatureFlags.imsResolverUserAware()) { 625 mHandler.obtainMessage(HANDLER_REMOVE_PACKAGE, 626 name.getPackageName()).sendToTarget(); 627 } else { 628 mHandler.obtainMessage(HANDLER_REMOVE_PACKAGE_PERM_ERROR, 629 new Pair<>(name.getPackageName(), user)).sendToTarget(); 630 } 631 } 632 }; 633 634 // Used during testing, overrides the carrier services while non-empty. 635 // Array index corresponds to slot, per slot there is a feature->package name mapping. 636 // should only be accessed from handler 637 private final SparseArray<SparseArray<String>> mOverrideServices; 638 //Used during testing, restricts the ImsService to be bound on a specific user. 639 private final Map<String, UserHandle> mImsServiceTestUserRestrictions = new HashMap<>(); 640 // Outer array index corresponds to Slot Id, Maps ImsFeature.FEATURE->bound ImsServiceController 641 // Locked on mBoundServicesLock 642 private final SparseArray<SparseArray<ImsServiceController>> mBoundImsServicesByFeature; 643 // not locked, only accessed on a handler thread. 644 // Tracks list of all installed ImsServices 645 private final Map<ComponentName, ImsServiceInfo> mInstalledServicesCache = new HashMap<>(); 646 // not locked, only accessed on a handler thread. 647 // Active ImsServiceControllers, which are bound to ImsServices. 648 private final Map<ComponentName, ImsServiceController> mActiveControllers = new HashMap<>(); 649 private ImsServiceFeatureQueryManager mFeatureQueryManager; 650 private final SparseIntArray mSlotIdToSubIdMap; 651 ImsResolver(Context context, String defaultMmTelPackageName, String defaultRcsPackageName, int numSlots, ImsFeatureBinderRepository repo, Looper looper, FeatureFlags featureFlags)652 public ImsResolver(Context context, String defaultMmTelPackageName, 653 String defaultRcsPackageName, int numSlots, ImsFeatureBinderRepository repo, 654 Looper looper, FeatureFlags featureFlags) { 655 Log.i(TAG, "device MMTEL package: " + defaultMmTelPackageName + ", device RCS package:" 656 + defaultRcsPackageName); 657 mContext = context; 658 mNumSlots = numSlots; 659 mRepo = repo; 660 mReceiverContext = context.createContextAsUser(UserHandle.ALL, 0 /*flags*/); 661 662 mHandler = new ResolverHandler(looper); 663 mRunnableExecutor = new HandlerExecutor(mHandler); 664 mFeatureFlags = featureFlags; 665 mCarrierServices = new SparseArray<>(mNumSlots); 666 setDeviceConfiguration(defaultMmTelPackageName, ImsFeature.FEATURE_EMERGENCY_MMTEL); 667 setDeviceConfiguration(defaultMmTelPackageName, ImsFeature.FEATURE_MMTEL); 668 setDeviceConfiguration(defaultRcsPackageName, ImsFeature.FEATURE_RCS); 669 mCarrierConfigManager = (CarrierConfigManager) mContext.getSystemService( 670 Context.CARRIER_CONFIG_SERVICE); 671 mOverrideServices = new SparseArray<>(0 /*initial size*/); 672 mBoundImsServicesByFeature = new SparseArray<>(mNumSlots); 673 mSlotIdToSubIdMap = new SparseIntArray(mNumSlots); 674 for (int i = 0; i < mNumSlots; i++) { 675 mSlotIdToSubIdMap.put(i, SubscriptionManager.INVALID_SUBSCRIPTION_ID); 676 } 677 } 678 679 @VisibleForTesting setTelephonyManagerProxy(TelephonyManagerProxy proxy)680 public void setTelephonyManagerProxy(TelephonyManagerProxy proxy) { 681 mTelephonyManagerProxy = proxy; 682 } 683 684 @VisibleForTesting setSubscriptionManagerProxy(SubscriptionManagerProxy proxy)685 public void setSubscriptionManagerProxy(SubscriptionManagerProxy proxy) { 686 mSubscriptionManagerProxy = proxy; 687 } 688 689 @VisibleForTesting setImsServiceControllerFactory(ImsServiceControllerFactory factory)690 public void setImsServiceControllerFactory(ImsServiceControllerFactory factory) { 691 mImsServiceControllerFactory = factory; 692 } 693 694 @VisibleForTesting setActivityManagerProxy(ActivityManagerProxy proxy)695 public void setActivityManagerProxy(ActivityManagerProxy proxy) { 696 mActivityManagerProxy = proxy; 697 } 698 699 @VisibleForTesting getHandler()700 public Handler getHandler() { 701 return mHandler; 702 } 703 704 @VisibleForTesting setImsDynamicQueryManagerFactory(ImsDynamicQueryManagerFactory m)705 public void setImsDynamicQueryManagerFactory(ImsDynamicQueryManagerFactory m) { 706 mDynamicQueryManagerFactory = m; 707 } 708 709 /** 710 * Needs to be called after the constructor to kick off the process of binding to ImsServices. 711 * Should be run on the handler thread of ImsResolver 712 */ initialize()713 public void initialize() { 714 mHandler.post(()-> initializeInternal()); 715 } 716 initializeInternal()717 private void initializeInternal() { 718 mEventLog.log("Initializing"); 719 Log.i(TAG, "Initializing cache."); 720 PhoneConfigurationManager.registerForMultiSimConfigChange(mHandler, 721 HANDLER_MSIM_CONFIGURATION_CHANGE, null); 722 mFeatureQueryManager = mDynamicQueryManagerFactory.create(mContext, mDynamicQueryListener); 723 724 updateInstalledServicesCache(); 725 726 IntentFilter appChangedFilter = new IntentFilter(); 727 appChangedFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); 728 appChangedFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 729 appChangedFilter.addAction(Intent.ACTION_PACKAGE_ADDED); 730 appChangedFilter.addDataScheme("package"); 731 mReceiverContext.registerReceiver(mAppChangedReceiver, appChangedFilter); 732 if (mFeatureFlags.imsResolverUserAware()) { 733 mReceiverContext.registerReceiver(mUserReceiver, new IntentFilter( 734 Intent.ACTION_USER_SWITCHED)); 735 } 736 mReceiverContext.registerReceiver(mConfigChangedReceiver, new IntentFilter( 737 CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)); 738 739 UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 740 if (userManager.isUserUnlocked()) { 741 mHandler.obtainMessage(HANDLER_BOOT_COMPLETE, null).sendToTarget(); 742 } else { 743 mReceiverContext.registerReceiver(mBootCompleted, new IntentFilter( 744 Intent.ACTION_BOOT_COMPLETED)); 745 if (userManager.isUserUnlocked()) { 746 mHandler.obtainMessage(HANDLER_BOOT_COMPLETE, null).sendToTarget(); 747 } 748 } 749 750 // Update the package names of the carrier ImsServices if they do not exist already and 751 // possibly bind if carrier configs exist. Otherwise wait for CarrierConfigChanged 752 // indication. 753 bindCarrierServicesIfAvailable(); 754 } 755 756 /** 757 * Query the system for all registered ImsServices and add them to the cache if there are any 758 * new ones that are not tracked. 759 */ updateInstalledServicesCache()760 private void updateInstalledServicesCache() { 761 // This will get all services with the correct intent filter from PackageManager 762 for (ImsServiceInfo info : getImsServiceInfo(null)) { 763 if (!mInstalledServicesCache.containsKey(info.name)) { 764 mInstalledServicesCache.put(info.name, info); 765 } 766 } 767 } 768 769 /** 770 * Destroys this ImsResolver. Used for tearing down static resources during testing. 771 */ 772 @VisibleForTesting destroy()773 public void destroy() { 774 PhoneConfigurationManager.unregisterForMultiSimConfigChange(mHandler); 775 mHandler.removeCallbacksAndMessages(null); 776 } 777 778 // Only start the bind if there is an existing Carrier Configuration. Otherwise, wait for 779 // carrier config changed. bindCarrierServicesIfAvailable()780 private void bindCarrierServicesIfAvailable() { 781 boolean hasConfigChanged = false; 782 boolean pendingDynamicQuery = false; 783 for (int slotId = 0; slotId < mNumSlots; slotId++) { 784 int subId = mSubscriptionManagerProxy.getSubId(slotId); 785 Map<Integer, String> featureMap = getImsPackageOverrideConfig(subId); 786 for (int f = ImsFeature.FEATURE_EMERGENCY_MMTEL; f < ImsFeature.FEATURE_MAX; f++) { 787 String newPackageName = featureMap.getOrDefault(f, ""); 788 if (!TextUtils.isEmpty(newPackageName)) { 789 Log.d(TAG, "bindCarrierServicesIfAvailable - carrier package found: " 790 + newPackageName + ", feature " 791 + ImsFeature.FEATURE_LOG_MAP.getOrDefault(f, "invalid") 792 + " on slot " + slotId); 793 mEventLog.log("bindCarrierServicesIfAvailable - carrier package found: " 794 + newPackageName + " on slot " + slotId); 795 // Carrier configs are already available, so mark received. 796 mCarrierConfigReceived = true; 797 setSubId(slotId, subId); 798 setCarrierConfiguredPackageName(newPackageName, slotId, f); 799 ImsServiceInfo info = getVisibleImsServiceInfoFromCache(newPackageName); 800 // We do not want to trigger feature configuration changes unless there is 801 // already a valid carrier config change. 802 if (info != null && info.featureFromMetadata) { 803 hasConfigChanged = true; 804 } else { 805 // Config will change when this query completes 806 scheduleQueryForFeatures(info); 807 if (info != null) pendingDynamicQuery = true; 808 } 809 } 810 } 811 } 812 // we want to make sure that we are either pending to bind to a carrier configured service 813 // or bind to the device config if we potentially missed the carrier config changed 814 // indication. 815 if (hasConfigChanged || (mFeatureFlags.imsResolverUserAware() 816 && mCarrierConfigReceived && !pendingDynamicQuery)) { 817 calculateFeatureConfigurationChange(); 818 } 819 } 820 821 /** 822 * Notify ImsService to enable IMS for the framework. This will trigger IMS registration and 823 * trigger ImsFeature status updates. 824 */ enableIms(int slotId)825 public void enableIms(int slotId) { 826 getImsServiceControllers(slotId).forEach( 827 (controller) -> controller.enableIms(slotId, getSubId(slotId))); 828 } 829 830 /** 831 * Notify ImsService to disable IMS for the framework. This will trigger IMS de-registration and 832 * trigger ImsFeature capability status to become false. 833 */ disableIms(int slotId)834 public void disableIms(int slotId) { 835 getImsServiceControllers(slotId).forEach( 836 (controller) -> controller.disableIms(slotId, getSubId(slotId))); 837 } 838 839 /** 840 * Notify ImsService to disable IMS for the framework. 841 * And notify ImsService back to enable IMS for the framework. 842 */ resetIms(int slotId)843 public void resetIms(int slotId) { 844 getImsServiceControllers(slotId).forEach( 845 (controller) -> controller.resetIms(slotId, getSubId(slotId))); 846 } 847 848 /** 849 * Returns the ImsRegistration structure associated with the slotId and feature specified. 850 */ getImsRegistration(int slotId, int feature)851 public @Nullable IImsRegistration getImsRegistration(int slotId, int feature) { 852 ImsFeatureContainer fc = mRepo.getIfExists(slotId, feature).orElse(null); 853 return (fc != null) ? fc.imsRegistration : null; 854 } 855 856 /** 857 * Returns the ImsConfig structure associated with the slotId and feature specified. 858 */ getImsConfig(int slotId, int feature)859 public @Nullable IImsConfig getImsConfig(int slotId, int feature) { 860 ImsFeatureContainer fc = mRepo.getIfExists(slotId, feature).orElse(null); 861 return (fc != null) ? fc.imsConfig : null; 862 } 863 864 /** 865 * @return A Set containing all the bound ImsServiceControllers for the slotId specified. 866 */ getImsServiceControllers(int slotId)867 private Set<ImsServiceController> getImsServiceControllers(int slotId) { 868 if (slotId < 0 || slotId >= mNumSlots) { 869 return Collections.emptySet(); 870 } 871 SparseArray<ImsServiceController> featureToControllerMap; 872 synchronized (mBoundServicesLock) { 873 featureToControllerMap = mBoundImsServicesByFeature.get(slotId); 874 } 875 if (featureToControllerMap == null) { 876 Log.w(TAG, "getImsServiceControllers: couldn't find any active " 877 + "ImsServiceControllers"); 878 return Collections.emptySet(); 879 } 880 // Create a temporary set to dedupe when multiple features map to the same 881 // ImsServiceController 882 Set<ImsServiceController> controllers = new ArraySet<>(2); 883 for (int i = 0; i < featureToControllerMap.size(); i++) { 884 int key = featureToControllerMap.keyAt(i); 885 ImsServiceController c = featureToControllerMap.get(key); 886 if (c != null) controllers.add(c); 887 } 888 return controllers; 889 } 890 891 /** 892 * Register a new listener for the feature type and slot specified. ImsServiceController will 893 * update the connections as they become available. 894 */ listenForFeature(int slotId, int feature, IImsServiceFeatureCallback callback)895 public void listenForFeature(int slotId, int feature, IImsServiceFeatureCallback callback) { 896 mRepo.registerForConnectionUpdates(slotId, feature, callback, mRunnableExecutor); 897 } 898 899 /** 900 * Unregister a previously registered IImsServiceFeatureCallback through 901 * {@link #listenForFeature(int, int, IImsServiceFeatureCallback)}. 902 * @param callback The callback to be unregistered. 903 */ unregisterImsFeatureCallback(IImsServiceFeatureCallback callback)904 public void unregisterImsFeatureCallback(IImsServiceFeatureCallback callback) { 905 mRepo.unregisterForConnectionUpdates(callback); 906 } 907 908 // Used for testing only. clearCarrierImsServiceConfiguration(int slotId)909 public boolean clearCarrierImsServiceConfiguration(int slotId) { 910 if (slotId < 0 || slotId >= mNumSlots) { 911 Log.w(TAG, "clearCarrierImsServiceConfiguration: invalid slotId!"); 912 return false; 913 } 914 915 Message.obtain(mHandler, HANDLER_CLEAR_CARRIER_IMS_SERVICE_CONFIG, slotId, 0 /*arg2*/) 916 .sendToTarget(); 917 return true; 918 } 919 920 // Used for testing only. overrideImsServiceConfiguration(String packageName, int slotId, int userId, boolean isCarrierService, int[] overrideFeatureTypes)921 public boolean overrideImsServiceConfiguration(String packageName, int slotId, int userId, 922 boolean isCarrierService, int[] overrideFeatureTypes) { 923 if (slotId < 0 || slotId >= mNumSlots) { 924 Log.w(TAG, "overrideImsServiceConfiguration: invalid slotId!"); 925 return false; 926 } 927 928 OverrideConfig overrideConfig = new OverrideConfig(packageName, slotId, userId, 929 isCarrierService, overrideFeatureTypes); 930 Message.obtain(mHandler, HANDLER_OVERRIDE_IMS_SERVICE_CONFIG, overrideConfig) 931 .sendToTarget(); 932 return true; 933 } 934 getDeviceConfiguration(@msFeature.FeatureType int featureType)935 private String getDeviceConfiguration(@ImsFeature.FeatureType int featureType) { 936 synchronized (mDeviceServices) { 937 return mDeviceServices.getOrDefault(featureType, ""); 938 } 939 } 940 setDeviceConfiguration(String name, @ImsFeature.FeatureType int featureType)941 private void setDeviceConfiguration(String name, @ImsFeature.FeatureType int featureType) { 942 synchronized (mDeviceServices) { 943 mDeviceServices.put(featureType, name); 944 } 945 } 946 947 // not synchronized, access in handler ONLY. setCarrierConfiguredPackageName(@onNull String packageName, int slotId, @ImsFeature.FeatureType int featureType)948 private void setCarrierConfiguredPackageName(@NonNull String packageName, int slotId, 949 @ImsFeature.FeatureType int featureType) { 950 getCarrierConfiguredPackageNames(slotId).put(featureType, packageName); 951 } 952 953 // not synchronized, access in handler ONLY. getCarrierConfiguredPackageName(int slotId, @ImsFeature.FeatureType int featureType)954 private @NonNull String getCarrierConfiguredPackageName(int slotId, 955 @ImsFeature.FeatureType int featureType) { 956 return getCarrierConfiguredPackageNames(slotId).getOrDefault(featureType, ""); 957 } 958 959 // not synchronized, access in handler ONLY. getCarrierConfiguredPackageNames(int slotId)960 private @NonNull Map<Integer, String> getCarrierConfiguredPackageNames(int slotId) { 961 Map<Integer, String> carrierConfig = mCarrierServices.get(slotId); 962 if (carrierConfig == null) { 963 carrierConfig = new ArrayMap<>(); 964 mCarrierServices.put(slotId, carrierConfig); 965 } 966 return carrierConfig; 967 } 968 969 // not synchronized, access in handler ONLY. removeOverridePackageName(int slotId)970 private Set<String> removeOverridePackageName(int slotId) { 971 Set<String> removedOverrides = new HashSet<>(); 972 for (int f = ImsFeature.FEATURE_EMERGENCY_MMTEL; f < ImsFeature.FEATURE_MAX; f++) { 973 SparseArray<String> overrides = getOverridePackageName(slotId); 974 String packageName = overrides.removeReturnOld(f); 975 if (packageName != null) removedOverrides.add(packageName); 976 } 977 return removedOverrides; 978 } 979 980 // not synchronized, access in handler ONLY. setOverridePackageName(@ullable String packageName, int slotId, @ImsFeature.FeatureType int featureType)981 private void setOverridePackageName(@Nullable String packageName, int slotId, 982 @ImsFeature.FeatureType int featureType) { 983 getOverridePackageName(slotId).put(featureType, packageName); 984 } 985 986 // not synchronized, access in handler ONLY. setPackageNameUserOverride(String packageName, int userId)987 private void setPackageNameUserOverride(String packageName, int userId) { 988 if (packageName == null || packageName.isEmpty() || userId == UserHandle.USER_NULL) return; 989 Log.i(TAG, "setPackageNameUserOverride: set for " + packageName + ", user= " + userId); 990 mImsServiceTestUserRestrictions.put(packageName, UserHandle.of(userId)); 991 } 992 993 // not synchronized, access in handler ONLY. clearPackageNameUserOverride(String packageName)994 private void clearPackageNameUserOverride(String packageName) { 995 UserHandle handle = mImsServiceTestUserRestrictions.remove(packageName); 996 if (handle != null) { 997 Log.i(TAG, "clearPackageNameUserOverride: cleared for " + packageName 998 + "on user " + handle); 999 } 1000 } 1001 1002 // not synchronized, access in handler ONLY. getOverridePackageName(int slotId, @ImsFeature.FeatureType int featureType)1003 private @Nullable String getOverridePackageName(int slotId, 1004 @ImsFeature.FeatureType int featureType) { 1005 return getOverridePackageName(slotId).get(featureType); 1006 } 1007 1008 // not synchronized, access in handler ONLY. getOverridePackageName(int slotId)1009 private @NonNull SparseArray<String> getOverridePackageName(int slotId) { 1010 SparseArray<String> carrierConfig = mOverrideServices.get(slotId); 1011 if (carrierConfig == null) { 1012 carrierConfig = new SparseArray<>(); 1013 mOverrideServices.put(slotId, carrierConfig); 1014 } 1015 return carrierConfig; 1016 } 1017 1018 /** 1019 * @return true if there is a carrier configuration that exists for the slot & featureType pair 1020 * and the cached carrier ImsService associated with the configuration also supports the 1021 * requested ImsFeature type. 1022 */ 1023 // not synchronized, access in handler ONLY. doesCarrierConfigurationExist(int slotId, @ImsFeature.FeatureType int featureType)1024 private boolean doesCarrierConfigurationExist(int slotId, 1025 @ImsFeature.FeatureType int featureType) { 1026 String carrierPackage = getCarrierConfiguredPackageName(slotId, featureType); 1027 if (TextUtils.isEmpty(carrierPackage)) { 1028 return false; 1029 } 1030 // Config exists, but the carrier ImsService also needs to support this feature 1031 return doesCachedImsServiceExist(carrierPackage, slotId, featureType); 1032 } 1033 1034 /** 1035 * Check the cached ImsServices that exist on this device to determine if there is a ImsService 1036 * with the same package name that matches the provided configuration and is configured to run 1037 * in one of the active users. 1038 */ 1039 // not synchronized, access in handler ONLY. doesCachedImsServiceExist(String packageName, int slotId, @ImsFeature.FeatureType int featureType)1040 private boolean doesCachedImsServiceExist(String packageName, int slotId, 1041 @ImsFeature.FeatureType int featureType) { 1042 // Config exists, but the carrier ImsService also needs to support this feature 1043 ImsServiceInfo info = getVisibleImsServiceInfoFromCache(packageName); 1044 return info != null && info.getSupportedFeatures().stream().anyMatch( 1045 feature -> feature.slotId == slotId && feature.featureType == featureType); 1046 } 1047 1048 /** 1049 * @return the package name of the ImsService with the requested configuration. 1050 */ 1051 // used in shell commands queries during testing only. getImsServiceConfiguration(int slotId, boolean isCarrierService, @ImsFeature.FeatureType int featureType)1052 public String getImsServiceConfiguration(int slotId, boolean isCarrierService, 1053 @ImsFeature.FeatureType int featureType) { 1054 if (slotId < 0 || slotId >= mNumSlots) { 1055 Log.w(TAG, "getImsServiceConfiguration: invalid slotId!"); 1056 return ""; 1057 } 1058 1059 LinkedBlockingQueue<String> result = new LinkedBlockingQueue<>(1); 1060 // access the configuration on the handler. 1061 mHandler.post(() -> result.offer(isCarrierService 1062 ? getCarrierConfiguredPackageName(slotId, featureType) : 1063 getDeviceConfiguration(featureType))); 1064 try { 1065 return result.poll(GET_IMS_SERVICE_TIMEOUT_MS, TimeUnit.MILLISECONDS); 1066 } catch (InterruptedException e) { 1067 Log.w(TAG, "getImsServiceConfiguration: exception=" + e.getMessage()); 1068 return null; 1069 } 1070 } 1071 1072 /** 1073 * Determines if there is a valid ImsService configured for the specified ImsFeature. 1074 * @param slotId The slot ID to check for. 1075 * @param featureType The ImsFeature featureType to check for. 1076 * @return true if there is an ImsService configured for the specified ImsFeature type, false 1077 * if there is not. 1078 */ isImsServiceConfiguredForFeature(int slotId, @ImsFeature.FeatureType int featureType)1079 public boolean isImsServiceConfiguredForFeature(int slotId, 1080 @ImsFeature.FeatureType int featureType) { 1081 if (!TextUtils.isEmpty(getDeviceConfiguration(featureType))) { 1082 // Shortcut a little bit here - instead of dynamically looking up the configured 1083 // package name, which can be a long operation depending on the state, just return true 1084 // if there is a configured device ImsService for the requested feature because that 1085 // means there will always be at least a device configured ImsService. 1086 return true; 1087 } 1088 return !TextUtils.isEmpty(getConfiguredImsServicePackageName(slotId, featureType)); 1089 } 1090 1091 /** 1092 * Resolves the PackageName of the ImsService that is configured to be bound for the slotId and 1093 * FeatureType specified and returns it. 1094 * <p> 1095 * If there is a PackageName that is configured, but there is no application on the device that 1096 * fulfills that configuration, this method will also return {@code null} as the ImsService will 1097 * not be bound. 1098 * 1099 * @param slotId The slot ID that the request is for. 1100 * @param featureType The ImsService feature type that the request is for. 1101 * @return The package name of the ImsService that will be bound from telephony for the provided 1102 * slot id and featureType. 1103 */ getConfiguredImsServicePackageName(int slotId, @ImsFeature.FeatureType int featureType)1104 public String getConfiguredImsServicePackageName(int slotId, 1105 @ImsFeature.FeatureType int featureType) { 1106 if (slotId < 0 || slotId >= mNumSlots || featureType <= ImsFeature.FEATURE_INVALID 1107 || featureType >= ImsFeature.FEATURE_MAX) { 1108 Log.w(TAG, "getResolvedImsServicePackageName received invalid parameters - slot: " 1109 + slotId + ", feature: " + featureType); 1110 return null; 1111 } 1112 CompletableFuture<String> packageNameFuture = new CompletableFuture<>(); 1113 final long startTimeMs = System.currentTimeMillis(); 1114 if (mHandler.getLooper().isCurrentThread()) { 1115 // If we are on the same thread as the Handler's looper, run the internal method 1116 // directly. 1117 packageNameFuture.complete(getConfiguredImsServicePackageNameInternal(slotId, 1118 featureType)); 1119 } else { 1120 mHandler.post(() -> { 1121 try { 1122 packageNameFuture.complete(getConfiguredImsServicePackageNameInternal(slotId, 1123 featureType)); 1124 } catch (Exception e) { 1125 // Catch all Exceptions to ensure we do not block indefinitely in the case of an 1126 // unexpected error. 1127 packageNameFuture.completeExceptionally(e); 1128 } 1129 }); 1130 } 1131 try { 1132 String packageName = packageNameFuture.get(); 1133 long timeDiff = System.currentTimeMillis() - startTimeMs; 1134 if (timeDiff > 50) { 1135 // Took an unusually long amount of time (> 50 ms), so log it. 1136 mEventLog.log("getResolvedImsServicePackageName - [" + slotId + ", " 1137 + ImsFeature.FEATURE_LOG_MAP.get(featureType) 1138 + "], async query complete, took " + timeDiff + " ms with package name: " 1139 + packageName); 1140 Log.w(TAG, "getResolvedImsServicePackageName: [" + slotId + ", " 1141 + ImsFeature.FEATURE_LOG_MAP.get(featureType) 1142 + "], async query complete, took " + timeDiff + " ms with package name: " 1143 + packageName); 1144 } 1145 return packageName; 1146 } catch (Exception e) { 1147 mEventLog.log("getResolvedImsServicePackageName - [" + slotId + ", " 1148 + ImsFeature.FEATURE_LOG_MAP.get(featureType) + "] -> Exception: " + e); 1149 Log.w(TAG, "getResolvedImsServicePackageName: [" + slotId + ", " 1150 + ImsFeature.FEATURE_LOG_MAP.get(featureType) + "] returned Exception: " + e); 1151 return null; 1152 } 1153 } 1154 1155 /** 1156 * @return the package name for the configured carrier ImsService if it exists on the device and 1157 * supports the supplied slotId and featureType. If no such configuration exists, fall back to 1158 * the device ImsService. If neither exist, then return {@code null}; 1159 */ 1160 // Not synchronized, access on Handler ONLY! getConfiguredImsServicePackageNameInternal(int slotId, @ImsFeature.FeatureType int featureType)1161 private String getConfiguredImsServicePackageNameInternal(int slotId, 1162 @ImsFeature.FeatureType int featureType) { 1163 // If a carrier ImsService is configured to be used for the provided slotId and 1164 // featureType, then return that one. 1165 String carrierPackage = getCarrierConfiguredPackageName(slotId, featureType); 1166 if (!TextUtils.isEmpty(carrierPackage) 1167 && doesCachedImsServiceExist(carrierPackage, slotId, featureType)) { 1168 return carrierPackage; 1169 } 1170 // If there is no carrier ImsService configured for that configuration, then 1171 // return the device's default ImsService for the provided slotId and 1172 // featureType. 1173 String devicePackage = getDeviceConfiguration(featureType); 1174 if (!TextUtils.isEmpty(devicePackage) 1175 && doesCachedImsServiceExist(devicePackage, slotId, featureType)) { 1176 return devicePackage; 1177 } 1178 // There is no ImsService configuration that exists for the slotId and 1179 // featureType. 1180 return null; 1181 } 1182 putImsController(int slotId, int subId, int feature, ImsServiceController controller)1183 private void putImsController(int slotId, int subId, int feature, 1184 ImsServiceController controller) { 1185 if (slotId < 0 || slotId >= mNumSlots || feature <= ImsFeature.FEATURE_INVALID 1186 || feature >= ImsFeature.FEATURE_MAX) { 1187 Log.w(TAG, "putImsController received invalid parameters - slot: " + slotId 1188 + ", feature: " + feature); 1189 return; 1190 } 1191 synchronized (mBoundServicesLock) { 1192 SparseArray<ImsServiceController> services = mBoundImsServicesByFeature.get(slotId); 1193 if (services == null) { 1194 services = new SparseArray<>(); 1195 mBoundImsServicesByFeature.put(slotId, services); 1196 } 1197 mEventLog.log("putImsController - [" + slotId + ", " 1198 + ImsFeature.FEATURE_LOG_MAP.get(feature) + "] -> " + controller); 1199 Log.i(TAG, "ImsServiceController added on slot: " + slotId + ", subId: " + subId 1200 + " with feature: " + ImsFeature.FEATURE_LOG_MAP.get(feature) 1201 + " using package: " + controller.getComponentName()); 1202 services.put(feature, controller); 1203 } 1204 } 1205 removeImsController(int slotId, int feature)1206 private ImsServiceController removeImsController(int slotId, int feature) { 1207 if (slotId < 0 || feature <= ImsFeature.FEATURE_INVALID 1208 || feature >= ImsFeature.FEATURE_MAX) { 1209 Log.w(TAG, "removeImsController received invalid parameters - slot: " + slotId 1210 + ", feature: " + feature); 1211 return null; 1212 } 1213 synchronized (mBoundServicesLock) { 1214 SparseArray<ImsServiceController> services = mBoundImsServicesByFeature.get(slotId); 1215 if (services == null) { 1216 return null; 1217 } 1218 ImsServiceController c = services.get(feature, null); 1219 if (c != null) { 1220 mEventLog.log("removeImsController - [" + slotId + ", " 1221 + ImsFeature.FEATURE_LOG_MAP.get(feature) + "] -> " + c); 1222 Log.i(TAG, "ImsServiceController removed on slot: " + slotId + " with feature: " 1223 + ImsFeature.FEATURE_LOG_MAP.get(feature) + " using package: " 1224 + c.getComponentName()); 1225 services.remove(feature); 1226 } 1227 return c; 1228 } 1229 } 1230 1231 // Update the current cache with the new ImsService(s) if it has been added or update the 1232 // supported IMS features if they have changed. 1233 // Called from the handler ONLY maybeAddedImsService(String packageName)1234 private void maybeAddedImsService(String packageName) { 1235 Log.d(TAG, "maybeAddedImsService, packageName: " + packageName); 1236 List<ImsServiceInfo> infos = getImsServiceInfo(packageName); 1237 // Wait until all ImsServiceInfo is cached before calling 1238 // calculateFeatureConfigurationChange to reduce churn. 1239 boolean requiresCalculation = false; 1240 for (ImsServiceInfo info : infos) { 1241 // Checking to see if the ComponentName is the same, so we can update the supported 1242 // features. Will only be one (if it exists), since it is a set. 1243 ImsServiceInfo match = getInfoByComponentName(mInstalledServicesCache, info.name); 1244 if (match != null) { 1245 if (mFeatureFlags.imsResolverUserAware()) { 1246 match.users.clear(); 1247 match.users.addAll(info.users); 1248 } 1249 // for dynamic query the new "info" will have no supported features yet. Don't wipe 1250 // out the cache for the existing features or update yet. Instead start a query 1251 // for features dynamically. 1252 if (info.featureFromMetadata) { 1253 mEventLog.log("maybeAddedImsService - updating features for " + info.name 1254 + ": " + printFeatures(match.getSupportedFeatures()) + " -> " 1255 + printFeatures(info.getSupportedFeatures())); 1256 Log.d(TAG, "Updating features in cached ImsService: " + info.name 1257 + ", old features: " + match + " new features: " + info); 1258 // update features in the cache 1259 match.replaceFeatures(info.getSupportedFeatures()); 1260 requiresCalculation = true; 1261 } else { 1262 mEventLog.log("maybeAddedImsService - scheduling query for " + info); 1263 // start a query to get ImsService features 1264 scheduleQueryForFeatures(info); 1265 } 1266 } else { 1267 Log.i(TAG, "Adding newly added ImsService to cache: " + info.name); 1268 mEventLog.log("maybeAddedImsService - adding new ImsService: " + info); 1269 mInstalledServicesCache.put(info.name, info); 1270 if (info.featureFromMetadata) { 1271 requiresCalculation = true; 1272 } else { 1273 // newly added ImsServiceInfo that has not had features queried yet. Start async 1274 // bind and query features. 1275 scheduleQueryForFeatures(info); 1276 } 1277 } 1278 } 1279 if (requiresCalculation) calculateFeatureConfigurationChange(); 1280 } 1281 1282 // Remove the ImsService from the cache due to the ImsService package being removed. 1283 // Called from the handler ONLY maybeRemovedImsServiceOld(String packageName)1284 private boolean maybeRemovedImsServiceOld(String packageName) { 1285 ImsServiceInfo match = getInfoByPackageName(mInstalledServicesCache, packageName); 1286 if (match != null) { 1287 mInstalledServicesCache.remove(match.name); 1288 mEventLog.log("maybeRemovedImsService - removing ImsService: " + match); 1289 Log.i(TAG, "Removing ImsService: " + match.name); 1290 unbindImsService(match); 1291 calculateFeatureConfigurationChange(); 1292 return true; 1293 } 1294 return false; 1295 } 1296 1297 // Remove the ImsService from the cache due to the ImsService package being removed. 1298 // Called from the handler ONLY maybeRemovedImsService(String packageName)1299 private boolean maybeRemovedImsService(String packageName) { 1300 if (!mFeatureFlags.imsResolverUserAware()) { 1301 return maybeRemovedImsServiceOld(packageName); 1302 } 1303 ImsServiceInfo match = getInfoByPackageName(mInstalledServicesCache, packageName); 1304 if (match != null) { 1305 List<ImsServiceInfo> imsServices = searchForImsServices(packageName, 1306 match.controllerFactory); 1307 ImsServiceInfo newMatch = imsServices.isEmpty() ? null : imsServices.getFirst(); 1308 if (newMatch == null) { 1309 clearPackageNameUserOverride(match.name.getPackageName()); 1310 // The package doesn't exist anymore on any user, so remove 1311 mInstalledServicesCache.remove(match.name); 1312 mEventLog.log("maybeRemovedImsService - removing ImsService: " + match); 1313 Log.i(TAG, "maybeRemovedImsService Removing ImsService for all users: " 1314 + match.name); 1315 unbindImsService(match); 1316 } else { 1317 // The Package exists on some users still, so modify the users 1318 match.users.clear(); 1319 match.users.addAll(newMatch.users); 1320 mEventLog.log("maybeRemovedImsService - modifying ImsService users: " + match); 1321 Log.i(TAG, "maybeRemovedImsService - Modifying ImsService users " + match); 1322 // If this package still remains on some users, then it is possible we are unbinding 1323 // an active ImsService, but the assumption here is that the package is being 1324 // removed on an active user. Be safe and unbind now - we will rebind below if 1325 // needed. 1326 unbindImsService(match); 1327 } 1328 calculateFeatureConfigurationChange(); 1329 return true; 1330 } 1331 return false; 1332 } 1333 1334 /** 1335 * Remove the cached ImsService for a specific user. If there are no more users available after 1336 * removing the specified user, remove the ImsService cache entry entirely. 1337 */ 1338 // Called from the handler ONLY maybeRemovedImsServiceForUser(String packageName, UserHandle user)1339 private boolean maybeRemovedImsServiceForUser(String packageName, UserHandle user) { 1340 ImsServiceInfo match = getInfoByPackageName(mInstalledServicesCache, packageName); 1341 if (match != null) { 1342 mEventLog.log("maybeRemovedImsServiceForUser - removing ImsService " + match 1343 + "for user " + user); 1344 Log.i(TAG, "maybeRemovedImsServiceForUser: Removing ImsService " 1345 + match + "for user " + user); 1346 unbindImsService(match); 1347 match.users.remove(user); 1348 if (match.users.isEmpty()) { 1349 mEventLog.log("maybeRemovedImsServiceForUser - no more users, removing " 1350 + "ImsService " + match); 1351 Log.i(TAG, "maybeRemovedImsServiceForUser - no more users, removing " 1352 + "ImsService " + match); 1353 mInstalledServicesCache.remove(match.name); 1354 } 1355 calculateFeatureConfigurationChange(); 1356 return true; 1357 } 1358 return false; 1359 } 1360 isDeviceService(ImsServiceInfo info)1361 private boolean isDeviceService(ImsServiceInfo info) { 1362 if (info == null) return false; 1363 synchronized (mDeviceServices) { 1364 return mDeviceServices.containsValue(info.name.getPackageName()); 1365 } 1366 } 1367 getSlotsForActiveCarrierService(ImsServiceInfo info)1368 private List<Integer> getSlotsForActiveCarrierService(ImsServiceInfo info) { 1369 if (info == null) return Collections.emptyList(); 1370 if (mFeatureFlags.imsResolverUserAware()) { 1371 UserHandle activeUser = getUserForBind(info); 1372 if (activeUser == null) { 1373 Log.d(TAG, "getSlotsForActiveCarrierService: ImsService " + info.name + "is not " 1374 + "configured to run for any users, skipping..."); 1375 return Collections.emptyList(); 1376 } 1377 } 1378 List<Integer> slots = new ArrayList<>(mNumSlots); 1379 for (int i = 0; i < mNumSlots; i++) { 1380 if (!TextUtils.isEmpty(getCarrierConfiguredPackageNames(i).values().stream() 1381 .filter(e -> e.equals(info.name.getPackageName())).findAny().orElse(""))) { 1382 slots.add(i); 1383 } 1384 } 1385 return slots; 1386 } 1387 getControllerByServiceInfo( Map<ComponentName, ImsServiceController> searchMap, ImsServiceInfo matchValue)1388 private ImsServiceController getControllerByServiceInfo( 1389 Map<ComponentName, ImsServiceController> searchMap, ImsServiceInfo matchValue) { 1390 return searchMap.values().stream() 1391 .filter(c -> Objects.equals(c.getComponentName(), matchValue.name)) 1392 .findFirst().orElse(null); 1393 } 1394 getInfoByPackageName(Map<ComponentName, ImsServiceInfo> searchMap, String matchValue)1395 private ImsServiceInfo getInfoByPackageName(Map<ComponentName, ImsServiceInfo> searchMap, 1396 String matchValue) { 1397 return searchMap.values().stream() 1398 .filter((i) -> Objects.equals(i.name.getPackageName(), matchValue)) 1399 .findFirst().orElse(null); 1400 } 1401 getInfoByComponentName( Map<ComponentName, ImsServiceInfo> searchMap, ComponentName matchValue)1402 private ImsServiceInfo getInfoByComponentName( 1403 Map<ComponentName, ImsServiceInfo> searchMap, ComponentName matchValue) { 1404 return searchMap.get(matchValue); 1405 } 1406 bindImsServiceWithFeatures(ImsServiceInfo info, UserHandle user, Set<ImsFeatureConfiguration.FeatureSlotPair> features)1407 private void bindImsServiceWithFeatures(ImsServiceInfo info, UserHandle user, 1408 Set<ImsFeatureConfiguration.FeatureSlotPair> features) { 1409 // Only bind if there are features that will be created by the service. 1410 if (shouldFeaturesCauseBind(features)) { 1411 // Check to see if an active controller already exists 1412 ImsServiceController controller = getControllerByServiceInfo(mActiveControllers, info); 1413 SparseIntArray slotIdToSubIdMap = mSlotIdToSubIdMap.clone(); 1414 if (controller != null) { 1415 try { 1416 if (!mFeatureFlags.imsResolverUserAware() 1417 || Objects.equals(user, controller.getBoundUser())) { 1418 Log.i(TAG, "ImsService connection exists for " + info.name 1419 + ", updating features " + features); 1420 controller.changeImsServiceFeatures(features, slotIdToSubIdMap); 1421 } else { 1422 // Changing a user is a pretty rare event, we need to unbind and rebind 1423 // on the correct new user. 1424 Log.i(TAG, "ImsService user changed for " + info.name 1425 + ", rebinding on user " + user + ", features " + features); 1426 controller.unbind(); 1427 controller.bind(user, features, slotIdToSubIdMap); 1428 } 1429 1430 // Features have been set, there was an error adding/removing. When the 1431 // controller recovers, it will add/remove again. 1432 } catch (RemoteException e) { 1433 Log.w(TAG, "bindImsService: error=" + e.getMessage()); 1434 } 1435 } else { 1436 controller = info.controllerFactory.create(mContext, info.name, this, mRepo, 1437 mFeatureFlags); 1438 Log.i(TAG, "Binding ImsService: " + controller.getComponentName() 1439 + "on user " + user + " with features: " + features + ", subIdMap: " 1440 + slotIdToSubIdMap); 1441 controller.bind(user, features, slotIdToSubIdMap); 1442 mEventLog.log("bindImsServiceWithFeatures - create new controller: " 1443 + controller); 1444 } 1445 mActiveControllers.put(info.name, controller); 1446 } 1447 } 1448 1449 // Clean up and unbind from an ImsService unbindImsService(ImsServiceInfo info)1450 private void unbindImsService(ImsServiceInfo info) { 1451 if (info == null) { 1452 return; 1453 } 1454 ImsServiceController controller = getControllerByServiceInfo(mActiveControllers, info); 1455 if (controller != null) { 1456 // Calls imsServiceFeatureRemoved on all features in the controller 1457 try { 1458 Log.i(TAG, "Unbinding ImsService: " + controller.getComponentName()); 1459 mEventLog.log("unbindImsService - unbinding and removing " + controller); 1460 controller.unbind(); 1461 } catch (RemoteException e) { 1462 Log.e(TAG, "unbindImsService: Remote Exception: " + e.getMessage()); 1463 } 1464 mActiveControllers.remove(info.name); 1465 } 1466 } 1467 1468 // Calculate which features an ImsServiceController will need. If it is the carrier specific 1469 // ImsServiceController, it will be granted all of the features it requests on the associated 1470 // slot. If it is the device ImsService, it will get all of the features not covered by the 1471 // carrier implementation. calculateFeaturesToCreate( ImsServiceInfo info)1472 private HashSet<ImsFeatureConfiguration.FeatureSlotPair> calculateFeaturesToCreate( 1473 ImsServiceInfo info) { 1474 HashSet<ImsFeatureConfiguration.FeatureSlotPair> imsFeaturesBySlot = new HashSet<>(); 1475 List<Integer> slots = getSlotsForActiveCarrierService(info); 1476 if (!slots.isEmpty()) { 1477 // There is an active carrier config associated with this. Return with the ImsService's 1478 // supported features that are also within the carrier configuration 1479 imsFeaturesBySlot.addAll(info.getSupportedFeatures().stream() 1480 .filter(feature -> info.name.getPackageName().equals( 1481 getCarrierConfiguredPackageName(feature.slotId, feature.featureType))) 1482 .toList()); 1483 return imsFeaturesBySlot; 1484 } 1485 if (isDeviceService(info)) { 1486 imsFeaturesBySlot.addAll(info.getSupportedFeatures().stream() 1487 // only allow supported features that are also set for this package as the 1488 // device configuration. 1489 .filter(feature -> info.name.getPackageName().equals( 1490 getDeviceConfiguration(feature.featureType))) 1491 // filter out any separate carrier configuration, since that feature is handled 1492 // by the carrier ImsService. 1493 .filter(feature -> !doesCarrierConfigurationExist(feature.slotId, 1494 feature.featureType)) 1495 .toList()); 1496 } 1497 return imsFeaturesBySlot; 1498 } 1499 1500 /** 1501 * Implementation of 1502 * {@link ImsServiceController.ImsServiceControllerCallbacks#imsServiceFeatureCreated}, which 1503 * adds the ImsServiceController from the mBoundImsServicesByFeature structure. 1504 */ 1505 @Override imsServiceFeatureCreated(int slotId, int subId, int feature, ImsServiceController controller)1506 public void imsServiceFeatureCreated(int slotId, int subId, int feature, 1507 ImsServiceController controller) { 1508 putImsController(slotId, subId, feature, controller); 1509 } 1510 1511 /** 1512 * Implementation of 1513 * {@link ImsServiceController.ImsServiceControllerCallbacks#imsServiceFeatureRemoved}, which 1514 * removes the ImsServiceController from the mBoundImsServicesByFeature structure. 1515 */ 1516 @Override imsServiceFeatureRemoved(int slotId, int feature, ImsServiceController controller)1517 public void imsServiceFeatureRemoved(int slotId, int feature, ImsServiceController controller) { 1518 removeImsController(slotId, feature); 1519 } 1520 1521 /** 1522 * Implementation of 1523 * {@link ImsServiceController.ImsServiceControllerCallbacks#imsServiceFeaturesChanged, which 1524 * notify the ImsResolver of a change to the supported ImsFeatures of a connected ImsService. 1525 */ imsServiceFeaturesChanged(ImsFeatureConfiguration config, ImsServiceController controller)1526 public void imsServiceFeaturesChanged(ImsFeatureConfiguration config, 1527 ImsServiceController controller) { 1528 if (controller == null || config == null) { 1529 return; 1530 } 1531 Log.i(TAG, "imsServiceFeaturesChanged: config=" + config.getServiceFeatures() 1532 + ", ComponentName=" + controller.getComponentName()); 1533 mEventLog.log("imsServiceFeaturesChanged - for " + controller + ", new config " 1534 + config.getServiceFeatures()); 1535 handleFeaturesChanged(controller.getComponentName(), config.getServiceFeatures()); 1536 } 1537 1538 @Override imsServiceBindPermanentError(ComponentName name, UserHandle user)1539 public void imsServiceBindPermanentError(ComponentName name, UserHandle user) { 1540 if (name == null) { 1541 return; 1542 } 1543 Log.w(TAG, "imsServiceBindPermanentError: component=" + name + ", user=" + user); 1544 mEventLog.log("imsServiceBindPermanentError - for " + name + ", user " + user); 1545 if (!mFeatureFlags.imsResolverUserAware()) { 1546 mHandler.obtainMessage(HANDLER_REMOVE_PACKAGE, 1547 name.getPackageName()).sendToTarget(); 1548 } else { 1549 mHandler.obtainMessage(HANDLER_REMOVE_PACKAGE_PERM_ERROR, 1550 new Pair<>(name.getPackageName(), user)).sendToTarget(); 1551 } 1552 } 1553 1554 /** 1555 * Determines if the features specified should cause a bind or keep a binding active to an 1556 * ImsService. 1557 * @return true if MMTEL or RCS features are present, false if they are not or only 1558 * EMERGENCY_MMTEL is specified. 1559 */ shouldFeaturesCauseBind(Set<ImsFeatureConfiguration.FeatureSlotPair> features)1560 private boolean shouldFeaturesCauseBind(Set<ImsFeatureConfiguration.FeatureSlotPair> features) { 1561 long bindableFeatures = features.stream() 1562 // remove all emergency features 1563 .filter(f -> f.featureType != ImsFeature.FEATURE_EMERGENCY_MMTEL).count(); 1564 return bindableFeatures > 0; 1565 } 1566 1567 // Possibly rebind to another ImsService for testing carrier ImsServices. 1568 // Called from the handler ONLY overrideCarrierService(int slotId, Map<Integer, String> featureMap)1569 private void overrideCarrierService(int slotId, Map<Integer, String> featureMap) { 1570 for (Integer featureType : featureMap.keySet()) { 1571 String overridePackageName = featureMap.get(featureType); 1572 mEventLog.log("overriding carrier ImsService to " + overridePackageName 1573 + " on slot " + slotId + " for feature " 1574 + ImsFeature.FEATURE_LOG_MAP.getOrDefault(featureType, "invalid")); 1575 setOverridePackageName(overridePackageName, slotId, featureType); 1576 } 1577 updateBoundServices(slotId, Collections.emptyMap()); 1578 } 1579 1580 // Possibly rebind to another ImsService for testing carrier ImsServices. 1581 // Called from the handler ONLY clearCarrierServiceOverrides(int slotId)1582 private void clearCarrierServiceOverrides(int slotId) { 1583 Log.i(TAG, "clearing carrier ImsService overrides"); 1584 mEventLog.log("clearing carrier ImsService overrides"); 1585 Set<String> removedPackages = removeOverridePackageName(slotId); 1586 for (String pkg : removedPackages) { 1587 clearPackageNameUserOverride(pkg); 1588 } 1589 carrierConfigChanged(slotId, getSubId(slotId)); 1590 } 1591 1592 // Possibly rebind to another ImsService for testing carrier ImsServices. 1593 // Called from the handler ONLY overrideDeviceService(Map<Integer, String> featureMap)1594 private void overrideDeviceService(Map<Integer, String> featureMap) { 1595 boolean requiresRecalc = false; 1596 for (Integer featureType : featureMap.keySet()) { 1597 String overridePackageName = featureMap.get(featureType); 1598 mEventLog.log("overriding device ImsService to " + overridePackageName + " for feature " 1599 + ImsFeature.FEATURE_LOG_MAP.getOrDefault(featureType, "invalid")); 1600 String oldPackageName = getDeviceConfiguration(featureType); 1601 if (!TextUtils.equals(oldPackageName, overridePackageName)) { 1602 Log.i(TAG, "overrideDeviceService - device package changed (override): " 1603 + oldPackageName + " -> " + overridePackageName); 1604 mEventLog.log("overrideDeviceService - device package changed (override): " 1605 + oldPackageName + " -> " + overridePackageName); 1606 clearPackageNameUserOverride(oldPackageName); 1607 setDeviceConfiguration(overridePackageName, featureType); 1608 ImsServiceInfo info = getVisibleImsServiceInfoFromCache(overridePackageName); 1609 if (info == null || info.featureFromMetadata) { 1610 requiresRecalc = true; 1611 } else { 1612 // Config will change when this query completes 1613 scheduleQueryForFeatures(info); 1614 } 1615 } 1616 } 1617 if (requiresRecalc) calculateFeatureConfigurationChange(); 1618 } 1619 1620 // Called from handler ONLY. carrierConfigChanged(int slotId, int subId)1621 private void carrierConfigChanged(int slotId, int subId) { 1622 setSubId(slotId, subId); 1623 updateBoundDeviceServices(); 1624 if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX) { 1625 // not specified, update carrier override cache and possibly rebind on all slots. 1626 for (int i = 0; i < mNumSlots; i++) { 1627 updateBoundServices(i, getImsPackageOverrideConfig(getSubId(i))); 1628 } 1629 } 1630 updateBoundServices(slotId, getImsPackageOverrideConfig(subId)); 1631 } 1632 updateBoundDeviceServices()1633 private void updateBoundDeviceServices() { 1634 Log.d(TAG, "updateBoundDeviceServices: called"); 1635 ArrayMap<String, ImsServiceInfo> featureDynamicImsPackages = new ArrayMap<>(); 1636 for (int f = ImsFeature.FEATURE_EMERGENCY_MMTEL; f < ImsFeature.FEATURE_MAX; f++) { 1637 String packageName = getDeviceConfiguration(f); 1638 ImsServiceInfo serviceInfo = getVisibleImsServiceInfoFromCache(packageName); 1639 if (serviceInfo != null && !serviceInfo.featureFromMetadata 1640 && !featureDynamicImsPackages.containsKey(packageName)) { 1641 featureDynamicImsPackages.put(packageName, serviceInfo); 1642 1643 Log.d(TAG, "updateBoundDeviceServices: Schedule query for package=" + packageName); 1644 scheduleQueryForFeatures(featureDynamicImsPackages.get(packageName)); 1645 } 1646 } 1647 } 1648 updateBoundServices(int slotId, Map<Integer, String> featureMap)1649 private void updateBoundServices(int slotId, Map<Integer, String> featureMap) { 1650 if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX || slotId >= mNumSlots) { 1651 return; 1652 } 1653 boolean hasConfigChanged = false; 1654 boolean didQuerySchedule = false; 1655 for (int f = ImsFeature.FEATURE_EMERGENCY_MMTEL; f < ImsFeature.FEATURE_MAX; f++) { 1656 String overridePackageName = getOverridePackageName(slotId, f); 1657 String oldPackageName = getCarrierConfiguredPackageName(slotId, f); 1658 String newPackageName = featureMap.getOrDefault(f, ""); 1659 if (!TextUtils.isEmpty(overridePackageName)) { 1660 // Do not allow carrier config changes to change the override package while it 1661 // is in effect. 1662 Log.i(TAG, String.format("updateBoundServices: overriding %s with %s for feature" 1663 + " %s on slot %d", 1664 TextUtils.isEmpty(newPackageName) ? "(none)" : newPackageName, 1665 overridePackageName, 1666 ImsFeature.FEATURE_LOG_MAP.getOrDefault(f, "invalid"), slotId)); 1667 newPackageName = overridePackageName; 1668 } 1669 1670 setCarrierConfiguredPackageName(newPackageName, slotId, f); 1671 // Carrier config may have not changed, but we still want to kick off a recalculation 1672 // in case there has been a change to the supported device features. 1673 ImsServiceInfo info = getVisibleImsServiceInfoFromCache(newPackageName); 1674 if (info == null || info.featureFromMetadata) { 1675 hasConfigChanged = true; 1676 } else { 1677 // Config will change when this query completes 1678 scheduleQueryForFeatures(info); 1679 didQuerySchedule = true; 1680 } 1681 Log.i(TAG, "updateBoundServices - carrier package changed: " 1682 + oldPackageName + " -> " + newPackageName + " on slot " + slotId 1683 + ", hasConfigChanged=" + hasConfigChanged); 1684 mEventLog.log("updateBoundServices - carrier package changed: " 1685 + oldPackageName + " -> " + newPackageName + " on slot " + slotId 1686 + ", hasConfigChanged=" + hasConfigChanged); 1687 } 1688 if (hasConfigChanged) calculateFeatureConfigurationChange(); 1689 1690 if (hasConfigChanged && didQuerySchedule) { 1691 mEventLog.log("[warning] updateBoundServices - both hasConfigChange and query " 1692 + "scheduled on slot " + slotId); 1693 } 1694 } 1695 getImsPackageOverrideConfig(int subId)1696 private @NonNull Map<Integer, String> getImsPackageOverrideConfig(int subId) { 1697 PersistableBundle config = mCarrierConfigManager.getConfigForSubId(subId); 1698 if (config == null) return Collections.emptyMap(); 1699 String packageNameMmTel = config.getString( 1700 CarrierConfigManager.KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING, null); 1701 // Set the config equal for the deprecated key. 1702 String packageNameRcs = packageNameMmTel; 1703 packageNameMmTel = config.getString( 1704 CarrierConfigManager.KEY_CONFIG_IMS_MMTEL_PACKAGE_OVERRIDE_STRING, 1705 packageNameMmTel); 1706 packageNameRcs = config.getString( 1707 CarrierConfigManager.KEY_CONFIG_IMS_RCS_PACKAGE_OVERRIDE_STRING, packageNameRcs); 1708 Map<Integer, String> result = new ArrayMap<>(); 1709 if (!TextUtils.isEmpty(packageNameMmTel)) { 1710 result.put(ImsFeature.FEATURE_EMERGENCY_MMTEL, packageNameMmTel); 1711 result.put(ImsFeature.FEATURE_MMTEL, packageNameMmTel); 1712 } 1713 if (!TextUtils.isEmpty(packageNameRcs)) { 1714 result.put(ImsFeature.FEATURE_RCS, packageNameRcs); 1715 } 1716 return result; 1717 } 1718 1719 /** 1720 * Schedules a query for dynamic ImsService features. 1721 */ scheduleQueryForFeatures(ImsServiceInfo service, int delayMs)1722 private void scheduleQueryForFeatures(ImsServiceInfo service, int delayMs) { 1723 if (service == null) { 1724 return; 1725 } 1726 Message msg = Message.obtain(mHandler, HANDLER_START_DYNAMIC_FEATURE_QUERY, service); 1727 if (mHandler.hasMessages(HANDLER_START_DYNAMIC_FEATURE_QUERY, service)) { 1728 Log.d(TAG, "scheduleQueryForFeatures: dynamic query for " + service.name 1729 + " already scheduled"); 1730 return; 1731 } 1732 Log.d(TAG, "scheduleQueryForFeatures: starting dynamic query for " + service.name 1733 + " in " + delayMs + "ms."); 1734 mHandler.sendMessageDelayed(msg, delayMs); 1735 } 1736 scheduleQueryForFeatures(ComponentName name, int delayMs)1737 private void scheduleQueryForFeatures(ComponentName name, int delayMs) { 1738 ImsServiceInfo service = getVisibleImsServiceInfoFromCache(name.getPackageName()); 1739 if (service == null) { 1740 Log.w(TAG, "scheduleQueryForFeatures: Couldn't find cached info for name: " + name); 1741 return; 1742 } 1743 scheduleQueryForFeatures(service, delayMs); 1744 } 1745 scheduleQueryForFeatures(ImsServiceInfo service)1746 private void scheduleQueryForFeatures(ImsServiceInfo service) { 1747 scheduleQueryForFeatures(service, 0); 1748 } 1749 1750 /** 1751 * Schedules the processing of a completed query. 1752 */ handleFeaturesChanged(ComponentName name, Set<ImsFeatureConfiguration.FeatureSlotPair> features)1753 private void handleFeaturesChanged(ComponentName name, 1754 Set<ImsFeatureConfiguration.FeatureSlotPair> features) { 1755 SomeArgs args = SomeArgs.obtain(); 1756 args.arg1 = name; 1757 args.arg2 = features; 1758 mHandler.obtainMessage(HANDLER_DYNAMIC_FEATURE_CHANGE, args).sendToTarget(); 1759 } 1760 handleMsimConfigChange(Integer newNumSlots)1761 private void handleMsimConfigChange(Integer newNumSlots) { 1762 int oldLen = mNumSlots; 1763 if (oldLen == newNumSlots) { 1764 return; 1765 } 1766 mNumSlots = newNumSlots; 1767 Log.i(TAG, "handleMsimConfigChange: oldLen=" + oldLen + ", newLen=" + newNumSlots); 1768 mEventLog.log("MSIM config change: " + oldLen + " -> " + newNumSlots); 1769 if (newNumSlots < oldLen) { 1770 // we need to trim data structures that use slots, however mBoundImsServicesByFeature 1771 // will be updated by ImsServiceController changing to remove features on old slots. 1772 // start at the index of the new highest slot + 1. 1773 for (int oldSlot = newNumSlots; oldSlot < oldLen; oldSlot++) { 1774 // First clear old carrier configs 1775 Map<Integer, String> carrierConfigs = getCarrierConfiguredPackageNames(oldSlot); 1776 for (Integer feature : carrierConfigs.keySet()) { 1777 setCarrierConfiguredPackageName("", oldSlot, feature); 1778 } 1779 // next clear old overrides 1780 SparseArray<String> overrideConfigs = getOverridePackageName(oldSlot); 1781 for (int i = 0; i < overrideConfigs.size(); i++) { 1782 int feature = overrideConfigs.keyAt(i); 1783 setOverridePackageName("", oldSlot, feature); 1784 } 1785 //clear removed slot. 1786 removeSlotId(oldSlot); 1787 } 1788 } 1789 // Get the new config for each ImsService. For manifest queries, this will update the 1790 // number of slots. 1791 // This will get all services with the correct intent filter from PackageManager 1792 List<ImsServiceInfo> infos = getImsServiceInfo(null); 1793 for (ImsServiceInfo info : infos) { 1794 ImsServiceInfo cachedInfo = mInstalledServicesCache.get(info.name); 1795 if (cachedInfo != null) { 1796 if (info.featureFromMetadata) { 1797 cachedInfo.replaceFeatures(info.getSupportedFeatures()); 1798 } else { 1799 // Remove features that are no longer supported by the device configuration. 1800 cachedInfo.getSupportedFeatures() 1801 .removeIf(filter -> filter.slotId >= newNumSlots); 1802 } 1803 } else { 1804 // This is unexpected, put the new service on the queue to be added 1805 mEventLog.log("handleMsimConfigChange: detected untracked service - " + info); 1806 Log.w(TAG, "handleMsimConfigChange: detected untracked package, queueing to add " 1807 + info); 1808 mHandler.obtainMessage(HANDLER_ADD_PACKAGE, 1809 info.name.getPackageName()).sendToTarget(); 1810 } 1811 } 1812 1813 if (newNumSlots < oldLen) { 1814 // A CarrierConfigChange will happen for the new slot, so only recalculate if there are 1815 // less new slots because we need to remove the old capabilities. 1816 calculateFeatureConfigurationChange(); 1817 } 1818 } 1819 1820 // Starts a dynamic query. Called from handler ONLY. startDynamicQuery(ImsServiceInfo service)1821 private void startDynamicQuery(ImsServiceInfo service) { 1822 UserHandle user = getUserForBind(service); 1823 if (user == null) { 1824 Log.i(TAG, "scheduleQueryForFeatures: skipping query for ImsService that is not" 1825 + " running: " + service); 1826 return; 1827 } 1828 // if not current device/carrier service, don't perform query. If this changes, this method 1829 // will be called again. 1830 if (!isDeviceService(service) && getSlotsForActiveCarrierService(service).isEmpty()) { 1831 Log.i(TAG, "scheduleQueryForFeatures: skipping query for ImsService that is not" 1832 + " set as carrier/device ImsService."); 1833 return; 1834 } 1835 mEventLog.log("startDynamicQuery - starting query for " + service); 1836 boolean queryStarted = mFeatureQueryManager.startQuery(service.name, user, 1837 service.controllerFactory.getServiceInterface()); 1838 if (!queryStarted) { 1839 Log.w(TAG, "startDynamicQuery: service could not connect. Retrying after delay."); 1840 mEventLog.log("startDynamicQuery - query failed. Retrying in " 1841 + DELAY_DYNAMIC_QUERY_MS + " mS"); 1842 scheduleQueryForFeatures(service, DELAY_DYNAMIC_QUERY_MS); 1843 } else { 1844 Log.d(TAG, "startDynamicQuery: Service queried, waiting for response."); 1845 } 1846 } 1847 1848 // process complete dynamic query. Called from handler ONLY. dynamicQueryComplete(ComponentName name, Set<ImsFeatureConfiguration.FeatureSlotPair> features)1849 private void dynamicQueryComplete(ComponentName name, 1850 Set<ImsFeatureConfiguration.FeatureSlotPair> features) { 1851 ImsServiceInfo service = getVisibleImsServiceInfoFromCache(name.getPackageName()); 1852 if (service == null) { 1853 Log.w(TAG, "dynamicQueryComplete: Couldn't find cached info for name: " 1854 + name); 1855 return; 1856 } 1857 sanitizeFeatureConfig(features); 1858 mEventLog.log("dynamicQueryComplete: for package " + name + ", features: " 1859 + printFeatures(service.getSupportedFeatures()) + " -> " + printFeatures(features)); 1860 // Add features to service 1861 service.replaceFeatures(features); 1862 // Wait until all queries have completed before changing the configuration to reduce churn. 1863 if (!mFeatureQueryManager.isQueryInProgress()) { 1864 if (mHandler.hasMessages(HANDLER_DYNAMIC_FEATURE_CHANGE)) { 1865 mEventLog.log("[warning] dynamicQueryComplete - HANDLER_DYNAMIC_FEATURE_CHANGE " 1866 + "pending with calculateFeatureConfigurationChange()"); 1867 } 1868 calculateFeatureConfigurationChange(); 1869 } 1870 } 1871 1872 /** 1873 * Sanitize feature configurations from the ImsService. 1874 * <ul> 1875 * <li> Strip out feature configs for inactive slots.</li> 1876 * <li> Ensure the feature includes MMTEL when it supports EMERGENCY_MMTEL, if not, remove. 1877 * </li> 1878 * </ul> 1879 */ sanitizeFeatureConfig(Set<ImsFeatureConfiguration.FeatureSlotPair> features)1880 private void sanitizeFeatureConfig(Set<ImsFeatureConfiguration.FeatureSlotPair> features) { 1881 // remove configs for slots that are mot active. 1882 features.removeIf(f -> f.slotId >= mNumSlots); 1883 // Ensure that if EMERGENCY_MMTEL is defined for a slot, MMTEL is also defined. 1884 Set<ImsFeatureConfiguration.FeatureSlotPair> emergencyMmtelFeatures = features.stream() 1885 .filter(feature -> feature.featureType == ImsFeature.FEATURE_EMERGENCY_MMTEL) 1886 .collect(Collectors.toSet()); 1887 for (ImsFeatureConfiguration.FeatureSlotPair feature : emergencyMmtelFeatures) { 1888 if (!features.contains(new ImsFeatureConfiguration.FeatureSlotPair(feature.slotId, 1889 ImsFeature.FEATURE_MMTEL))) { 1890 features.remove(feature); 1891 } 1892 } 1893 } 1894 1895 // Calculate the new configuration for the bound ImsServices. 1896 // Should ONLY be called from the handler. calculateFeatureConfigurationChangeOld()1897 private void calculateFeatureConfigurationChangeOld() { 1898 for (ImsServiceInfo info : mInstalledServicesCache.values()) { 1899 Set<ImsFeatureConfiguration.FeatureSlotPair> features = calculateFeaturesToCreate(info); 1900 if (shouldFeaturesCauseBind(features)) { 1901 bindImsServiceWithFeatures(info, mContext.getUser(), features); 1902 } else { 1903 unbindImsService(info); 1904 } 1905 } 1906 } 1907 1908 // Should ONLY be called from the handler. calculateFeatureConfigurationChange()1909 private void calculateFeatureConfigurationChange() { 1910 if (!mFeatureFlags.imsResolverUserAware()) { 1911 calculateFeatureConfigurationChangeOld(); 1912 return; 1913 } 1914 // There is an implicit assumption here that the ImsServiceController will remove itself 1915 // from caches BEFORE adding a new one. If this assumption is broken, we will remove a valid 1916 // ImsServiceController from the cache accidentally. To keep this assumption valid, we will 1917 // iterate through the cache twice - first to unbind, then to bind and change features of 1918 // existing ImsServiceControllers. This is a little inefficient, but there should be on the 1919 // order of 10 installed ImsServices at most, so running through this list twice is 1920 // reasonable vs the memory cost of caching binding vs unbinding services. 1921 1922 // Unbind first if needed 1923 for (ImsServiceInfo info : mInstalledServicesCache.values()) { 1924 Set<ImsFeatureConfiguration.FeatureSlotPair> features = calculateFeaturesToCreate(info); 1925 UserHandle user = getUserForBind(info); 1926 if (shouldFeaturesCauseBind(features) && user != null) continue; 1927 unbindImsService(info); 1928 } 1929 // Bind/alter features second 1930 for (ImsServiceInfo info : mInstalledServicesCache.values()) { 1931 Set<ImsFeatureConfiguration.FeatureSlotPair> features = calculateFeaturesToCreate(info); 1932 UserHandle user = getUserForBind(info); 1933 if (shouldFeaturesCauseBind(features) && user != null) { 1934 bindImsServiceWithFeatures(info, user, features); 1935 } 1936 } 1937 } 1938 1939 /** 1940 * Returns the UserHandle that should be used to bind the ImsService. 1941 * 1942 * @return The UserHandle of the user that telephony is running in if the 1943 * ImsService is configured to run in that user, or the current active user 1944 * if not. Returns null if the ImsService is not configured to run in any 1945 * active user. 1946 */ getUserForBind(ImsServiceInfo info)1947 private UserHandle getUserForBind(ImsServiceInfo info) { 1948 if (!mFeatureFlags.imsResolverUserAware()) { 1949 return mContext.getUser(); 1950 } 1951 UserHandle currentUser = mActivityManagerProxy.getCurrentUser(); 1952 List<UserHandle> activeUsers = getActiveUsers().stream() 1953 .filter(info.users::contains).toList(); 1954 if (activeUsers.isEmpty()) return null; 1955 // If there is a test restriction in place for this package, prioritize that restriction 1956 UserHandle testRestriction = mImsServiceTestUserRestrictions.getOrDefault( 1957 info.name.getPackageName(), null); 1958 if (testRestriction != null && activeUsers.stream() 1959 .anyMatch(u -> Objects.equals(u, testRestriction))) { 1960 return testRestriction; 1961 } 1962 // Prioritize the User that Telephony is in, since it is always running 1963 if (activeUsers.stream() 1964 .anyMatch(u -> Objects.equals(u, mContext.getUser()))) { 1965 return mContext.getUser(); 1966 } 1967 if (activeUsers.stream().anyMatch(u -> Objects.equals(u, currentUser))) { 1968 return currentUser; 1969 } 1970 return null; 1971 } 1972 1973 /** 1974 * Returns the set of full users that are currently active. 1975 */ getActiveUsers()1976 private Set<UserHandle> getActiveUsers() { 1977 Set<UserHandle> profiles = new HashSet<>(); 1978 profiles.add(mContext.getUser()); 1979 profiles.add(mActivityManagerProxy.getCurrentUser()); 1980 return profiles; 1981 } 1982 printFeatures(Set<ImsFeatureConfiguration.FeatureSlotPair> features)1983 private static String printFeatures(Set<ImsFeatureConfiguration.FeatureSlotPair> features) { 1984 StringBuilder featureString = new StringBuilder(); 1985 featureString.append(" features: ["); 1986 if (features != null) { 1987 for (ImsFeatureConfiguration.FeatureSlotPair feature : features) { 1988 featureString.append("{"); 1989 featureString.append(feature.slotId); 1990 featureString.append(","); 1991 featureString.append(ImsFeature.FEATURE_LOG_MAP.get(feature.featureType)); 1992 featureString.append("}"); 1993 } 1994 featureString.append("]"); 1995 } 1996 return featureString.toString(); 1997 } 1998 1999 /** 2000 * Returns the ImsServiceInfo that matches the provided packageName if it belongs to a 2001 * package that is visible as part of the set of active users. 2002 */ getVisibleImsServiceInfoFromCache(String packageName)2003 public ImsServiceInfo getVisibleImsServiceInfoFromCache(String packageName) { 2004 ImsServiceInfo match = getImsServiceInfoFromCache(packageName); 2005 if (!mFeatureFlags.imsResolverUserAware()) { 2006 return match; 2007 } 2008 if (match == null) return null; 2009 UserHandle targetUser = getUserForBind(match); 2010 Log.d(TAG, "getVisibleImsServiceInfoFromCache: " + packageName + ", match=" + match 2011 + ", targetUser=" + targetUser); 2012 if (targetUser != null) return match; else return null; 2013 } 2014 2015 /** 2016 * Returns the ImsServiceInfo that matches the provided packageName. This includes 2017 * ImsServiceInfos that are not currently visible for the active users. 2018 */ 2019 @VisibleForTesting getImsServiceInfoFromCache(String packageName)2020 public ImsServiceInfo getImsServiceInfoFromCache(String packageName) { 2021 if (TextUtils.isEmpty(packageName)) { 2022 return null; 2023 } 2024 ImsServiceInfo infoFilter = getInfoByPackageName(mInstalledServicesCache, packageName); 2025 if (infoFilter != null) { 2026 return infoFilter; 2027 } else { 2028 return null; 2029 } 2030 } 2031 2032 // Return the ImsServiceInfo specified for the package name. If the package name is null, 2033 // get all packages that support ImsServices. getImsServiceInfo(String packageName)2034 private List<ImsServiceInfo> getImsServiceInfo(String packageName) { 2035 List<ImsServiceInfo> infos = new ArrayList<>(); 2036 // Search for Current ImsService implementations 2037 infos.addAll(searchForImsServices(packageName, mImsServiceControllerFactory)); 2038 // Search for compat ImsService Implementations 2039 infos.addAll(searchForImsServices(packageName, mImsServiceControllerFactoryCompat)); 2040 return infos; 2041 } 2042 getInfoFromCache(List<ImsServiceInfo> infos, ComponentName componentName)2043 private ImsServiceInfo getInfoFromCache(List<ImsServiceInfo> infos, 2044 ComponentName componentName) { 2045 return infos.stream().filter(info -> Objects.equals(info.name, componentName)).findFirst() 2046 .orElse(null); 2047 } 2048 searchForImsServices(String packageName, ImsServiceControllerFactory controllerFactory)2049 private List<ImsServiceInfo> searchForImsServices(String packageName, 2050 ImsServiceControllerFactory controllerFactory) { 2051 List<ImsServiceInfo> infos = new ArrayList<>(); 2052 2053 Intent serviceIntent = new Intent(controllerFactory.getServiceInterface()); 2054 serviceIntent.setPackage(packageName); 2055 2056 Set<UserHandle> profiles; 2057 if (mFeatureFlags.imsResolverUserAware()) { 2058 profiles = getActiveUsers(); 2059 } else { 2060 profiles = Collections.singleton(mContext.getUser()); 2061 } 2062 Log.v(TAG, "searchForImsServices: package=" + packageName + ", users=" + profiles); 2063 2064 PackageManager packageManager = mContext.getPackageManager(); 2065 for (UserHandle handle : profiles) { 2066 for (ResolveInfo entry : packageManager.queryIntentServicesAsUser(serviceIntent, 2067 PackageManager.GET_META_DATA, handle)) { 2068 ServiceInfo serviceInfo = entry.serviceInfo; 2069 2070 if (serviceInfo != null) { 2071 ComponentName name = new ComponentName(serviceInfo.packageName, 2072 serviceInfo.name); 2073 ImsServiceInfo info = getInfoFromCache(infos, name); 2074 if (info != null) { 2075 info.users.add(handle); 2076 Log.d(TAG, "service modify users:" + info); 2077 continue; 2078 } else { 2079 info = new ImsServiceInfo(name); 2080 info.users.add(handle); 2081 } 2082 info.controllerFactory = controllerFactory; 2083 2084 // we will allow the manifest method of declaring manifest features in two 2085 // cases: 2086 2087 // 1) it is the device overlay "default" ImsService, where the features do not 2088 // change (the new method can still be used if the default does not define 2089 // manifest entries). 2090 // 2) using the "compat" ImsService, which only supports manifest query. 2091 if (isDeviceService(info) 2092 || mImsServiceControllerFactoryCompat == controllerFactory) { 2093 if (serviceInfo.metaData != null) { 2094 if (serviceInfo.metaData.getBoolean(METADATA_MMTEL_FEATURE, false)) { 2095 info.addFeatureForAllSlots(mNumSlots, ImsFeature.FEATURE_MMTEL); 2096 // only allow FEATURE_EMERGENCY_MMTEL if FEATURE_MMTEL is defined. 2097 if (serviceInfo.metaData.getBoolean( 2098 METADATA_EMERGENCY_MMTEL_FEATURE, 2099 false)) { 2100 info.addFeatureForAllSlots(mNumSlots, 2101 ImsFeature.FEATURE_EMERGENCY_MMTEL); 2102 } 2103 } 2104 if (serviceInfo.metaData.getBoolean(METADATA_RCS_FEATURE, false)) { 2105 info.addFeatureForAllSlots(mNumSlots, ImsFeature.FEATURE_RCS); 2106 } 2107 } 2108 // Only dynamic query if we are not a compat version of ImsService and the 2109 // default service. 2110 if (mImsServiceControllerFactoryCompat != controllerFactory 2111 && info.getSupportedFeatures().isEmpty()) { 2112 // metadata empty, try dynamic query instead 2113 info.featureFromMetadata = false; 2114 } 2115 } else { 2116 // We are a carrier service and not using the compat version of ImsService. 2117 info.featureFromMetadata = false; 2118 } 2119 Log.d(TAG, "service name: " + info.name + ", manifest query: " 2120 + info.featureFromMetadata + ", users: " + info.users); 2121 // Check manifest permission to be sure that the service declares the correct 2122 // permissions. Overridden if the METADATA_OVERRIDE_PERM_CHECK metadata is set 2123 // to true. 2124 // NOTE: METADATA_OVERRIDE_PERM_CHECK should only be set for testing. 2125 if (TextUtils.equals(serviceInfo.permission, 2126 Manifest.permission.BIND_IMS_SERVICE) 2127 || serviceInfo.metaData.getBoolean(METADATA_OVERRIDE_PERM_CHECK, 2128 false)) { 2129 infos.add(info); 2130 } else { 2131 Log.w(TAG, "ImsService is not protected with BIND_IMS_SERVICE permission: " 2132 + info.name); 2133 } 2134 } 2135 } 2136 } 2137 return infos; 2138 } 2139 setSubId(int slotId, int subId)2140 private void setSubId(int slotId, int subId) { 2141 synchronized (mSlotIdToSubIdMap) { 2142 mSlotIdToSubIdMap.put(slotId, subId); 2143 } 2144 } 2145 getSubId(int slotId)2146 private int getSubId(int slotId) { 2147 synchronized (mSlotIdToSubIdMap) { 2148 return mSlotIdToSubIdMap.get(slotId, SubscriptionManager.INVALID_SUBSCRIPTION_ID); 2149 } 2150 } removeSlotId(int slotId)2151 private void removeSlotId(int slotId) { 2152 synchronized (mSlotIdToSubIdMap) { 2153 mSlotIdToSubIdMap.delete(slotId); 2154 } 2155 } 2156 2157 // Dump is called on the main thread, since ImsResolver Handler is also handled on main thread, 2158 // we shouldn't need to worry about concurrent access of private params. dump(FileDescriptor fd, PrintWriter printWriter, String[] args)2159 public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { 2160 IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); 2161 pw.println("ImsResolver:"); 2162 pw.increaseIndent(); 2163 pw.println("Configurations:"); 2164 pw.increaseIndent(); 2165 pw.println("Device:"); 2166 pw.increaseIndent(); 2167 synchronized (mDeviceServices) { 2168 for (Integer i : mDeviceServices.keySet()) { 2169 pw.println(ImsFeature.FEATURE_LOG_MAP.get(i) + " -> " + mDeviceServices.get(i)); 2170 } 2171 } 2172 pw.decreaseIndent(); 2173 pw.println("Carrier: "); 2174 pw.increaseIndent(); 2175 for (int i = 0; i < mNumSlots; i++) { 2176 for (int j = 0; j < MmTelFeature.FEATURE_MAX; j++) { 2177 pw.print("slot="); 2178 pw.print(i); 2179 pw.print(", feature="); 2180 pw.print(ImsFeature.FEATURE_LOG_MAP.getOrDefault(j, "?")); 2181 pw.println(": "); 2182 pw.increaseIndent(); 2183 String name = getCarrierConfiguredPackageName(i, j); 2184 pw.println(TextUtils.isEmpty(name) ? "none" : name); 2185 pw.decreaseIndent(); 2186 } 2187 } 2188 pw.decreaseIndent(); 2189 pw.decreaseIndent(); 2190 pw.println("Cached ImsServices:"); 2191 pw.increaseIndent(); 2192 for (ImsServiceInfo i : mInstalledServicesCache.values()) { 2193 pw.println(i); 2194 } 2195 pw.decreaseIndent(); 2196 pw.println("Active controllers:"); 2197 pw.increaseIndent(); 2198 for (ImsServiceController c : mActiveControllers.values()) { 2199 pw.println(c); 2200 pw.increaseIndent(); 2201 c.dump(pw); 2202 pw.decreaseIndent(); 2203 } 2204 pw.decreaseIndent(); 2205 pw.println("Connection Repository Log:"); 2206 pw.increaseIndent(); 2207 mRepo.dump(pw); 2208 pw.decreaseIndent(); 2209 pw.println("Event Log:"); 2210 pw.increaseIndent(); 2211 mEventLog.dump(pw); 2212 pw.decreaseIndent(); 2213 } 2214 } 2215