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 static android.telephony.SubscriptionManager.PLACEHOLDER_SUBSCRIPTION_ID_BASE; 20 21 import android.content.ComponentName; 22 import android.content.Context; 23 import android.content.Intent; 24 import android.content.ServiceConnection; 25 import android.content.pm.ChangedPackages; 26 import android.content.pm.PackageManager; 27 import android.os.Handler; 28 import android.os.HandlerThread; 29 import android.os.IBinder; 30 import android.os.IInterface; 31 import android.os.RemoteException; 32 import android.os.UserHandle; 33 import android.permission.LegacyPermissionManager; 34 import android.telephony.AnomalyReporter; 35 import android.telephony.SubscriptionManager; 36 import android.telephony.ims.ImsService; 37 import android.telephony.ims.aidl.IImsConfig; 38 import android.telephony.ims.aidl.IImsRegistration; 39 import android.telephony.ims.aidl.IImsServiceController; 40 import android.telephony.ims.aidl.ISipTransport; 41 import android.telephony.ims.feature.ImsFeature; 42 import android.telephony.ims.stub.ImsFeatureConfiguration; 43 import android.util.LocalLog; 44 import android.util.Log; 45 import android.util.SparseIntArray; 46 47 import com.android.ims.ImsFeatureBinderRepository; 48 import com.android.ims.ImsFeatureContainer; 49 import com.android.ims.internal.IImsFeatureStatusCallback; 50 import com.android.internal.annotations.VisibleForTesting; 51 import com.android.internal.telephony.ExponentialBackoff; 52 import com.android.internal.telephony.flags.FeatureFlags; 53 import com.android.internal.telephony.util.TelephonyUtils; 54 55 import java.io.PrintWriter; 56 import java.util.HashSet; 57 import java.util.List; 58 import java.util.Set; 59 import java.util.UUID; 60 import java.util.concurrent.CountDownLatch; 61 import java.util.stream.Collectors; 62 63 /** 64 * Manages the Binding lifecycle of one ImsService as well as the relevant ImsFeatures that the 65 * ImsService will support. 66 * 67 * When the ImsService is first bound, {@link ImsService#createMmTelFeature(int)} and 68 * {@link ImsService#createRcsFeature(int)} will be called 69 * on each feature that the service supports. For each ImsFeature that is created, 70 * {@link ImsServiceControllerCallbacks#imsServiceFeatureCreated} will be called to notify the 71 * listener that the ImsService now supports that feature. 72 * 73 * When {@link #changeImsServiceFeatures} is called with a set of features that is different from 74 * the original set, create*Feature and {@link IImsServiceController#removeImsFeature} will be 75 * called for each feature that is created/removed. 76 */ 77 public class ImsServiceController { 78 private final UUID mAnomalyUUID = UUID.fromString("e93b05e4-6d0a-4755-a6da-a2d2dbfb10d6"); 79 private int mLastSequenceNumber = 0; 80 private ChangedPackages mChangedPackages; 81 private PackageManager mPackageManager; 82 class ImsServiceConnection implements ServiceConnection { 83 // Track the status of whether or not the Service has died in case we need to permanently 84 // unbind (see onNullBinding below). 85 private boolean mIsServiceConnectionDead = false; 86 87 @Override onServiceConnected(ComponentName name, IBinder service)88 public void onServiceConnected(ComponentName name, IBinder service) { 89 if (mHandler.getLooper().isCurrentThread()) { 90 onServiceConnectedInternal(name, service); 91 } else { 92 mHandler.post(() -> onServiceConnectedInternal(name, service)); 93 } 94 } 95 96 @Override onServiceDisconnected(ComponentName name)97 public void onServiceDisconnected(ComponentName name) { 98 if (mHandler.getLooper().isCurrentThread()) { 99 onServiceDisconnectedInternal(name); 100 } else { 101 mHandler.post(() -> onServiceDisconnectedInternal(name)); 102 } 103 } 104 105 @Override onBindingDied(ComponentName name)106 public void onBindingDied(ComponentName name) { 107 if (mHandler.getLooper().isCurrentThread()) { 108 onBindingDiedInternal(name); 109 } else { 110 mHandler.post(() -> onBindingDiedInternal(name)); 111 } 112 } 113 114 @Override onNullBinding(ComponentName name)115 public void onNullBinding(ComponentName name) { 116 if (mHandler.getLooper().isCurrentThread()) { 117 onNullBindingInternal(name); 118 } else { 119 mHandler.post(() -> onNullBindingInternal(name)); 120 } 121 } 122 onServiceConnectedInternal(ComponentName name, IBinder service)123 private void onServiceConnectedInternal(ComponentName name, IBinder service) { 124 synchronized (mLock) { 125 mBackoff.stop(); 126 mIsBound = true; 127 mIsBinding = false; 128 try { 129 mLocalLog.log("onServiceConnectedInternal"); 130 Log.d(LOG_TAG, "ImsService(" + name 131 + "): onServiceConnectedInternal with binder: " + service); 132 setServiceController(service); 133 notifyImsServiceReady(); 134 retrieveStaticImsServiceCapabilities(); 135 // create all associated features in the ImsService 136 for (ImsFeatureConfiguration.FeatureSlotPair i : mImsFeatures) { 137 long caps = modifyCapabiltiesForSlot(mImsFeatures, i.slotId, 138 mServiceCapabilities); 139 addImsServiceFeature(i, caps, mSlotIdToSubIdMap.get(i.slotId)); 140 } 141 } catch (RemoteException e) { 142 mIsBound = false; 143 mIsBinding = false; 144 // RemoteException means that the process holding the binder died or something 145 // unexpected happened... try a full rebind. 146 cleanupConnection(); 147 unbindService(); 148 startDelayedRebindToService(); 149 mLocalLog.log("onConnected exception=" + e.getMessage() + ", retry in " 150 + mBackoff.getCurrentDelay() + " mS"); 151 Log.e(LOG_TAG, "ImsService(" + name + ") RemoteException:" 152 + e.getMessage()); 153 } 154 } 155 } 156 onServiceDisconnectedInternal(ComponentName name)157 private void onServiceDisconnectedInternal(ComponentName name) { 158 synchronized (mLock) { 159 mIsBinding = false; 160 cleanupConnection(); 161 } 162 mLocalLog.log("onServiceDisconnectedInternal"); 163 Log.w(LOG_TAG, "ImsService(" + name + "): onServiceDisconnectedInternal. Waiting..."); 164 // Service disconnected, but we are still technically bound. Waiting for reconnect. 165 checkAndReportAnomaly(name); 166 } 167 onBindingDiedInternal(ComponentName name)168 private void onBindingDiedInternal(ComponentName name) { 169 mIsServiceConnectionDead = true; 170 synchronized (mLock) { 171 mIsBinding = false; 172 mIsBound = false; 173 // according to the docs, we should fully unbind before rebinding again. 174 cleanupConnection(); 175 unbindService(); 176 startDelayedRebindToService(); 177 } 178 Log.w(LOG_TAG, "ImsService(" + name + "): onBindingDiedInternal. Starting rebind..."); 179 mLocalLog.log("onBindingDiedInternal, retrying in " 180 + mBackoff.getCurrentDelay() + " mS"); 181 } 182 onNullBindingInternal(ComponentName name)183 private void onNullBindingInternal(ComponentName name) { 184 Log.w(LOG_TAG, "ImsService(" + name + "): onNullBindingInternal. Is service dead = " 185 + mIsServiceConnectionDead); 186 mLocalLog.log("onNullBindingInternal, is service dead = " + mIsServiceConnectionDead); 187 // onNullBinding will happen after onBindingDied. In this case, we should not 188 // permanently unbind and instead let the automatic rebind occur. 189 if (mIsServiceConnectionDead) return; 190 synchronized (mLock) { 191 mIsBinding = false; 192 // Service connection exists, so we are bound but the binder is null. Wait for 193 // ImsResolver to trigger the unbind here. 194 mIsBound = true; 195 cleanupConnection(); 196 } 197 if (mCallbacks != null) { 198 // Will trigger an unbind. 199 mCallbacks.imsServiceBindPermanentError(getComponentName()); 200 } 201 } 202 203 // Does not clear feature configuration, just cleans up the active callbacks and 204 // invalidates remote FeatureConnections. 205 // This should only be called when locked cleanupConnection()206 private void cleanupConnection() { 207 cleanupAllFeatures(); 208 setServiceController(null); 209 } 210 } 211 212 /** 213 * Defines callbacks that are used by the ImsServiceController to notify when an ImsService 214 * has created or removed a new feature as well as the associated ImsServiceController. 215 */ 216 public interface ImsServiceControllerCallbacks { 217 /** 218 * Called by ImsServiceController when a new MMTEL or RCS feature has been created. 219 */ imsServiceFeatureCreated(int slotId, int feature, ImsServiceController controller)220 void imsServiceFeatureCreated(int slotId, int feature, ImsServiceController controller); 221 /** 222 * Called by ImsServiceController when a new MMTEL or RCS feature has been removed. 223 */ imsServiceFeatureRemoved(int slotId, int feature, ImsServiceController controller)224 void imsServiceFeatureRemoved(int slotId, int feature, ImsServiceController controller); 225 226 /** 227 * Called by the ImsServiceController when the ImsService has notified the framework that 228 * its features have changed. 229 */ imsServiceFeaturesChanged(ImsFeatureConfiguration config, ImsServiceController controller)230 void imsServiceFeaturesChanged(ImsFeatureConfiguration config, 231 ImsServiceController controller); 232 233 /** 234 * Called by the ImsServiceController when there has been an error binding that is 235 * not recoverable, such as the ImsService returning a null binder. 236 */ imsServiceBindPermanentError(ComponentName name)237 void imsServiceBindPermanentError(ComponentName name); 238 } 239 240 /** 241 * Returns the currently defined rebind retry timeout. Used for testing. 242 */ 243 @VisibleForTesting 244 public interface RebindRetry { 245 /** 246 * Returns a long in ms indicating how long the ImsServiceController should wait before 247 * rebinding for the first time. 248 */ getStartDelay()249 long getStartDelay(); 250 251 /** 252 * Returns a long in ms indicating the maximum time the ImsServiceController should wait 253 * before rebinding. 254 */ getMaximumDelay()255 long getMaximumDelay(); 256 } 257 258 private static final String LOG_TAG = "ImsServiceController"; 259 private static final int REBIND_START_DELAY_MS = 2 * 1000; // 2 seconds 260 private static final int REBIND_MAXIMUM_DELAY_MS = 60 * 1000; // 1 minute 261 private static final long CHANGE_PERMISSION_TIMEOUT_MS = 15 * 1000; // 15 seconds 262 // Enforce ImsService has both MMTEL and RCS supported in order to enable SIP transport API. 263 // Enable ImsServiceControllerTest and SipDelegateManagerTest cases if this is re-enabled. 264 private static final boolean ENFORCE_SINGLE_SERVICE_FOR_SIP_TRANSPORT = false; 265 private final ComponentName mComponentName; 266 private final HandlerThread mHandlerThread = new HandlerThread("ImsServiceControllerHandler"); 267 private final Handler mHandler; 268 private final LegacyPermissionManager mPermissionManager; 269 private final FeatureFlags mFeatureFlags; 270 private ImsFeatureBinderRepository mRepo; 271 private ImsServiceControllerCallbacks mCallbacks; 272 private ExponentialBackoff mBackoff; 273 274 private boolean mIsBound = false; 275 private boolean mIsBinding = false; 276 // Set of a pair of slotId->feature 277 private Set<ImsFeatureConfiguration.FeatureSlotPair> mImsFeatures; 278 private SparseIntArray mSlotIdToSubIdMap; 279 private IImsServiceController mIImsServiceController; 280 private final ImsEnablementTracker mImsEnablementTracker; 281 // The Capabilities bitmask of the connected ImsService (see ImsService#ImsServiceCapability). 282 private long mServiceCapabilities; 283 private ImsServiceConnection mImsServiceConnection; 284 // Only added or removed, never accessed on purpose. 285 private Set<ImsFeatureStatusCallback> mFeatureStatusCallbacks = new HashSet<>(); 286 private final LocalLog mLocalLog = new LocalLog(8); 287 288 protected final Object mLock = new Object(); 289 protected final Context mContext; 290 291 private ImsService.Listener mFeatureChangedListener = new ImsService.Listener() { 292 @Override 293 public void onUpdateSupportedImsFeatures(ImsFeatureConfiguration c) { 294 if (mCallbacks == null) { 295 return; 296 } 297 mLocalLog.log("onUpdateSupportedImsFeatures to " + c.getServiceFeatures()); 298 mCallbacks.imsServiceFeaturesChanged(c, ImsServiceController.this); 299 } 300 }; 301 302 /** 303 * Container class for the IImsFeatureStatusCallback callback implementation. This class is 304 * never used directly, but we need to keep track of the IImsFeatureStatusCallback 305 * implementations explicitly. 306 */ 307 private class ImsFeatureStatusCallback { 308 private int mSlotId; 309 private int mFeatureType; 310 311 private final IImsFeatureStatusCallback mCallback = new IImsFeatureStatusCallback.Stub() { 312 313 @Override 314 public void notifyImsFeatureStatus(int featureStatus) throws RemoteException { 315 Log.i(LOG_TAG, "notifyImsFeatureStatus: slot=" + mSlotId + ", feature=" 316 + ImsFeature.FEATURE_LOG_MAP.get(mFeatureType) + ", status=" 317 + ImsFeature.STATE_LOG_MAP.get(featureStatus)); 318 mRepo.notifyFeatureStateChanged(mSlotId, mFeatureType, featureStatus); 319 } 320 }; 321 ImsFeatureStatusCallback(int slotId, int featureType)322 ImsFeatureStatusCallback(int slotId, int featureType) { 323 mSlotId = slotId; 324 mFeatureType = featureType; 325 } 326 getCallback()327 public IImsFeatureStatusCallback getCallback() { 328 return mCallback; 329 } 330 } 331 332 // Retry the bind to the ImsService that has died after mRebindRetry timeout. 333 private Runnable mRestartImsServiceRunnable = new Runnable() { 334 @Override 335 public void run() { 336 synchronized (mLock) { 337 if (mIsBound) { 338 return; 339 } 340 bind(mImsFeatures, mSlotIdToSubIdMap); 341 } 342 } 343 }; 344 345 private RebindRetry mRebindRetry = new RebindRetry() { 346 @Override 347 public long getStartDelay() { 348 return REBIND_START_DELAY_MS; 349 } 350 351 @Override 352 public long getMaximumDelay() { 353 return REBIND_MAXIMUM_DELAY_MS; 354 } 355 }; 356 ImsServiceController(Context context, ComponentName componentName, ImsServiceControllerCallbacks callbacks, ImsFeatureBinderRepository repo, FeatureFlags featureFlags)357 public ImsServiceController(Context context, ComponentName componentName, 358 ImsServiceControllerCallbacks callbacks, ImsFeatureBinderRepository repo, 359 FeatureFlags featureFlags) { 360 mContext = context; 361 mComponentName = componentName; 362 mCallbacks = callbacks; 363 mHandlerThread.start(); 364 mHandler = new Handler(mHandlerThread.getLooper()); 365 mBackoff = new ExponentialBackoff( 366 mRebindRetry.getStartDelay(), 367 mRebindRetry.getMaximumDelay(), 368 2, /* multiplier */ 369 mHandler, 370 mRestartImsServiceRunnable); 371 mPermissionManager = (LegacyPermissionManager) mContext.getSystemService( 372 Context.LEGACY_PERMISSION_SERVICE); 373 mRepo = repo; 374 mImsEnablementTracker = new ImsEnablementTracker(mHandlerThread.getLooper(), componentName); 375 mFeatureFlags = featureFlags; 376 mPackageManager = mContext.getPackageManager(); 377 if (mPackageManager != null) { 378 mChangedPackages = mPackageManager.getChangedPackages(mLastSequenceNumber); 379 if (mChangedPackages != null) { 380 mLastSequenceNumber = mChangedPackages.getSequenceNumber(); 381 } 382 } 383 } 384 385 @VisibleForTesting 386 // Creating a new HandlerThread and background handler for each test causes a segfault, so for 387 // testing, use a handler supplied by the testing system. ImsServiceController(Context context, ComponentName componentName, ImsServiceControllerCallbacks callbacks, Handler handler, RebindRetry rebindRetry, ImsFeatureBinderRepository repo, FeatureFlags featureFlags)388 public ImsServiceController(Context context, ComponentName componentName, 389 ImsServiceControllerCallbacks callbacks, Handler handler, RebindRetry rebindRetry, 390 ImsFeatureBinderRepository repo, FeatureFlags featureFlags) { 391 mContext = context; 392 mComponentName = componentName; 393 mCallbacks = callbacks; 394 mHandler = handler; 395 mBackoff = new ExponentialBackoff( 396 rebindRetry.getStartDelay(), 397 rebindRetry.getMaximumDelay(), 398 2, /* multiplier */ 399 handler, 400 mRestartImsServiceRunnable); 401 mPermissionManager = null; 402 mRepo = repo; 403 mFeatureFlags = featureFlags; 404 mImsEnablementTracker = new ImsEnablementTracker(handler.getLooper(), componentName); 405 } 406 407 /** 408 * Sends request to bind to ImsService designated by the {@link ComponentName} with the feature 409 * set imsFeatureSet. 410 * 411 * @param imsFeatureSet a Set of Pairs that designate the slotId->featureId that need to be 412 * created once the service is bound. 413 * @return {@link true} if the service is in the process of being bound, {@link false} if it 414 * has failed. 415 */ bind(Set<ImsFeatureConfiguration.FeatureSlotPair> imsFeatureSet, SparseIntArray slotIdToSubIdMap)416 public boolean bind(Set<ImsFeatureConfiguration.FeatureSlotPair> imsFeatureSet, 417 SparseIntArray slotIdToSubIdMap) { 418 synchronized (mLock) { 419 if (!mIsBound && !mIsBinding) { 420 mIsBinding = true; 421 sanitizeFeatureConfig(imsFeatureSet); 422 mImsFeatures = imsFeatureSet; 423 mSlotIdToSubIdMap = slotIdToSubIdMap; 424 // Set the number of slots that support the feature 425 mImsEnablementTracker.setNumOfSlots(mSlotIdToSubIdMap.size()); 426 grantPermissionsToService(); 427 Intent imsServiceIntent = new Intent(getServiceInterface()).setComponent( 428 mComponentName); 429 mImsServiceConnection = new ImsServiceConnection(); 430 int serviceFlags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE 431 | Context.BIND_IMPORTANT; 432 mLocalLog.log("binding " + imsFeatureSet); 433 Log.i(LOG_TAG, "Binding ImsService:" + mComponentName); 434 try { 435 boolean bindSucceeded = mContext.bindService(imsServiceIntent, 436 mImsServiceConnection, serviceFlags); 437 if (!bindSucceeded) { 438 mLocalLog.log(" binding failed, retrying in " 439 + mBackoff.getCurrentDelay() + " mS"); 440 mIsBinding = false; 441 mBackoff.notifyFailed(); 442 } 443 return bindSucceeded; 444 } catch (Exception e) { 445 mBackoff.notifyFailed(); 446 mLocalLog.log(" binding exception=" + e.getMessage() + ", retrying in " 447 + mBackoff.getCurrentDelay() + " mS"); 448 Log.e(LOG_TAG, "Error binding (" + mComponentName + ") with exception: " 449 + e.getMessage() + ", rebinding in " + mBackoff.getCurrentDelay() 450 + " ms"); 451 return false; 452 } 453 } else { 454 return false; 455 } 456 } 457 } 458 459 /** 460 * Ensure the feature includes MMTEL when it supports EMERGENCY_MMTEL, if not, remove. 461 */ sanitizeFeatureConfig(Set<ImsFeatureConfiguration.FeatureSlotPair> features)462 private void sanitizeFeatureConfig(Set<ImsFeatureConfiguration.FeatureSlotPair> features) { 463 Set<ImsFeatureConfiguration.FeatureSlotPair> emergencyMmtelFeatures = features.stream() 464 .filter(feature -> feature.featureType == ImsFeature.FEATURE_EMERGENCY_MMTEL) 465 .collect(Collectors.toSet()); 466 for (ImsFeatureConfiguration.FeatureSlotPair feature : emergencyMmtelFeatures) { 467 if (!features.contains(new ImsFeatureConfiguration.FeatureSlotPair(feature.slotId, 468 ImsFeature.FEATURE_MMTEL))) { 469 features.remove(feature); 470 } 471 } 472 } 473 474 /** 475 * Calls {@link IImsServiceController#removeImsFeature} on all features that the 476 * ImsService supports and then unbinds the service. 477 */ unbind()478 public void unbind() throws RemoteException { 479 synchronized (mLock) { 480 mBackoff.stop(); 481 // Clean up all features 482 changeImsServiceFeatures(new HashSet<>(), mSlotIdToSubIdMap); 483 mIsBound = false; 484 mIsBinding = false; 485 setServiceController(null); 486 unbindService(); 487 } 488 } 489 490 /** 491 * For every feature that is added, the service calls the associated create. For every 492 * ImsFeature that is removed, {@link IImsServiceController#removeImsFeature} is called. 493 */ changeImsServiceFeatures( Set<ImsFeatureConfiguration.FeatureSlotPair> newImsFeatures, SparseIntArray slotIdToSubIdMap)494 public void changeImsServiceFeatures( 495 Set<ImsFeatureConfiguration.FeatureSlotPair> newImsFeatures, 496 SparseIntArray slotIdToSubIdMap) throws RemoteException { 497 sanitizeFeatureConfig(newImsFeatures); 498 synchronized (mLock) { 499 HashSet<Integer> slotIDs = newImsFeatures.stream().map(e -> e.slotId).collect( 500 Collectors.toCollection(HashSet::new)); 501 502 // Set the number of slot for IMS enable for each slot 503 if (mFeatureFlags.setNumberOfSimForImsEnable()) { 504 mImsEnablementTracker.setNumOfSlots(slotIDs.size()); 505 } 506 507 // detect which subIds have changed on a per-slot basis 508 SparseIntArray changedSubIds = new SparseIntArray(slotIDs.size()); 509 for (Integer slotID : slotIDs) { 510 int oldSubId = mSlotIdToSubIdMap.get(slotID, PLACEHOLDER_SUBSCRIPTION_ID_BASE); 511 int newSubId = slotIdToSubIdMap.get(slotID); 512 if (oldSubId != newSubId) { 513 changedSubIds.put(slotID, newSubId); 514 mLocalLog.log("subId changed for slot: " + slotID + ", " + oldSubId + " -> " 515 + newSubId); 516 Log.i(LOG_TAG, "subId changed for slot: " + slotID + ", " + oldSubId + " -> " 517 + newSubId); 518 if (newSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 519 /* An INVALID subId can also be set in bind(), however 520 the ImsEnablementTracker will move into the DEFAULT state, so we only 521 need to track changes in subId that result in requiring we move 522 the state machine back to DEFAULT. 523 */ 524 mImsEnablementTracker.subIdChangedToInvalid(slotID); 525 } 526 } 527 } 528 mSlotIdToSubIdMap = slotIdToSubIdMap; 529 // no change, return early. 530 if (mImsFeatures.equals(newImsFeatures) && changedSubIds.size() == 0) { 531 return; 532 } 533 mLocalLog.log("Features (" + mImsFeatures + "->" + newImsFeatures + ")"); 534 Log.i(LOG_TAG, "Features (" + mImsFeatures + "->" + newImsFeatures + ") for " 535 + "ImsService: " + mComponentName); 536 HashSet<ImsFeatureConfiguration.FeatureSlotPair> oldImsFeatures = 537 new HashSet<>(mImsFeatures); 538 // Set features first in case we lose binding and need to rebind later. 539 mImsFeatures = newImsFeatures; 540 if (mIsBound) { 541 // add features to service. 542 HashSet<ImsFeatureConfiguration.FeatureSlotPair> newFeatures = 543 new HashSet<>(mImsFeatures); 544 newFeatures.removeAll(oldImsFeatures); 545 for (ImsFeatureConfiguration.FeatureSlotPair i : newFeatures) { 546 long caps = modifyCapabiltiesForSlot(mImsFeatures, i.slotId, 547 mServiceCapabilities); 548 addImsServiceFeature(i, caps, mSlotIdToSubIdMap.get(i.slotId)); 549 } 550 // remove old features 551 HashSet<ImsFeatureConfiguration.FeatureSlotPair> oldFeatures = 552 new HashSet<>(oldImsFeatures); 553 oldFeatures.removeAll(mImsFeatures); 554 for (ImsFeatureConfiguration.FeatureSlotPair i : oldFeatures) { 555 removeImsServiceFeature(i, false); 556 } 557 // ensure the capabilities have been updated for unchanged features. 558 HashSet<ImsFeatureConfiguration.FeatureSlotPair> unchangedFeatures = 559 new HashSet<>(mImsFeatures); 560 unchangedFeatures.removeAll(oldFeatures); 561 unchangedFeatures.removeAll(newFeatures); 562 // Go through ImsFeatures whose associated subId have changed and recreate them. 563 if (changedSubIds.size() > 0) { 564 for (int slotId : changedSubIds.copyKeys()) { 565 int subId = changedSubIds.get(slotId, 566 SubscriptionManager.INVALID_SUBSCRIPTION_ID); 567 HashSet<ImsFeatureConfiguration.FeatureSlotPair> 568 removeAddFeatures = unchangedFeatures.stream() 569 .filter(e -> e.slotId == slotId).collect( 570 Collectors.toCollection(HashSet::new)); 571 for (ImsFeatureConfiguration.FeatureSlotPair i : removeAddFeatures) { 572 removeImsServiceFeature(i, true); 573 } 574 for (ImsFeatureConfiguration.FeatureSlotPair i : removeAddFeatures) { 575 long caps = modifyCapabiltiesForSlot(mImsFeatures, i.slotId, 576 mServiceCapabilities); 577 addImsServiceFeature(i, caps, subId); 578 } 579 unchangedFeatures.removeAll(removeAddFeatures); 580 } 581 } 582 for (ImsFeatureConfiguration.FeatureSlotPair p : unchangedFeatures) { 583 long caps = modifyCapabiltiesForSlot(mImsFeatures, p.slotId, 584 mServiceCapabilities); 585 mRepo.notifyFeatureCapabilitiesChanged(p.slotId, p.featureType, caps); 586 } 587 } 588 } 589 } 590 591 @VisibleForTesting getImsServiceController()592 public IImsServiceController getImsServiceController() { 593 return mIImsServiceController; 594 } 595 596 @VisibleForTesting getRebindDelay()597 public long getRebindDelay() { 598 return mBackoff.getCurrentDelay(); 599 } 600 601 @VisibleForTesting stopBackoffTimerForTesting()602 public void stopBackoffTimerForTesting() { 603 mBackoff.stop(); 604 } 605 getComponentName()606 public ComponentName getComponentName() { 607 return mComponentName; 608 } 609 610 /** 611 * Notify ImsService to enable IMS for the framework. This will trigger IMS registration and 612 * trigger ImsFeature status updates. 613 */ enableIms(int slotId, int subId)614 public void enableIms(int slotId, int subId) { 615 mImsEnablementTracker.enableIms(slotId, subId); 616 } 617 618 /** 619 * Notify ImsService to disable IMS for the framework. This will trigger IMS de-registration and 620 * trigger ImsFeature capability status to become false. 621 */ disableIms(int slotId, int subId)622 public void disableIms(int slotId, int subId) { 623 mImsEnablementTracker.disableIms(slotId, subId); 624 } 625 626 /** 627 * Notify ImsService to disable IMS for the framework. 628 * And notify ImsService back to enable IMS for the framework 629 */ resetIms(int slotId, int subId)630 public void resetIms(int slotId, int subId) { 631 mImsEnablementTracker.resetIms(slotId, subId); 632 } 633 634 /** 635 * @return the IImsRegistration that corresponds to the slot id specified. 636 */ getRegistration(int slotId, int subId)637 public IImsRegistration getRegistration(int slotId, int subId) throws RemoteException { 638 synchronized (mLock) { 639 return isServiceControllerAvailable() 640 ? mIImsServiceController.getRegistration(slotId, subId) : null; 641 } 642 } 643 644 /** 645 * @return the IImsConfig that corresponds to the slot id specified. 646 */ getConfig(int slotId, int subId)647 public IImsConfig getConfig(int slotId, int subId) throws RemoteException { 648 synchronized (mLock) { 649 return isServiceControllerAvailable() 650 ? mIImsServiceController.getConfig(slotId, subId) : null; 651 } 652 } 653 654 /** 655 * @return the ISipTransport instance associated with the requested slot ID. 656 */ getSipTransport(int slotId)657 public ISipTransport getSipTransport(int slotId) throws RemoteException { 658 synchronized (mLock) { 659 return isServiceControllerAvailable() 660 ? mIImsServiceController.getSipTransport(slotId) : null; 661 } 662 } 663 getStaticServiceCapabilities()664 protected long getStaticServiceCapabilities() throws RemoteException { 665 synchronized (mLock) { 666 return isServiceControllerAvailable() 667 ? mIImsServiceController.getImsServiceCapabilities() : 0L; 668 } 669 } 670 671 /** 672 * notify the ImsService that the ImsService is ready for feature creation. 673 */ notifyImsServiceReady()674 protected void notifyImsServiceReady() throws RemoteException { 675 synchronized (mLock) { 676 if (isServiceControllerAvailable()) { 677 Log.d(LOG_TAG, "notifyImsServiceReady"); 678 mIImsServiceController.setListener(mFeatureChangedListener); 679 mIImsServiceController.notifyImsServiceReadyForFeatureCreation(); 680 } 681 } 682 } 683 retrieveStaticImsServiceCapabilities()684 private void retrieveStaticImsServiceCapabilities() throws RemoteException { 685 long caps = getStaticServiceCapabilities(); 686 Log.i(LOG_TAG, "retrieveStaticImsServiceCapabilities: " 687 + ImsService.getCapabilitiesString(caps)); 688 mLocalLog.log("retrieveStaticImsServiceCapabilities: " 689 + ImsService.getCapabilitiesString(caps)); 690 synchronized (mLock) { 691 mServiceCapabilities = caps; 692 } 693 } 694 getServiceInterface()695 protected String getServiceInterface() { 696 return ImsService.SERVICE_INTERFACE; 697 } 698 699 /** 700 * Sets the IImsServiceController instance. Overridden by compat layers to set compatibility 701 * versions of this service controller. 702 */ setServiceController(IBinder serviceController)703 protected void setServiceController(IBinder serviceController) { 704 mIImsServiceController = IImsServiceController.Stub.asInterface(serviceController); 705 mImsEnablementTracker.setServiceController(serviceController); 706 } 707 708 /** 709 * Check to see if the service controller is available, overridden for compat versions, 710 * @return true if available, false otherwise; 711 */ isServiceControllerAvailable()712 protected boolean isServiceControllerAvailable() { 713 return mIImsServiceController != null; 714 } 715 716 // Only add a new rebind if there are no pending rebinds waiting. startDelayedRebindToService()717 private void startDelayedRebindToService() { 718 mBackoff.start(); 719 } 720 unbindService()721 private void unbindService() { 722 synchronized (mLock) { 723 if (mImsServiceConnection != null) { 724 Log.i(LOG_TAG, "Unbinding ImsService: " + mComponentName); 725 mLocalLog.log("unbinding: " + mComponentName); 726 mContext.unbindService(mImsServiceConnection); 727 mImsServiceConnection = null; 728 } else { 729 Log.i(LOG_TAG, "unbindService called on already unbound ImsService: " 730 + mComponentName); 731 mLocalLog.log("Note: unbindService called with no ServiceConnection on " 732 + mComponentName); 733 } 734 } 735 } 736 737 /** 738 * Modify the capabilities returned by the ImsService based on the state of this controller: 739 * - CAPABILITY_EMERGENCY_OVER_MMTEL should only be set if features contains 740 * FEATURE_EMERGENCY_MMTEL (This is not set by the ImsService itself). 741 * - CAPABILITY_SIP_DELEGATE_CREATION should only be set in the case that this ImsService is 742 * handling both MMTEL and RCS features for this slot. 743 */ modifyCapabiltiesForSlot( Set<ImsFeatureConfiguration.FeatureSlotPair> features, int slotId, long serviceCaps)744 private long modifyCapabiltiesForSlot( 745 Set<ImsFeatureConfiguration.FeatureSlotPair> features, int slotId, long serviceCaps) { 746 long caps = serviceCaps; 747 List<Integer> featureTypes = getFeaturesForSlot(slotId, features); 748 if (featureTypes.contains(ImsFeature.FEATURE_EMERGENCY_MMTEL)) { 749 // We only consider MMTEL_EMERGENCY as a capability here, so set the capability if 750 // the ImsService has declared it. 751 caps |= ImsService.CAPABILITY_EMERGENCY_OVER_MMTEL; 752 } 753 754 if (ENFORCE_SINGLE_SERVICE_FOR_SIP_TRANSPORT) { 755 if (!featureTypes.contains(ImsFeature.FEATURE_MMTEL) 756 || !featureTypes.contains(ImsFeature.FEATURE_RCS)) { 757 // Only allow SipDelegate creation if this ImsService is providing both MMTEL and 758 // RCS features. 759 caps &= ~(ImsService.CAPABILITY_SIP_DELEGATE_CREATION); 760 } 761 } else { 762 Log.i(LOG_TAG, "skipping single service enforce check..."); 763 } 764 return caps; 765 } 766 767 // Grant runtime permissions to ImsService. PermissionManager ensures that the ImsService is 768 // system/signed before granting permissions. grantPermissionsToService()769 private void grantPermissionsToService() { 770 mLocalLog.log("grant permissions to " + getComponentName()); 771 Log.i(LOG_TAG, "Granting Runtime permissions to:" + getComponentName()); 772 String[] pkgToGrant = {mComponentName.getPackageName()}; 773 try { 774 if (mPermissionManager != null) { 775 CountDownLatch latch = new CountDownLatch(1); 776 mPermissionManager.grantDefaultPermissionsToEnabledImsServices( 777 pkgToGrant, UserHandle.of(UserHandle.myUserId()), Runnable::run, 778 isSuccess -> { 779 if (isSuccess) { 780 latch.countDown(); 781 } else { 782 Log.e(LOG_TAG, "Failed to grant permissions to service."); 783 } 784 }); 785 TelephonyUtils.waitUntilReady(latch, CHANGE_PERMISSION_TIMEOUT_MS); 786 } 787 } catch (RuntimeException e) { 788 Log.w(LOG_TAG, "Unable to grant permissions, binder died."); 789 } 790 } 791 792 // This method should only be called when synchronized on mLock addImsServiceFeature(ImsFeatureConfiguration.FeatureSlotPair featurePair, long capabilities, int subId)793 private void addImsServiceFeature(ImsFeatureConfiguration.FeatureSlotPair featurePair, 794 long capabilities, int subId) throws RemoteException { 795 if (!isServiceControllerAvailable() || mCallbacks == null) { 796 Log.w(LOG_TAG, "addImsServiceFeature called with null values."); 797 return; 798 } 799 if (featurePair.featureType != ImsFeature.FEATURE_EMERGENCY_MMTEL) { 800 IInterface f = createImsFeature( 801 featurePair.slotId, subId, featurePair.featureType, capabilities); 802 addImsFeatureBinder(featurePair.slotId, subId, featurePair.featureType, 803 f, capabilities); 804 addImsFeatureStatusCallback(featurePair.slotId, featurePair.featureType); 805 } else { 806 // Don't update ImsService for emergency MMTEL feature. 807 Log.i(LOG_TAG, "supports emergency calling on slot " + featurePair.slotId); 808 } 809 // Signal ImsResolver to change supported ImsFeatures for this ImsServiceController 810 mCallbacks.imsServiceFeatureCreated(featurePair.slotId, featurePair.featureType, this); 811 } 812 813 // This method should only be called when synchronized on mLock removeImsServiceFeature(ImsFeatureConfiguration.FeatureSlotPair featurePair, boolean changeSubId)814 private void removeImsServiceFeature(ImsFeatureConfiguration.FeatureSlotPair featurePair, 815 boolean changeSubId) { 816 if (!isServiceControllerAvailable() || mCallbacks == null) { 817 Log.w(LOG_TAG, "removeImsServiceFeature called with null values."); 818 return; 819 } 820 // Signal ImsResolver to change supported ImsFeatures for this ImsServiceController 821 mCallbacks.imsServiceFeatureRemoved(featurePair.slotId, featurePair.featureType, this); 822 if (featurePair.featureType != ImsFeature.FEATURE_EMERGENCY_MMTEL) { 823 removeImsFeatureStatusCallback(featurePair.slotId, featurePair.featureType); 824 removeImsFeatureBinder(featurePair.slotId, featurePair.featureType); 825 try { 826 removeImsFeature(featurePair.slotId, featurePair.featureType, changeSubId); 827 } catch (RemoteException e) { 828 // The connection to this ImsService doesn't exist. This may happen if the service 829 // has died and we are removing features. 830 Log.i(LOG_TAG, "Couldn't remove feature {" 831 + ImsFeature.FEATURE_LOG_MAP.get(featurePair.featureType) 832 + "}, connection is down: " + e.getMessage()); 833 } 834 } else { 835 // Don't update ImsService for emergency MMTEL feature. 836 Log.i(LOG_TAG, "doesn't support emergency calling on slot " + featurePair.slotId); 837 } 838 } 839 840 // This method should only be called when already synchronized on mLock. 841 // overridden by compat layer to create features createImsFeature(int slotId, int subId, int featureType, long capabilities)842 protected IInterface createImsFeature(int slotId, int subId, int featureType, long capabilities) 843 throws RemoteException { 844 switch (featureType) { 845 case ImsFeature.FEATURE_MMTEL: { 846 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 847 boolean emergencyAvailable = 848 (capabilities & ImsService.CAPABILITY_EMERGENCY_OVER_MMTEL) > 0; 849 if (emergencyAvailable) { 850 return mIImsServiceController.createEmergencyOnlyMmTelFeature(slotId); 851 } else { 852 return null; 853 } 854 } 855 return mIImsServiceController.createMmTelFeature(slotId, subId); 856 } 857 case ImsFeature.FEATURE_RCS: { 858 return mIImsServiceController.createRcsFeature(slotId, subId); 859 } 860 default: 861 return null; 862 } 863 } 864 865 // This method should only be called when already synchronized on mLock. addImsFeatureStatusCallback(int slotId, int featureType)866 private void addImsFeatureStatusCallback(int slotId, int featureType) throws RemoteException { 867 ImsFeatureStatusCallback c = new ImsFeatureStatusCallback(slotId, featureType); 868 mFeatureStatusCallbacks.add(c); 869 registerImsFeatureStatusCallback(slotId, featureType, c.getCallback()); 870 } 871 872 // This method should only be called when already synchronized on mLock. removeImsFeatureStatusCallback(int slotId, int featureType)873 private void removeImsFeatureStatusCallback(int slotId, int featureType) { 874 ImsFeatureStatusCallback callbackToRemove = mFeatureStatusCallbacks.stream().filter(c -> 875 c.mSlotId == slotId && c.mFeatureType == featureType).findFirst().orElse(null); 876 // Remove status callbacks from list. 877 if (callbackToRemove != null) { 878 mFeatureStatusCallbacks.remove(callbackToRemove); 879 unregisterImsFeatureStatusCallback(slotId, featureType, callbackToRemove.getCallback()); 880 } 881 } 882 883 // overridden by compat layer to register feature status callbacks registerImsFeatureStatusCallback(int slotId, int featureType, IImsFeatureStatusCallback c)884 protected void registerImsFeatureStatusCallback(int slotId, int featureType, 885 IImsFeatureStatusCallback c) throws RemoteException { 886 mIImsServiceController.addFeatureStatusCallback(slotId, featureType, c); 887 } 888 889 // overridden by compat layer to deregister feature status callbacks unregisterImsFeatureStatusCallback(int slotId, int featureType, IImsFeatureStatusCallback c)890 protected void unregisterImsFeatureStatusCallback(int slotId, int featureType, 891 IImsFeatureStatusCallback c) { 892 try { 893 mIImsServiceController.removeFeatureStatusCallback(slotId, featureType, c); 894 } catch (RemoteException e) { 895 mLocalLog.log("unregisterImsFeatureStatusCallback - couldn't remove " + c); 896 } 897 } 898 899 900 // overridden by compat layer to remove features removeImsFeature(int slotId, int featureType, boolean changeSubId)901 protected void removeImsFeature(int slotId, int featureType, boolean changeSubId) 902 throws RemoteException { 903 mIImsServiceController.removeImsFeature(slotId, featureType, changeSubId); 904 } 905 addImsFeatureBinder(int slotId, int subId, int featureType, IInterface b, long capabilities)906 private void addImsFeatureBinder(int slotId, int subId, int featureType, IInterface b, 907 long capabilities) 908 throws RemoteException { 909 if (b == null) { 910 911 Log.w(LOG_TAG, "addImsFeatureBinder: null IInterface reported for " 912 + ImsFeature.FEATURE_LOG_MAP.get(featureType)); 913 mLocalLog.log("addImsFeatureBinder: null IInterface reported for " 914 + ImsFeature.FEATURE_LOG_MAP.get(featureType)); 915 return; 916 } 917 ImsFeatureContainer fc = createFeatureContainer(slotId, subId, b.asBinder(), capabilities); 918 mRepo.addConnection(slotId, subId, featureType, fc); 919 } 920 removeImsFeatureBinder(int slotId, int featureType)921 private void removeImsFeatureBinder(int slotId, int featureType) { 922 mRepo.removeConnection(slotId, featureType); 923 } 924 createFeatureContainer(int slotId, int subId, IBinder b, long capabilities)925 private ImsFeatureContainer createFeatureContainer(int slotId, int subId, IBinder b, 926 long capabilities) 927 throws RemoteException { 928 IImsConfig config = getConfig(slotId, subId); 929 IImsRegistration reg = getRegistration(slotId, subId); 930 // When either is null, this is an unexpected condition. Do not report the ImsService as 931 // being available. 932 if (config == null || reg == null) { 933 Log.w(LOG_TAG, "createFeatureContainer: invalid state. Reporting as not " 934 + "available. componentName= " + getComponentName()); 935 mLocalLog.log("createFeatureContainer: invalid state. Reporting as not " 936 + "available."); 937 return null; 938 } 939 // SipTransport AIDL may be null for older devices, this is expected. 940 ISipTransport transport = getSipTransport(slotId); 941 return new ImsFeatureContainer(b, config, reg, transport, capabilities); 942 } 943 getFeaturesForSlot(int slotId, Set<ImsFeatureConfiguration.FeatureSlotPair> features)944 private List<Integer> getFeaturesForSlot(int slotId, 945 Set<ImsFeatureConfiguration.FeatureSlotPair> features) { 946 return features.stream().filter(f -> f.slotId == slotId).map(f -> f.featureType) 947 .collect(Collectors.toList()); 948 } 949 cleanupAllFeatures()950 private void cleanupAllFeatures() { 951 synchronized (mLock) { 952 // Remove all features and clean up all associated Binders. 953 for (ImsFeatureConfiguration.FeatureSlotPair i : mImsFeatures) { 954 removeImsServiceFeature(i, false); 955 } 956 } 957 } 958 checkAndReportAnomaly(ComponentName name)959 private void checkAndReportAnomaly(ComponentName name) { 960 if (mPackageManager == null) { 961 Log.w(LOG_TAG, "mPackageManager null"); 962 return; 963 } 964 ChangedPackages curChangedPackages = 965 mPackageManager.getChangedPackages(mLastSequenceNumber); 966 if (curChangedPackages != null) { 967 mLastSequenceNumber = curChangedPackages.getSequenceNumber(); 968 List<String> packagesNames = curChangedPackages.getPackageNames(); 969 if (packagesNames.contains(name.getPackageName())) { 970 Log.d(LOG_TAG, "Ignore due to updated, package: " + name.getPackageName()); 971 return; 972 } 973 } 974 String message = "IMS Service Crashed"; 975 AnomalyReporter.reportAnomaly(mAnomalyUUID, message); 976 } 977 978 @Override toString()979 public String toString() { 980 synchronized (mLock) { 981 return "[ImsServiceController: componentName=" + getComponentName() + ", features=" 982 + mImsFeatures + ", isBinding=" + mIsBinding + ", isBound=" + mIsBound 983 + ", serviceController=" + getImsServiceController() + ", rebindDelay=" 984 + getRebindDelay() + "]"; 985 } 986 } 987 dump(PrintWriter printWriter)988 public void dump(PrintWriter printWriter) { 989 mLocalLog.dump(printWriter); 990 } 991 } 992