diff options
Diffstat (limited to 'src/java/com/android/ims/MmTelFeatureConnection.java')
-rw-r--r-- | src/java/com/android/ims/MmTelFeatureConnection.java | 117 |
1 files changed, 72 insertions, 45 deletions
diff --git a/src/java/com/android/ims/MmTelFeatureConnection.java b/src/java/com/android/ims/MmTelFeatureConnection.java index de8f9282..d6954f3f 100644 --- a/src/java/com/android/ims/MmTelFeatureConnection.java +++ b/src/java/com/android/ims/MmTelFeatureConnection.java @@ -44,8 +44,10 @@ import com.android.ims.internal.IImsMultiEndpoint; import com.android.ims.internal.IImsServiceFeatureCallback; import com.android.ims.internal.IImsUt; +import java.util.Collections; import java.util.HashSet; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; /** * A container of the IImsServiceController binder, which implements all of the ImsFeatures that @@ -73,35 +75,41 @@ public class MmTelFeatureConnection { private IImsRegistration mRegistrationBinder; private IImsConfig mConfigBinder; + private IBinder.DeathRecipient mDeathRecipient = () -> { + Log.w(TAG, "DeathRecipient triggered, binder died."); + onRemovedOrDied(); + }; + private abstract class CallbackAdapterManager<T> { private static final String TAG = "CallbackAdapterManager"; - protected final Set<T> mLocalCallbacks = new HashSet<>(); + protected final Set<T> mLocalCallbacks = + Collections.newSetFromMap(new ConcurrentHashMap<>()); private boolean mHasConnected = false; public void addCallback(T localCallback) throws RemoteException { // We only one one binding to the ImsService per process. // Store any more locally. synchronized (mLock) { - if(!mHasConnected) { + if (!mHasConnected) { // throws a RemoteException if a connection can not be established. - if(createConnection()) { + if (createConnection()) { mHasConnected = true; } else { throw new RemoteException("Can not create connection!"); } } - Log.i(TAG, "Local callback added: " + localCallback); - mLocalCallbacks.add(localCallback); } + Log.i(TAG, "Local callback added: " + localCallback); + mLocalCallbacks.add(localCallback); } public void removeCallback(T localCallback) { // We only maintain one binding to the ImsService per process. + Log.i(TAG, "Local callback removed: " + localCallback); + mLocalCallbacks.remove(localCallback); synchronized (mLock) { - Log.i(TAG, "Local callback removed: " + localCallback); - mLocalCallbacks.remove(localCallback); - // If we have removed all local callbacks, remove callback to ImsService. + // If we have removed all local callbacks, remove callback to ImsService. if(mHasConnected) { if (mLocalCallbacks.isEmpty()) { removeConnection(); @@ -118,9 +126,9 @@ public class MmTelFeatureConnection { // Still mark the connection as disconnected, even if this fails. mHasConnected = false; } - Log.i(TAG, "Closing connection and clearing callbacks"); - mLocalCallbacks.clear(); } + Log.i(TAG, "Closing connection and clearing callbacks"); + mLocalCallbacks.clear(); } abstract boolean createConnection() throws RemoteException; @@ -140,27 +148,21 @@ public class MmTelFeatureConnection { public void onRegistered(int imsRadioTech) { Log.i(TAG, "onRegistered ::"); - synchronized (mLock) { - mLocalCallbacks.forEach(l -> l.onRegistered(imsRadioTech)); - } + mLocalCallbacks.forEach(l -> l.onRegistered(imsRadioTech)); } @Override public void onRegistering(int imsRadioTech) { Log.i(TAG, "onRegistering ::"); - synchronized (mLock) { - mLocalCallbacks.forEach(l -> l.onRegistering(imsRadioTech)); - } + mLocalCallbacks.forEach(l -> l.onRegistering(imsRadioTech)); } @Override public void onDeregistered(ImsReasonInfo imsReasonInfo) { Log.i(TAG, "onDeregistered ::"); - synchronized (mLock) { - mLocalCallbacks.forEach(l -> l.onDeregistered(imsReasonInfo)); - } + mLocalCallbacks.forEach(l -> l.onDeregistered(imsReasonInfo)); } @Override @@ -168,18 +170,15 @@ public class MmTelFeatureConnection { Log.i(TAG, "onTechnologyChangeFailed :: targetAccessTech=" + targetRadioTech + ", imsReasonInfo=" + imsReasonInfo); - synchronized (mLock) { mLocalCallbacks.forEach(l -> l.onTechnologyChangeFailed(targetRadioTech, imsReasonInfo)); - } } @Override public void onSubscriberAssociatedUriChanged(Uri[] uris) { Log.i(TAG, "onSubscriberAssociatedUriChanged"); - synchronized (mLock) { - mLocalCallbacks.forEach(l -> l.onSubscriberAssociatedUriChanged(uris)); - } + + mLocalCallbacks.forEach(l -> l.onSubscriberAssociatedUriChanged(uris)); } } @@ -220,16 +219,18 @@ public class MmTelFeatureConnection { // Called when the Capabilities Status on this connection have changed. @Override public void onCapabilitiesStatusChanged(ImsFeature.Capabilities config) { - synchronized (mLock) { - mLocalCallbacks.forEach( - callback -> callback.onCapabilitiesStatusChanged(config)); - } + mLocalCallbacks.forEach( + callback -> callback.onCapabilitiesStatusChanged(config)); } } @Override boolean createConnection() throws RemoteException { - IImsMmTelFeature binder = getServiceInterface(mBinder); + IImsMmTelFeature binder; + synchronized (mLock) { + checkServiceIsReady(); + binder = getServiceInterface(mBinder); + } if (binder != null) { binder.addCapabilityCallback(mCallbackAdapter); return true; @@ -241,7 +242,15 @@ public class MmTelFeatureConnection { @Override void removeConnection() { - IImsMmTelFeature binder = getServiceInterface(mBinder); + IImsMmTelFeature binder = null; + synchronized (mLock) { + try { + checkServiceIsReady(); + binder = getServiceInterface(mBinder); + } catch (RemoteException e) { + // binder is null + } + } if (binder != null) { try { binder.removeCapabilityCallback(mCallbackAdapter); @@ -333,14 +342,8 @@ public class MmTelFeatureConnection { } switch (feature) { case ImsFeature.FEATURE_MMTEL: { - if (mIsAvailable) { - Log.i(TAG, "MmTel disabled on slotId: " + slotId); - mIsAvailable = false; - mmTelFeatureRemoved(); - if (mStatusCallback != null) { - mStatusCallback.notifyUnavailable(); - } - } + Log.i(TAG, "MmTel removed on slotId: " + slotId); + onRemovedOrDied(); break; } case ImsFeature.FEATURE_EMERGENCY_MMTEL : { @@ -372,12 +375,23 @@ public class MmTelFeatureConnection { mContext = context; } - // Called when the MmTelFeatureConnection has received an unavailable notification. - private void mmTelFeatureRemoved() { + /** + * Called when the MmTelFeature has either been removed by Telephony or crashed. + */ + private void onRemovedOrDied() { synchronized (mLock) { - // invalidate caches. - mRegistrationBinder = null; - mConfigBinder = null; + if (mIsAvailable) { + mIsAvailable = false; + // invalidate caches. + mRegistrationBinder = null; + mConfigBinder = null; + if (mBinder != null) { + mBinder.unlinkToDeath(mDeathRecipient, 0); + } + if (mStatusCallback != null) { + mStatusCallback.notifyUnavailable(); + } + } } } @@ -430,7 +444,16 @@ public class MmTelFeatureConnection { } public void setBinder(IBinder binder) { - mBinder = binder; + synchronized (mLock) { + mBinder = binder; + try { + if (mBinder != null) { + mBinder.linkToDeath(mDeathRecipient, 0); + } + } catch (RemoteException e) { + // No need to do anything if the binder is already dead. + } + } } /** @@ -451,7 +474,11 @@ public class MmTelFeatureConnection { mRegistrationCallbackManager.close(); mCapabilityCallbackManager.close(); try { - getServiceInterface(mBinder).setListener(null); + synchronized (mLock) { + if (isBinderAlive()) { + getServiceInterface(mBinder).setListener(null); + } + } } catch (RemoteException e) { Log.w(TAG, "closeConnection: couldn't remove listener!"); } |