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 android.telephony.ims; 18 19 import android.annotation.LongDef; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.annotation.SuppressLint; 23 import android.annotation.SystemApi; 24 import android.app.Service; 25 import android.content.Intent; 26 import android.os.IBinder; 27 import android.os.RemoteException; 28 import android.telephony.CarrierConfigManager; 29 import android.telephony.ims.aidl.IImsConfig; 30 import android.telephony.ims.aidl.IImsMmTelFeature; 31 import android.telephony.ims.aidl.IImsRcsFeature; 32 import android.telephony.ims.aidl.IImsRegistration; 33 import android.telephony.ims.aidl.IImsServiceController; 34 import android.telephony.ims.aidl.IImsServiceControllerListener; 35 import android.telephony.ims.aidl.ISipTransport; 36 import android.telephony.ims.feature.ImsFeature; 37 import android.telephony.ims.feature.MmTelFeature; 38 import android.telephony.ims.feature.RcsFeature; 39 import android.telephony.ims.stub.ImsConfigImplBase; 40 import android.telephony.ims.stub.ImsFeatureConfiguration; 41 import android.telephony.ims.stub.ImsRegistrationImplBase; 42 import android.telephony.ims.stub.SipTransportImplBase; 43 import android.util.Log; 44 import android.util.SparseArray; 45 import android.util.SparseBooleanArray; 46 47 import com.android.ims.internal.IImsFeatureStatusCallback; 48 import com.android.internal.annotations.VisibleForTesting; 49 import com.android.internal.telephony.util.TelephonyUtils; 50 51 import java.lang.annotation.Retention; 52 import java.lang.annotation.RetentionPolicy; 53 import java.util.Map; 54 import java.util.NoSuchElementException; 55 import java.util.concurrent.CancellationException; 56 import java.util.concurrent.CompletableFuture; 57 import java.util.concurrent.CompletionException; 58 import java.util.concurrent.ExecutionException; 59 import java.util.concurrent.Executor; 60 import java.util.function.Supplier; 61 62 /** 63 * Main ImsService implementation, which binds via the Telephony ImsResolver. Services that extend 64 * ImsService must register the service in their AndroidManifest to be detected by the framework. 65 * First, the application must declare that they use the "android.permission.BIND_IMS_SERVICE" 66 * permission. Then, the ImsService definition in the manifest must follow the following format: 67 * 68 * ... 69 * <service android:name=".EgImsService" 70 * android:permission="android.permission.BIND_IMS_SERVICE" > 71 * ... 72 * <intent-filter> 73 * <action android:name="android.telephony.ims.ImsService" /> 74 * </intent-filter> 75 * </service> 76 * ... 77 * 78 * The telephony framework will then bind to the ImsService you have defined in your manifest 79 * if you are either: 80 * 1) Defined as the default ImsService for the device in the device overlay using 81 * "config_ims_mmtel_package" or "config_ims_rcs_package". 82 * 2) Defined as a Carrier Provided ImsService in the Carrier Configuration using 83 * {@link CarrierConfigManager#KEY_CONFIG_IMS_MMTEL_PACKAGE_OVERRIDE_STRING} or 84 * {@link CarrierConfigManager#KEY_CONFIG_IMS_RCS_PACKAGE_OVERRIDE_STRING}. 85 * 86 * There are two ways to define to the platform which {@link ImsFeature}s this {@link ImsService} 87 * supports, dynamic or static definitions. 88 * 89 * In the static definition, the {@link ImsFeature}s that are supported are defined in the service 90 * definition of the AndroidManifest.xml file as metadata: 91 * <!-- Apps must declare which features they support as metadata. The different categories are 92 * defined below. In this example, the MMTEL_FEATURE feature is supported. --> 93 * <meta-data android:name="android.telephony.ims.MMTEL_FEATURE" android:value="true" /> 94 * 95 * The features that are currently supported in an ImsService are: 96 * - RCS_FEATURE: This ImsService implements the RcsFeature class. 97 * - MMTEL_FEATURE: This ImsService implements the MmTelFeature class. 98 * - EMERGENCY_MMTEL_FEATURE: This ImsService supports Emergency Calling for MMTEL, must be 99 * declared along with the MMTEL_FEATURE. If this is not specified, the framework will use 100 * circuit switch for emergency calling. 101 * 102 * In the dynamic definition, the supported features are not specified in the service definition 103 * of the AndroidManifest. Instead, the framework binds to this service and calls 104 * {@link #querySupportedImsFeatures()}. The {@link ImsService} then returns an 105 * {@link ImsFeatureConfiguration}, which the framework uses to initialize the supported 106 * {@link ImsFeature}s. If at any time, the list of supported {@link ImsFeature}s changes, 107 * {@link #onUpdateSupportedImsFeatures(ImsFeatureConfiguration)} can be called to tell the 108 * framework of the changes. 109 * 110 * @hide 111 */ 112 @SystemApi 113 public class ImsService extends Service { 114 115 private static final String LOG_TAG = "ImsService"; 116 117 /** 118 * This ImsService supports the capability to place emergency calls over MMTEL. 119 * <p> 120 * Note: This should never be set by {@link #getImsServiceCapabilities()}, as whether it is 121 * there or not depends on whether or not {@link ImsFeature#FEATURE_EMERGENCY_MMTEL} is defined 122 * for this ImsService. If it is set, it will be removed during sanitization before the final 123 * capabilities bitfield is sent back to the framework. 124 * @hide This is encoded into the {@link ImsFeature#FEATURE_EMERGENCY_MMTEL}, but we will be 125 * adding other capabilities in a central location, so track this capability here as well. 126 */ 127 public static final long CAPABILITY_EMERGENCY_OVER_MMTEL = 1 << 0; 128 129 /** 130 * This ImsService supports the capability to create SIP delegates for other IMS applications 131 * to use to proxy SIP messaging traffic through it. 132 * <p> 133 * In order for the framework to report SipDelegate creation as being available for this 134 * ImsService implementation, this ImsService must report this capability flag in 135 * {@link #getImsServiceCapabilities()}, {@link #getSipTransport(int)} must not return null, and 136 * this ImsService MUST report the ability to create both {@link ImsFeature#FEATURE_MMTEL} and 137 * {@link ImsFeature#FEATURE_RCS} features. 138 */ 139 public static final long CAPABILITY_SIP_DELEGATE_CREATION = 1 << 1; 140 141 /** 142 * This ImsService supports the terminal based call waiting service. 143 * <p> 144 * In order for the IMS service to support the service, IMS service shall 145 * override {@link MmTelFeature#setTerminalBasedCallWaitingStatus}. 146 * If ImsService has this capability, Android platform will handle the synchronization 147 * between the network based call waiting service over circuit-switched networks and the 148 * terminal based call waiting service of IMS service, and will handle the received 149 * circuit-switched waiting calls. Otherwise, this functionality of Android platform shall 150 * be disabled. 151 */ 152 public static final long CAPABILITY_TERMINAL_BASED_CALL_WAITING = 1 << 2; 153 154 /** 155 * Used for internal correctness checks of capabilities set by the ImsService implementation and 156 * tracks the index of the largest defined flag in the capabilities long. 157 * @hide 158 */ 159 public static final long CAPABILITY_MAX_INDEX = 160 Long.numberOfTrailingZeros(CAPABILITY_TERMINAL_BASED_CALL_WAITING); 161 162 /** 163 * @hide 164 */ 165 @LongDef(flag = true, 166 prefix = "CAPABILITY_", 167 value = { 168 // CAPABILITY_EMERGENCY_OVER_MMTEL is not included here because it is managed by 169 // whether or not ImsFeature.FEATURE_EMERGENCY_MMTEL feature is set and should 170 // not be set by users of ImsService. 171 CAPABILITY_SIP_DELEGATE_CREATION, 172 CAPABILITY_TERMINAL_BASED_CALL_WAITING 173 }) 174 @Retention(RetentionPolicy.SOURCE) 175 public @interface ImsServiceCapability {} 176 177 /** 178 * Used for logging purposes, see {@link #getCapabilitiesString(long)} 179 * @hide 180 */ 181 private static final Map<Long, String> CAPABILITIES_LOG_MAP = Map.of( 182 CAPABILITY_EMERGENCY_OVER_MMTEL, "EMERGENCY_OVER_MMTEL", 183 CAPABILITY_SIP_DELEGATE_CREATION, "SIP_DELEGATE_CREATION"); 184 185 /** 186 * The intent that must be defined as an intent-filter in the AndroidManifest of the ImsService. 187 * @hide 188 */ 189 public static final String SERVICE_INTERFACE = "android.telephony.ims.ImsService"; 190 191 // A map of slot Id -> map of features (indexed by ImsFeature feature id) corresponding to that 192 // slot. 193 // We keep track of this to facilitate cleanup of the IImsFeatureStatusCallback and 194 // call ImsFeature#onFeatureRemoved. 195 private final SparseArray<SparseArray<ImsFeature>> mFeaturesBySlot = new SparseArray<>(); 196 197 // A map of slot id -> boolean array, where each entry in the boolean array corresponds to an 198 // ImsFeature that was created for a slot id and not a sub id for backwards compatibility 199 // purposes. 200 private final SparseArray<SparseBooleanArray> mCreateImsFeatureWithSlotIdFlagMap = 201 new SparseArray<>(); 202 203 private IImsServiceControllerListener mListener; 204 private final Object mListenerLock = new Object(); 205 private final Object mExecutorLock = new Object(); 206 private Executor mExecutor; 207 208 /** 209 * Create a new ImsService. 210 * <p> 211 * Method stubs called from the framework will be called asynchronously. Vendor specifies the 212 * {@link Executor} that the methods stubs will be called. If mExecutor is set to null by 213 * vendor use Runnable::run. 214 */ ImsService()215 public ImsService() { 216 } 217 218 /** 219 * Listener that notifies the framework of ImsService changes. 220 * @hide 221 */ 222 public static class Listener extends IImsServiceControllerListener.Stub { 223 /** 224 * The IMS features that this ImsService supports has changed. 225 * @param c a new {@link ImsFeatureConfiguration} containing {@link ImsFeature.FeatureType}s 226 * that this ImsService supports. This may trigger the addition/removal of feature 227 * in this service. 228 */ onUpdateSupportedImsFeatures(ImsFeatureConfiguration c)229 public void onUpdateSupportedImsFeatures(ImsFeatureConfiguration c) { 230 } 231 } 232 233 /** 234 * @hide 235 */ 236 protected final IBinder mImsServiceController = new IImsServiceController.Stub() { 237 @Override 238 public void setListener(IImsServiceControllerListener l) { 239 synchronized (mListenerLock) { 240 if (mListener != null && mListener.asBinder().isBinderAlive()) { 241 try { 242 mListener.asBinder().unlinkToDeath(mDeathRecipient, 0); 243 } catch (NoSuchElementException e) { 244 Log.w(LOG_TAG, "IImsServiceControllerListener does not exist"); 245 } 246 } 247 248 mListener = l; 249 if (mListener == null) { 250 executeMethodAsync(() -> releaseResource(), "releaseResource"); 251 return; 252 } 253 254 try { 255 mListener.asBinder().linkToDeath(mDeathRecipient, 0); 256 Log.i(LOG_TAG, "setListener: register linkToDeath"); 257 } catch (RemoteException e) { 258 // RemoteException means target binder process was crashed 259 // release resource 260 executeMethodAsync(() -> releaseResource(), "releaseResource"); 261 } 262 } 263 } 264 265 @Override 266 public IImsMmTelFeature createMmTelFeature(int slotId, int subId) { 267 MmTelFeature f = (MmTelFeature) getImsFeature(slotId, ImsFeature.FEATURE_MMTEL); 268 if (f == null) { 269 return executeMethodAsyncForResult(() -> createMmTelFeatureInternal(slotId, subId), 270 "createMmTelFeature"); 271 } else { 272 return f.getBinder(); 273 } 274 } 275 276 @Override 277 public IImsMmTelFeature createEmergencyOnlyMmTelFeature(int slotId) { 278 MmTelFeature f = (MmTelFeature) getImsFeature(slotId, ImsFeature.FEATURE_MMTEL); 279 if (f == null) { 280 return executeMethodAsyncForResult(() -> createEmergencyOnlyMmTelFeatureInternal( 281 slotId), "createEmergencyOnlyMmTelFeature"); 282 } else { 283 return f.getBinder(); 284 } 285 } 286 287 @Override 288 public IImsRcsFeature createRcsFeature(int slotId, int subId) { 289 RcsFeature f = (RcsFeature) getImsFeature(slotId, ImsFeature.FEATURE_RCS); 290 if (f == null) { 291 return executeMethodAsyncForResult(() -> 292 createRcsFeatureInternal(slotId, subId), "createRcsFeature"); 293 } else { 294 return f.getBinder(); 295 } 296 } 297 298 @Override 299 public void addFeatureStatusCallback(int slotId, int featureType, 300 IImsFeatureStatusCallback c) { 301 executeMethodAsync(() -> ImsService.this.addImsFeatureStatusCallback( 302 slotId, featureType, c), "addFeatureStatusCallback"); 303 } 304 305 @Override 306 public void removeFeatureStatusCallback(int slotId, int featureType, 307 IImsFeatureStatusCallback c) { 308 executeMethodAsync(() -> ImsService.this.removeImsFeatureStatusCallback( 309 slotId, featureType, c), "removeFeatureStatusCallback"); 310 } 311 312 @Override 313 public void removeImsFeature(int slotId, int featureType, boolean changeSubId) { 314 if (changeSubId && isImsFeatureCreatedForSlot(slotId, featureType)) { 315 Log.w(LOG_TAG, "Do not remove Ims feature for compatibility"); 316 return; 317 } 318 executeMethodAsync(() -> ImsService.this.removeImsFeature(slotId, featureType), 319 "removeImsFeature"); 320 setImsFeatureCreatedForSlot(slotId, featureType, false); 321 } 322 323 @Override 324 public ImsFeatureConfiguration querySupportedImsFeatures() { 325 return executeMethodAsyncForResult(() -> ImsService.this.querySupportedImsFeatures(), 326 "ImsFeatureConfiguration"); 327 } 328 329 @Override 330 public long getImsServiceCapabilities() { 331 return executeMethodAsyncForResult(() -> { 332 long caps = ImsService.this.getImsServiceCapabilities(); 333 long sanitizedCaps = sanitizeCapabilities(caps); 334 if (caps != sanitizedCaps) { 335 Log.w(LOG_TAG, "removing invalid bits from field: 0x" 336 + Long.toHexString(caps ^ sanitizedCaps)); 337 } 338 return sanitizedCaps; 339 }, "getImsServiceCapabilities"); 340 } 341 342 @Override 343 public void notifyImsServiceReadyForFeatureCreation() { 344 executeMethodAsync(() -> ImsService.this.readyForFeatureCreation(), 345 "notifyImsServiceReadyForFeatureCreation"); 346 } 347 348 @Override 349 public IImsConfig getConfig(int slotId, int subId) { 350 return executeMethodAsyncForResult(() -> { 351 ImsConfigImplBase c = 352 ImsService.this.getConfigForSubscription(slotId, subId); 353 if (c != null) { 354 c.setDefaultExecutor(getCachedExecutor()); 355 return c.getIImsConfig(); 356 } else { 357 return null; 358 } 359 }, "getConfig"); 360 } 361 362 @Override 363 public IImsRegistration getRegistration(int slotId, int subId) { 364 return executeMethodAsyncForResult(() -> { 365 ImsRegistrationImplBase r = 366 ImsService.this.getRegistrationForSubscription(slotId, subId); 367 if (r != null) { 368 r.setDefaultExecutor(getCachedExecutor()); 369 return r.getBinder(); 370 } else { 371 return null; 372 } 373 }, "getRegistration"); 374 } 375 376 @Override 377 public ISipTransport getSipTransport(int slotId) { 378 return executeMethodAsyncForResult(() -> { 379 SipTransportImplBase s = ImsService.this.getSipTransport(slotId); 380 if (s != null) { 381 s.setDefaultExecutor(getCachedExecutor()); 382 return s.getBinder(); 383 } else { 384 return null; 385 } 386 }, "getSipTransport"); 387 } 388 389 @Override 390 public void enableIms(int slotId, int subId) { 391 executeMethodAsync(() -> 392 ImsService.this.enableImsForSubscription(slotId, subId), "enableIms"); 393 } 394 395 @Override 396 public void disableIms(int slotId, int subId) { 397 executeMethodAsync(() -> 398 ImsService.this.disableImsForSubscription(slotId, subId), "disableIms"); 399 } 400 401 @Override 402 public void resetIms(int slotId, int subId) { 403 executeMethodAsync(() -> 404 ImsService.this.resetImsInternal(slotId, subId), "resetIms"); 405 } 406 }; 407 408 private final IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() { 409 @Override 410 public void binderDied() { 411 Log.w(LOG_TAG, 412 "IImsServiceControllerListener binder to framework has died. Cleaning up"); 413 executeMethodAsync(() -> releaseResource(), "releaseResource"); 414 } 415 }; 416 417 /** 418 * @hide 419 */ 420 @Override onBind(Intent intent)421 public IBinder onBind(Intent intent) { 422 if(SERVICE_INTERFACE.equals(intent.getAction())) { 423 Log.i(LOG_TAG, "ImsService Bound."); 424 return mImsServiceController; 425 } 426 return null; 427 } 428 getCachedExecutor()429 private Executor getCachedExecutor() { 430 synchronized (mExecutorLock) { 431 if (mExecutor == null) { 432 Executor e = ImsService.this.getExecutor(); 433 mExecutor = (e != null) ? e : Runnable::run; 434 } 435 return mExecutor; 436 } 437 } 438 createMmTelFeatureInternal(int slotId, int subscriptionId)439 private IImsMmTelFeature createMmTelFeatureInternal(int slotId, int subscriptionId) { 440 MmTelFeature f = createMmTelFeatureForSubscription(slotId, subscriptionId); 441 if (f != null) { 442 setupFeature(f, slotId, ImsFeature.FEATURE_MMTEL); 443 f.setDefaultExecutor(getCachedExecutor()); 444 return f.getBinder(); 445 } else { 446 Log.e(LOG_TAG, "createMmTelFeatureInternal: null feature returned."); 447 return null; 448 } 449 } 450 createEmergencyOnlyMmTelFeatureInternal(int slotId)451 private IImsMmTelFeature createEmergencyOnlyMmTelFeatureInternal(int slotId) { 452 MmTelFeature f = createEmergencyOnlyMmTelFeature(slotId); 453 if (f != null) { 454 setupFeature(f, slotId, ImsFeature.FEATURE_MMTEL); 455 f.setDefaultExecutor(getCachedExecutor()); 456 return f.getBinder(); 457 } else { 458 Log.e(LOG_TAG, "createEmergencyOnlyMmTelFeatureInternal: null feature returned."); 459 return null; 460 } 461 } 462 createRcsFeatureInternal(int slotId, int subId)463 private IImsRcsFeature createRcsFeatureInternal(int slotId, int subId) { 464 RcsFeature f = createRcsFeatureForSubscription(slotId, subId); 465 if (f != null) { 466 f.setDefaultExecutor(getCachedExecutor()); 467 setupFeature(f, slotId, ImsFeature.FEATURE_RCS); 468 return f.getBinder(); 469 } else { 470 Log.e(LOG_TAG, "createRcsFeatureInternal: null feature returned."); 471 return null; 472 } 473 } 474 setupFeature(ImsFeature f, int slotId, int featureType)475 private void setupFeature(ImsFeature f, int slotId, int featureType) { 476 f.initialize(this, slotId); 477 addImsFeature(slotId, featureType, f); 478 } 479 addImsFeatureStatusCallback(int slotId, int featureType, IImsFeatureStatusCallback c)480 private void addImsFeatureStatusCallback(int slotId, int featureType, 481 IImsFeatureStatusCallback c) { 482 synchronized (mFeaturesBySlot) { 483 // get ImsFeature associated with the slot/feature 484 SparseArray<ImsFeature> features = mFeaturesBySlot.get(slotId); 485 if (features == null) { 486 Log.w(LOG_TAG, "Can not add ImsFeatureStatusCallback - no features on slot " 487 + slotId); 488 return; 489 } 490 ImsFeature f = features.get(featureType); 491 if (f != null) { 492 f.addImsFeatureStatusCallback(c); 493 } 494 } 495 } 496 removeImsFeatureStatusCallback(int slotId, int featureType, IImsFeatureStatusCallback c)497 private void removeImsFeatureStatusCallback(int slotId, int featureType, 498 IImsFeatureStatusCallback c) { 499 synchronized (mFeaturesBySlot) { 500 // get ImsFeature associated with the slot/feature 501 SparseArray<ImsFeature> features = mFeaturesBySlot.get(slotId); 502 if (features == null) { 503 Log.w(LOG_TAG, "Can not remove ImsFeatureStatusCallback - no features on slot " 504 + slotId); 505 return; 506 } 507 ImsFeature f = features.get(featureType); 508 if (f != null) { 509 f.removeImsFeatureStatusCallback(c); 510 } 511 } 512 } 513 addImsFeature(int slotId, int featureType, ImsFeature f)514 private void addImsFeature(int slotId, int featureType, ImsFeature f) { 515 synchronized (mFeaturesBySlot) { 516 // Get SparseArray for Features, by querying slot Id 517 SparseArray<ImsFeature> features = mFeaturesBySlot.get(slotId); 518 if (features == null) { 519 // Populate new SparseArray of features if it doesn't exist for this slot yet. 520 features = new SparseArray<>(); 521 mFeaturesBySlot.put(slotId, features); 522 } 523 features.put(featureType, f); 524 } 525 } 526 removeImsFeature(int slotId, int featureType)527 private void removeImsFeature(int slotId, int featureType) { 528 // clear cached data 529 notifySubscriptionRemoved(slotId); 530 531 synchronized (mFeaturesBySlot) { 532 // get ImsFeature associated with the slot/feature 533 SparseArray<ImsFeature> features = mFeaturesBySlot.get(slotId); 534 if (features == null) { 535 Log.w(LOG_TAG, "Can not remove ImsFeature. No ImsFeatures exist on slot " 536 + slotId); 537 return; 538 } 539 ImsFeature f = features.get(featureType); 540 if (f == null) { 541 Log.w(LOG_TAG, "Can not remove ImsFeature. No feature with type " 542 + featureType + " exists on slot " + slotId); 543 return; 544 } 545 f.onFeatureRemoved(); 546 features.remove(featureType); 547 } 548 } 549 550 /** 551 * @hide 552 */ 553 @VisibleForTesting getImsFeature(int slotId, int featureType)554 public ImsFeature getImsFeature(int slotId, int featureType) { 555 synchronized (mFeaturesBySlot) { 556 // Get SparseArray for Features, by querying slot Id 557 SparseArray<ImsFeature> features = mFeaturesBySlot.get(slotId); 558 if (features == null) { 559 return null; 560 } 561 return features.get(featureType); 562 } 563 } 564 setImsFeatureCreatedForSlot(int slotId, @ImsFeature.FeatureType int featureType, boolean createdForSlot)565 private void setImsFeatureCreatedForSlot(int slotId, 566 @ImsFeature.FeatureType int featureType, boolean createdForSlot) { 567 synchronized (mCreateImsFeatureWithSlotIdFlagMap) { 568 getImsFeatureCreatedForSlot(slotId).put(featureType, createdForSlot); 569 } 570 } 571 572 /** 573 * @hide 574 */ 575 @VisibleForTesting isImsFeatureCreatedForSlot(int slotId, @ImsFeature.FeatureType int featureType)576 public boolean isImsFeatureCreatedForSlot(int slotId, 577 @ImsFeature.FeatureType int featureType) { 578 synchronized (mCreateImsFeatureWithSlotIdFlagMap) { 579 return getImsFeatureCreatedForSlot(slotId).get(featureType); 580 } 581 } 582 getImsFeatureCreatedForSlot(int slotId)583 private SparseBooleanArray getImsFeatureCreatedForSlot(int slotId) { 584 SparseBooleanArray createFlag = mCreateImsFeatureWithSlotIdFlagMap.get(slotId); 585 if (createFlag == null) { 586 createFlag = new SparseBooleanArray(); 587 mCreateImsFeatureWithSlotIdFlagMap.put(slotId, createFlag); 588 } 589 return createFlag; 590 } 591 releaseResource()592 private void releaseResource() { 593 Log.w(LOG_TAG, "cleaning up features"); 594 synchronized (mFeaturesBySlot) { 595 SparseArray<ImsFeature> features; 596 ImsFeature imsFeature; 597 598 for (int i = 0; i < mFeaturesBySlot.size(); i++) { 599 features = mFeaturesBySlot.valueAt(i); 600 if (features == null) { 601 continue; 602 } 603 604 for (int index = 0; index < features.size(); index++) { 605 imsFeature = features.valueAt(index); 606 if (imsFeature != null) { 607 imsFeature.onFeatureRemoved(); 608 } 609 } 610 features.clear(); 611 } 612 mFeaturesBySlot.clear(); 613 } 614 } 615 616 // Call the methods with a clean calling identity on the executor and wait indefinitely for 617 // the future to return. executeMethodAsync(Runnable r, String errorLogName)618 private void executeMethodAsync(Runnable r, String errorLogName) { 619 try { 620 CompletableFuture.runAsync( 621 () -> TelephonyUtils.runWithCleanCallingIdentity(r), 622 getCachedExecutor()).join(); 623 } catch (CancellationException | CompletionException e) { 624 Log.w(LOG_TAG, "ImsService Binder - " + errorLogName + " exception: " 625 + e.getMessage()); 626 } 627 } 628 executeMethodAsyncForResult(Supplier<T> r, String errorLogName)629 private <T> T executeMethodAsyncForResult(Supplier<T> r, String errorLogName) { 630 CompletableFuture<T> future = CompletableFuture.supplyAsync( 631 () -> TelephonyUtils.runWithCleanCallingIdentity(r), getCachedExecutor()); 632 try { 633 return future.get(); 634 } catch (ExecutionException | InterruptedException e) { 635 Log.w(LOG_TAG, "ImsService Binder - " + errorLogName + " exception: " 636 + e.getMessage()); 637 return null; 638 } 639 } 640 resetImsInternal(int slotId, int subId)641 private void resetImsInternal(int slotId, int subId) { 642 try { 643 resetIms(slotId); 644 } catch (UnsupportedOperationException e) { 645 disableImsForSubscription(slotId, subId); 646 } 647 } 648 649 /** 650 * When called, provide the {@link ImsFeatureConfiguration} that this {@link ImsService} 651 * currently supports. This will trigger the framework to set up the {@link ImsFeature}s that 652 * correspond to the {@link ImsFeature}s configured here. 653 * 654 * Use {@link #onUpdateSupportedImsFeatures(ImsFeatureConfiguration)} to change the supported 655 * {@link ImsFeature}s. 656 * 657 * @return an {@link ImsFeatureConfiguration} containing Features this ImsService supports. 658 */ querySupportedImsFeatures()659 public ImsFeatureConfiguration querySupportedImsFeatures() { 660 // Return empty for base implementation 661 return new ImsFeatureConfiguration(); 662 } 663 664 /** 665 * Updates the framework with a new {@link ImsFeatureConfiguration} containing the updated 666 * features, that this {@link ImsService} supports. This may trigger the framework to add/remove 667 * new ImsFeatures, depending on the configuration. 668 */ onUpdateSupportedImsFeatures(ImsFeatureConfiguration c)669 public final void onUpdateSupportedImsFeatures(ImsFeatureConfiguration c) 670 throws RemoteException { 671 IImsServiceControllerListener l; 672 synchronized (mListenerLock) { 673 if (mListener == null) { 674 throw new IllegalStateException("Framework is not ready"); 675 } 676 l = mListener; 677 } 678 l.onUpdateSupportedImsFeatures(c); 679 } 680 681 /** 682 * The optional capabilities that this ImsService supports. 683 * <p> 684 * This should be a static configuration and should not change at runtime. 685 * @return The optional static capabilities of this ImsService implementation. 686 */ 687 // ImsService follows a different convention, since it is a stub class. The on* methods are 688 // final and call back into the framework with a state update. 689 @SuppressLint("OnNameExpected") getImsServiceCapabilities()690 public @ImsServiceCapability long getImsServiceCapabilities() { 691 // Stub implementation to be implemented by ImsService. 692 return 0L; 693 } 694 695 /** 696 * The ImsService has been bound and is ready for ImsFeature creation based on the Features that 697 * the ImsService has registered for with the framework, either in the manifest or via 698 * {@link #querySupportedImsFeatures()}. 699 * 700 * The ImsService should use this signal instead of onCreate/onBind or similar to perform 701 * feature initialization because the framework may bind to this service multiple times to 702 * query the ImsService's {@link ImsFeatureConfiguration} via 703 * {@link #querySupportedImsFeatures()}before creating features. 704 */ readyForFeatureCreation()705 public void readyForFeatureCreation() { 706 } 707 708 /** 709 * The framework has enabled IMS for the subscription specified, the ImsService should register 710 * for IMS and perform all appropriate initialization to bring up all ImsFeatures. 711 * 712 * @param slotId The slot ID that IMS will be enabled for. 713 * @param subscriptionId The subscription ID that IMS will be enabled for. 714 */ enableImsForSubscription(int slotId, int subscriptionId)715 public void enableImsForSubscription(int slotId, int subscriptionId) { 716 enableIms(slotId); 717 } 718 719 /** 720 * The framework has disabled IMS for the subscription specified. The ImsService must deregister 721 * for IMS and set capability status to false for all ImsFeatures. 722 * @param slotId The slot ID that IMS will be disabled for. 723 * @param subscriptionId The subscription ID that IMS will be disabled for. 724 */ disableImsForSubscription(int slotId, int subscriptionId)725 public void disableImsForSubscription(int slotId, int subscriptionId) { 726 disableIms(slotId); 727 } 728 729 /** 730 * The subscription has removed. The ImsService should notify ImsRegistrationImplBase and 731 * ImsConfigImplBase the SIM state was changed. 732 * @param slotId The slot ID which has removed. 733 */ notifySubscriptionRemoved(int slotId)734 private void notifySubscriptionRemoved(int slotId) { 735 ImsRegistrationImplBase registrationImplBase = 736 getRegistration(slotId); 737 if (registrationImplBase != null) { 738 registrationImplBase.clearRegistrationCache(); 739 } 740 741 ImsConfigImplBase imsConfigImplBase = getConfig(slotId); 742 if (imsConfigImplBase != null) { 743 imsConfigImplBase.clearConfigurationCache(); 744 } 745 } 746 747 /** 748 * The framework has enabled IMS for the slot specified, the ImsService should register for IMS 749 * and perform all appropriate initialization to bring up all ImsFeatures. 750 * @deprecated Use {@link #enableImsForSubscription} instead. 751 */ 752 @Deprecated enableIms(int slotId)753 public void enableIms(int slotId) { 754 } 755 756 /** 757 * The framework has disabled IMS for the slot specified. The ImsService must deregister for IMS 758 * and set capability status to false for all ImsFeatures. 759 * @deprecated Use {@link #disableImsForSubscription} instead. 760 */ 761 @Deprecated disableIms(int slotId)762 public void disableIms(int slotId) { 763 } 764 765 /** 766 * The framework has reset IMS for the slot specified. The ImsService must deregister 767 * and release all resources for IMS. After resetIms is called, either 768 * {@link #enableImsForSubscription(int, int)} or {@link #disableImsForSubscription(int, int)} 769 * will be called for the same slotId. 770 * 771 * @param slotId The slot ID that IMS will be reset for. 772 * @hide 773 */ resetIms(int slotId)774 public void resetIms(int slotId) { 775 throw new UnsupportedOperationException(); 776 } 777 778 /** 779 * When called, the framework is requesting that a new {@link MmTelFeature} is created for the 780 * specified subscription. 781 * 782 * @param subscriptionId The subscription ID that the MMTEL Feature is being created for. 783 * @return The newly created {@link MmTelFeature} associated with the subscription or null if 784 * the feature is not supported. 785 */ createMmTelFeatureForSubscription(int slotId, int subscriptionId)786 public @Nullable MmTelFeature createMmTelFeatureForSubscription(int slotId, 787 int subscriptionId) { 788 setImsFeatureCreatedForSlot(slotId, ImsFeature.FEATURE_MMTEL, true); 789 return createMmTelFeature(slotId); 790 } 791 792 /** 793 * When called, the framework is requesting that a new {@link RcsFeature} is created for the 794 * specified subscription. 795 * 796 * @param subscriptionId The subscription ID that the RCS Feature is being created for. 797 * @return The newly created {@link RcsFeature} associated with the subscription or null if the 798 * feature is not supported. 799 */ createRcsFeatureForSubscription(int slotId, int subscriptionId)800 public @Nullable RcsFeature createRcsFeatureForSubscription(int slotId, int subscriptionId) { 801 setImsFeatureCreatedForSlot(slotId, ImsFeature.FEATURE_RCS, true); 802 return createRcsFeature(slotId); 803 } 804 805 /** 806 * When called, the framework is requesting that a new emergency-only {@link MmTelFeature} is 807 * created for the specified slot. For emergency calls, there is no known Subscription Id. 808 * 809 * @param slotId The slot ID that the MMTEL Feature is being created for. 810 * @return An MmTelFeature instance to be used for the slot ID when there is not 811 * subscription inserted. Only requested when there is no subscription active on 812 * the specified slot. 813 */ createEmergencyOnlyMmTelFeature(int slotId)814 public @Nullable MmTelFeature createEmergencyOnlyMmTelFeature(int slotId) { 815 setImsFeatureCreatedForSlot(slotId, ImsFeature.FEATURE_MMTEL, true); 816 return createMmTelFeature(slotId); 817 } 818 819 /** 820 * When called, the framework is requesting that a new {@link MmTelFeature} is created for the 821 * specified slot. 822 * @deprecated Use {@link #createMmTelFeatureForSubscription} instead 823 * 824 * @param slotId The slot ID that the MMTEL Feature is being created for. 825 * @return The newly created {@link MmTelFeature} associated with the slot or null if the 826 * feature is not supported. 827 */ 828 @Deprecated createMmTelFeature(int slotId)829 public MmTelFeature createMmTelFeature(int slotId) { 830 return null; 831 } 832 833 /** 834 * When called, the framework is requesting that a new {@link RcsFeature} is created for the 835 * specified slot. 836 * @deprecated Use {@link #createRcsFeatureForSubscription} instead 837 * 838 * @param slotId The slot ID that the RCS Feature is being created for. 839 * @return The newly created {@link RcsFeature} associated with the slot or null if the feature 840 * is not supported. 841 */ 842 @Deprecated createRcsFeature(int slotId)843 public RcsFeature createRcsFeature(int slotId) { 844 return null; 845 } 846 847 /** 848 * Return the {@link ImsConfigImplBase} implementation associated with the provided 849 * subscription. This will be used by the platform to get/set specific IMS related 850 * configurations. 851 * 852 * @param subscriptionId The subscription ID that the IMS configuration is associated with. 853 * @return ImsConfig implementation that is associated with the specified subscription. 854 */ getConfigForSubscription(int slotId, int subscriptionId)855 public @NonNull ImsConfigImplBase getConfigForSubscription(int slotId, int subscriptionId) { 856 return getConfig(slotId); 857 } 858 859 /** 860 * Return the {@link ImsRegistrationImplBase} implementation associated with the provided 861 * subscription. 862 * 863 * @param subscriptionId The subscription ID that is associated with the IMS Registration. 864 * @return the ImsRegistration implementation associated with the subscription. 865 */ getRegistrationForSubscription(int slotId, int subscriptionId)866 public @NonNull ImsRegistrationImplBase getRegistrationForSubscription(int slotId, 867 int subscriptionId) { 868 return getRegistration(slotId); 869 } 870 871 /** 872 * Return the {@link ImsConfigImplBase} implementation associated with the provided slot. This 873 * will be used by the platform to get/set specific IMS related configurations. 874 * @deprecated use {@link #getConfigForSubscription} instead. 875 * 876 * @param slotId The slot that the IMS configuration is associated with. 877 * @return ImsConfig implementation that is associated with the specified slot. 878 */ 879 @Deprecated getConfig(int slotId)880 public ImsConfigImplBase getConfig(int slotId) { 881 return new ImsConfigImplBase(); 882 } 883 884 /** 885 * Return the {@link ImsRegistrationImplBase} implementation associated with the provided slot. 886 * @deprecated use {@link #getRegistrationForSubscription} instead. 887 * 888 * @param slotId The slot that is associated with the IMS Registration. 889 * @return the ImsRegistration implementation associated with the slot. 890 */ 891 @Deprecated getRegistration(int slotId)892 public ImsRegistrationImplBase getRegistration(int slotId) { 893 return new ImsRegistrationImplBase(); 894 } 895 896 /** 897 * Return the {@link SipTransportImplBase} implementation associated with the provided slot. 898 * <p> 899 * This is an optional interface used for devices that must support IMS single registration and 900 * proxy SIP traffic to remote IMS applications. If this is not supported for this IMS service, 901 * this method should return {@code null}. If this feature is supported, then this method must 902 * never be {@code null} and the optional ImsService capability flag 903 * {@link #CAPABILITY_SIP_DELEGATE_CREATION} must be set in 904 * {@link #getImsServiceCapabilities()}. Otherwise the framework will assume this feature is not 905 * supported for this ImsService. 906 * @param slotId The slot that is associated with the SipTransport implementation. 907 * @return the SipTransport implementation for the specified slot. 908 */ 909 // ImsService follows a different convention, since it is a stub class. The on* methods are 910 // final and call back into the framework with a state update. 911 @SuppressLint("OnNameExpected") getSipTransport(int slotId)912 public @Nullable SipTransportImplBase getSipTransport(int slotId) { 913 // Stub implementation for ImsServices that do not support SipTransport. 914 return null; 915 } 916 sanitizeCapabilities(@msServiceCapability long caps)917 private static long sanitizeCapabilities(@ImsServiceCapability long caps) { 918 long filter = 0xFFFFFFFFFFFFFFFFL; 919 // pad the "allowed" set with zeros 920 filter <<= CAPABILITY_MAX_INDEX + 1; 921 // remove values above the allowed set. 922 caps &= ~filter; 923 // CAPABILITY_EMERGENCY_OVER_MMTEL should also not be set here, will be set by telephony 924 // internally. 925 caps &= ~CAPABILITY_EMERGENCY_OVER_MMTEL; 926 return caps; 927 } 928 929 /** 930 * @return A string representation of the ImsService capabilities for logging. 931 * @hide 932 */ getCapabilitiesString(@msServiceCapability long caps)933 public static String getCapabilitiesString(@ImsServiceCapability long caps) { 934 StringBuffer result = new StringBuffer(); 935 result.append("capabilities={ "); 936 // filter incrementally fills 0s from left to right. This is used to keep filtering out 937 // more bits in the long until the remaining leftmost bits are all zero. 938 long filter = 0xFFFFFFFFFFFFFFFFL; 939 // position of iterator to potentially print capability. 940 long i = 0; 941 while ((caps & filter) != 0 && i <= 63) { 942 long bitToCheck = (1L << i); 943 if ((caps & bitToCheck) != 0) { 944 result.append(CAPABILITIES_LOG_MAP.getOrDefault(bitToCheck, bitToCheck + "?")); 945 result.append(" "); 946 } 947 // shift left by one and fill in another 1 on the leftmost bit. 948 filter <<= 1; 949 i++; 950 } 951 result.append("}"); 952 return result.toString(); 953 } 954 955 /** 956 * The ImsService will now be able to define an Executor that the ImsService can be used to 957 * execute the methods. By default all ImsService level method calls will use this Executor. 958 * The ImsService has set the default executor as Runnable::run, 959 * Should be override or default executor will be used. 960 * @return an Executor used to execute methods called remotely by the framework. 961 */ getExecutor()962 public @NonNull Executor getExecutor() { 963 return Runnable::run; 964 } 965 } 966