284 lines
10 KiB
Java
284 lines
10 KiB
Java
/*
|
|
* Copyright (C) 2020 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package android.telephony.ims.aidl;
|
|
|
|
import android.os.Binder;
|
|
import android.os.IBinder;
|
|
import android.os.RemoteException;
|
|
import android.telephony.ims.DelegateRegistrationState;
|
|
import android.telephony.ims.FeatureTagState;
|
|
import android.telephony.ims.SipDelegateConfiguration;
|
|
import android.telephony.ims.SipDelegateConnection;
|
|
import android.telephony.ims.SipDelegateImsConfiguration;
|
|
import android.telephony.ims.SipDelegateManager;
|
|
import android.telephony.ims.SipMessage;
|
|
import android.telephony.ims.stub.DelegateConnectionMessageCallback;
|
|
import android.telephony.ims.stub.DelegateConnectionStateCallback;
|
|
import android.telephony.ims.stub.SipDelegate;
|
|
import android.util.ArraySet;
|
|
import android.util.Log;
|
|
|
|
import java.util.List;
|
|
import java.util.NoSuchElementException;
|
|
import java.util.concurrent.Executor;
|
|
import java.util.concurrent.atomic.AtomicReference;
|
|
|
|
/**
|
|
* Wrapper class implementing {@link SipDelegateConnection} using AIDL, which is returned to the
|
|
* local process. Also holds a reference to incoming connection message and state AIDL impl to
|
|
* trampoline events to callbacks as well as notify the local process in the event that the remote
|
|
* process becomes unavailable.
|
|
* <p>
|
|
* When the remote {@link SipDelegate} is created, this instance tracks the
|
|
* {@link ISipDelegate} associated with it and implements the
|
|
* {@link SipDelegateConnection} sent back to the local callback.
|
|
* @hide
|
|
*/
|
|
public class SipDelegateConnectionAidlWrapper implements SipDelegateConnection,
|
|
IBinder.DeathRecipient {
|
|
private static final String LOG_TAG = "SipDelegateCAW";
|
|
|
|
private final ISipDelegateConnectionStateCallback.Stub mStateBinder =
|
|
new ISipDelegateConnectionStateCallback.Stub() {
|
|
@Override
|
|
public void onCreated(ISipDelegate c) {
|
|
associateSipDelegate(c);
|
|
final long token = Binder.clearCallingIdentity();
|
|
try {
|
|
mExecutor.execute(() ->
|
|
mStateCallback.onCreated(SipDelegateConnectionAidlWrapper.this));
|
|
} finally {
|
|
Binder.restoreCallingIdentity(token);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onFeatureTagStatusChanged(DelegateRegistrationState registrationState,
|
|
List<FeatureTagState> deniedFeatureTags) {
|
|
final long token = Binder.clearCallingIdentity();
|
|
try {
|
|
mExecutor.execute(() ->
|
|
mStateCallback.onFeatureTagStatusChanged(registrationState,
|
|
new ArraySet<>(deniedFeatureTags)));
|
|
} finally {
|
|
Binder.restoreCallingIdentity(token);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onImsConfigurationChanged(SipDelegateImsConfiguration registeredSipConfig) {
|
|
final long token = Binder.clearCallingIdentity();
|
|
try {
|
|
mExecutor.execute(() ->
|
|
mStateCallback.onImsConfigurationChanged(registeredSipConfig));
|
|
} finally {
|
|
Binder.restoreCallingIdentity(token);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onConfigurationChanged(SipDelegateConfiguration registeredSipConfig) {
|
|
final long token = Binder.clearCallingIdentity();
|
|
try {
|
|
mExecutor.execute(() ->
|
|
mStateCallback.onConfigurationChanged(registeredSipConfig));
|
|
} finally {
|
|
Binder.restoreCallingIdentity(token);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onDestroyed(int reason) {
|
|
invalidateSipDelegateBinder();
|
|
final long token = Binder.clearCallingIdentity();
|
|
try {
|
|
mExecutor.execute(() ->
|
|
mStateCallback.onDestroyed(reason));
|
|
} finally {
|
|
Binder.restoreCallingIdentity(token);
|
|
}
|
|
}
|
|
};
|
|
|
|
private final ISipDelegateMessageCallback.Stub mMessageBinder =
|
|
new ISipDelegateMessageCallback.Stub() {
|
|
@Override
|
|
public void onMessageReceived(SipMessage message) {
|
|
final long token = Binder.clearCallingIdentity();
|
|
try {
|
|
mExecutor.execute(() ->
|
|
mMessageCallback.onMessageReceived(message));
|
|
} finally {
|
|
Binder.restoreCallingIdentity(token);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onMessageSent(String viaTransactionId) {
|
|
final long token = Binder.clearCallingIdentity();
|
|
try {
|
|
mExecutor.execute(() ->
|
|
mMessageCallback.onMessageSent(viaTransactionId));
|
|
} finally {
|
|
Binder.restoreCallingIdentity(token);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onMessageSendFailure(String viaTransactionId, int reason) {
|
|
final long token = Binder.clearCallingIdentity();
|
|
try {
|
|
mExecutor.execute(() ->
|
|
mMessageCallback.onMessageSendFailure(viaTransactionId, reason));
|
|
} finally {
|
|
Binder.restoreCallingIdentity(token);
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
private final Executor mExecutor;
|
|
private final DelegateConnectionStateCallback mStateCallback;
|
|
private final DelegateConnectionMessageCallback mMessageCallback;
|
|
private final AtomicReference<ISipDelegate> mDelegateBinder =
|
|
new AtomicReference<>();
|
|
|
|
/**
|
|
* Wrap the local state and message callbacks, calling the implementation of these interfaces
|
|
* when the remote process calls these methods.
|
|
*/
|
|
public SipDelegateConnectionAidlWrapper(Executor executor,
|
|
DelegateConnectionStateCallback stateCallback,
|
|
DelegateConnectionMessageCallback messageCallback) {
|
|
mExecutor = executor;
|
|
mStateCallback = stateCallback;
|
|
mMessageCallback = messageCallback;
|
|
}
|
|
|
|
@Override
|
|
public void sendMessage(SipMessage sipMessage, long configVersion) {
|
|
try {
|
|
ISipDelegate conn = getSipDelegateBinder();
|
|
if (conn == null) {
|
|
notifyLocalMessageFailedToSend(sipMessage,
|
|
SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_CLOSED);
|
|
return;
|
|
}
|
|
conn.sendMessage(sipMessage, configVersion);
|
|
} catch (RemoteException e) {
|
|
notifyLocalMessageFailedToSend(sipMessage,
|
|
SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_DEAD);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void notifyMessageReceived(String viaTransactionId) {
|
|
try {
|
|
ISipDelegate conn = getSipDelegateBinder();
|
|
if (conn == null) {
|
|
return;
|
|
}
|
|
conn.notifyMessageReceived(viaTransactionId);
|
|
} catch (RemoteException e) {
|
|
// Nothing to do here, app will eventually get remote death callback.
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void notifyMessageReceiveError(String viaTransactionId, int reason) {
|
|
try {
|
|
ISipDelegate conn = getSipDelegateBinder();
|
|
if (conn == null) {
|
|
return;
|
|
}
|
|
conn.notifyMessageReceiveError(viaTransactionId, reason);
|
|
} catch (RemoteException e) {
|
|
// Nothing to do here, app will eventually get remote death callback.
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void cleanupSession(String callId) {
|
|
try {
|
|
ISipDelegate conn = getSipDelegateBinder();
|
|
if (conn == null) {
|
|
return;
|
|
}
|
|
conn.cleanupSession(callId);
|
|
} catch (RemoteException e) {
|
|
// Nothing to do here, app will eventually get remote death callback.
|
|
}
|
|
}
|
|
|
|
// Also called upon IImsRcsController death (telephony process dies).
|
|
@Override
|
|
public void binderDied() {
|
|
invalidateSipDelegateBinder();
|
|
mExecutor.execute(() -> mStateCallback.onDestroyed(
|
|
SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SERVICE_DEAD));
|
|
}
|
|
|
|
/**
|
|
* @return Implementation of state binder.
|
|
*/
|
|
public ISipDelegateConnectionStateCallback getStateCallbackBinder() {
|
|
return mStateBinder;
|
|
}
|
|
|
|
/**
|
|
* @return Implementation of message binder.
|
|
*/
|
|
public ISipDelegateMessageCallback getMessageCallbackBinder() {
|
|
return mMessageBinder;
|
|
}
|
|
|
|
/**
|
|
* @return The ISipDelegateConnection associated with this wrapper.
|
|
*/
|
|
public ISipDelegate getSipDelegateBinder() {
|
|
return mDelegateBinder.get();
|
|
}
|
|
|
|
private void associateSipDelegate(ISipDelegate c) {
|
|
if (c != null) {
|
|
try {
|
|
c.asBinder().linkToDeath(this, 0 /*flags*/);
|
|
} catch (RemoteException e) {
|
|
// already dead.
|
|
c = null;
|
|
}
|
|
}
|
|
mDelegateBinder.set(c);
|
|
}
|
|
|
|
private void invalidateSipDelegateBinder() {
|
|
ISipDelegate oldVal = mDelegateBinder.getAndUpdate((unused) -> null);
|
|
if (oldVal != null) {
|
|
try {
|
|
oldVal.asBinder().unlinkToDeath(this, 0 /*flags*/);
|
|
} catch (NoSuchElementException e) {
|
|
Log.i(LOG_TAG, "invalidateSipDelegateBinder: " + e);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void notifyLocalMessageFailedToSend(SipMessage m, int reason) {
|
|
String transactionId = m.getViaBranchParameter();
|
|
mExecutor.execute(() -> mMessageCallback.onMessageSendFailure(transactionId, reason));
|
|
}
|
|
}
|