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