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