From fdc4bff3198fcaedfa29f45d92525c0351acd583 Mon Sep 17 00:00:00 2001 From: Tyler Gunn Date: Thu, 24 Jun 2021 11:25:07 -0700 Subject: Fix issue when adding existing connections via remote connection services. When an existing connection is added to represent an IMS conference participant, it is added with an associated parent conference specified. This was NOT passed along to the connection manager via the RemoteConnectionService API since there is no equivalent API present for that operation. To work around this, we stash the parent conference's ID into the connection extras. We will use that later so that Telecom can know which conference is the parent of this call. Also, removing restriction in RemoteConnectionService which would ignore conferences with no children. This assumption was incorrect for VOLTE conferences since they will start with no children. As a consequence we would ALWAYS skip adding IMS conferences to the connection manager, which would mean that it had no way of knowing about the conference that the existing connections are associated with. Test: Manual test with connection manager APIS on live network; make conference and verify that the correct objects are being created wrapped by the connection manager. Bug: 188420526 Change-Id: Ie58afed7a3b7eeaa7e329e80479d273e4c50ec82 Change-Id: I4250f9459c7a1b82936583a10e93d049fdfb4c5d --- telecomm/java/android/telecom/Connection.java | 15 +++++++++++++ .../android/telecom/RemoteConnectionService.java | 26 ++++++++++++++++------ 2 files changed, 34 insertions(+), 7 deletions(-) (limited to 'telecomm/java/android') diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java index 759afd72d539..f2f1645b335d 100644 --- a/telecomm/java/android/telecom/Connection.java +++ b/telecomm/java/android/telecom/Connection.java @@ -774,6 +774,21 @@ public abstract class Connection extends Conferenceable { public static final String EXTRA_REMOTE_PHONE_ACCOUNT_HANDLE = "android.telecom.extra.REMOTE_PHONE_ACCOUNT_HANDLE"; + /** + * The Telecom call ID of the conference an existing connection should be added to. This is + * required when {@link com.android.services.telephony.TelephonyConnectionService} adds a + * {@link Conference} to Telecom using the + * {@link ConnectionService#addExistingConnection(PhoneAccountHandle, Connection, Conference)} + * API. That API specifies a parent conference associated with the new existing connection + * being added, and there is no equivalent as part of the {@link RemoteConnectionService} API. + * This extra key is used to stack the ID of the conference to which the existing connection + * will be added so that Telecom can link it up correctly when the {@link RemoteConference} + * is added to Telecom by the connection manager. + * @hide + */ + public static final String EXTRA_ADD_TO_CONFERENCE_ID = + "android.telecom.extra.ADD_TO_CONFERENCE_ID"; + /** * Extra key set from a {@link ConnectionService} when using the remote connection APIs * (e.g. {@link RemoteConnectionService#createRemoteConnection(PhoneAccountHandle, diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java index bf6a6ef793ff..efe35d21c003 100644 --- a/telecomm/java/android/telecom/RemoteConnectionService.java +++ b/telecomm/java/android/telecom/RemoteConnectionService.java @@ -239,13 +239,9 @@ final class RemoteConnectionService { conference.addConnection(c); } } - if (conference.getConnections().size() == 0) { - // A conference was created, but none of its connections are ones that have been - // created by, and therefore being tracked by, this remote connection service. It - // is of no interest to us. - Log.d(this, "addConferenceCall - skipping"); - return; - } + // We used to skip adding empty conferences; however in the world of IMS conference + // calls we need to add them to the remote connection service because they will always + // start with no participants. conference.setState(parcel.getState()); conference.setConnectionCapabilities(parcel.getConnectionCapabilities()); @@ -379,6 +375,8 @@ final class RemoteConnectionService { @Override public void addExistingConnection(String callId, ParcelableConnection connection, Session.Info sessionInfo) { + Log.i(RemoteConnectionService.this, "addExistingConnection: callId=%s, conn=%s", callId, + connection); String callingPackage = mOurConnectionServiceImpl.getApplicationContext(). getOpPackageName(); int callingTargetSdkVersion = mOurConnectionServiceImpl.getApplicationInfo() @@ -390,6 +388,20 @@ final class RemoteConnectionService { Bundle newExtras = new Bundle(); newExtras.putParcelable(Connection.EXTRA_REMOTE_PHONE_ACCOUNT_HANDLE, connection.getPhoneAccount()); + if (connection.getParentCallId() != null) { + RemoteConference parentConf = mConferenceById.get(connection.getParentCallId()); + // If there is a parent being set, we need to stash the conference ID here. + // Telephony can add an existing connection while specifying a parent conference. + // There is no equivalent version of that operation as part of the remote connection + // API, so we will stash the pre-defined parent's ID in the extras. When the + // connectionmanager copies over the extras from the remote connection to the + // actual one, it'll get passed to Telecom so that it can make the association. + if (parentConf != null) { + newExtras.putString(Connection.EXTRA_ADD_TO_CONFERENCE_ID, parentConf.getId()); + Log.i(this, "addExistingConnection: stash parent of %s as %s", + connection.getParentCallId(), parentConf.getId()); + } + } remoteConnection.putExtras(newExtras); mConnectionById.put(callId, remoteConnection); remoteConnection.registerCallback(new RemoteConnection.Callback() { -- cgit v1.2.3-59-g8ed1b From c71732375d4f748161f3aacf41f4a175a7fb23c2 Mon Sep 17 00:00:00 2001 From: Grace Jia Date: Thu, 15 Jul 2021 11:36:49 -0700 Subject: Add a lock for call read/write operations to avoid ConcurrentModificationException. Bug: 189816293 Test: InCallService cts tests Change-Id: I123b2de55b856d12ee2a5e6d2fa49c15a74592fc --- telecomm/java/android/telecom/Phone.java | 45 ++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 14 deletions(-) (limited to 'telecomm/java/android') diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java index a427ed612b31..bc0a14667307 100644 --- a/telecomm/java/android/telecom/Phone.java +++ b/telecomm/java/android/telecom/Phone.java @@ -23,6 +23,8 @@ import android.os.Build; import android.os.Bundle; import android.util.ArrayMap; +import com.android.internal.annotations.GuardedBy; + import java.util.Collections; import java.util.List; import java.util.Map; @@ -115,6 +117,7 @@ public final class Phone { public static final int SDK_VERSION_R = 30; // A Map allows us to track each Call by its Telecom-specified call ID + @GuardedBy("mLock") private final Map mCallByTelecomCallId = new ArrayMap<>(); // A List allows us to keep the Calls in a stable iteration order so that casually developed @@ -139,6 +142,8 @@ public final class Phone { */ private final int mTargetSdkVersion; + private final Object mLock = new Object(); + Phone(InCallAdapter adapter, String callingPackage, int targetSdkVersion) { mInCallAdapter = adapter; mCallingPackage = callingPackage; @@ -152,12 +157,16 @@ public final class Phone { return; } - Call call = mCallByTelecomCallId.get(parcelableCall.getId()); + Call call = getCallById(parcelableCall.getId()); if (call == null) { call = new Call(this, parcelableCall.getId(), mInCallAdapter, parcelableCall.getState(), mCallingPackage, mTargetSdkVersion); - mCallByTelecomCallId.put(parcelableCall.getId(), call); - mCalls.add(call); + + synchronized (mLock) { + mCallByTelecomCallId.put(parcelableCall.getId(), call); + mCalls.add(call); + } + checkCallTree(parcelableCall); call.internalUpdate(parcelableCall, mCallByTelecomCallId); fireCallAdded(call); @@ -169,8 +178,10 @@ public final class Phone { } final void internalRemoveCall(Call call) { - mCallByTelecomCallId.remove(call.internalGetCallId()); - mCalls.remove(call); + synchronized (mLock) { + mCallByTelecomCallId.remove(call.internalGetCallId()); + mCalls.remove(call); + } InCallService.VideoCall videoCall = call.getVideoCall(); if (videoCall != null) { @@ -183,14 +194,14 @@ public final class Phone { if (mTargetSdkVersion < SDK_VERSION_R && parcelableCall.getState() == Call.STATE_AUDIO_PROCESSING) { Log.i(this, "removing audio processing call during update for sdk compatibility"); - Call call = mCallByTelecomCallId.get(parcelableCall.getId()); + Call call = getCallById(parcelableCall.getId()); if (call != null) { internalRemoveCall(call); } return; } - Call call = mCallByTelecomCallId.get(parcelableCall.getId()); + Call call = getCallById(parcelableCall.getId()); if (call != null) { checkCallTree(parcelableCall); call.internalUpdate(parcelableCall, mCallByTelecomCallId); @@ -207,8 +218,14 @@ public final class Phone { } } + Call getCallById(String callId) { + synchronized (mLock) { + return mCallByTelecomCallId.get(callId); + } + } + final void internalSetPostDialWait(String telecomId, String remaining) { - Call call = mCallByTelecomCallId.get(telecomId); + Call call = getCallById(telecomId); if (call != null) { call.internalSetPostDialWait(remaining); } @@ -222,7 +239,7 @@ public final class Phone { } final Call internalGetCallByTelecomId(String telecomId) { - return mCallByTelecomCallId.get(telecomId); + return getCallById(telecomId); } final void internalBringToForeground(boolean showDialpad) { @@ -241,35 +258,35 @@ public final class Phone { } final void internalOnConnectionEvent(String telecomId, String event, Bundle extras) { - Call call = mCallByTelecomCallId.get(telecomId); + Call call = getCallById(telecomId); if (call != null) { call.internalOnConnectionEvent(event, extras); } } final void internalOnRttUpgradeRequest(String callId, int requestId) { - Call call = mCallByTelecomCallId.get(callId); + Call call = getCallById(callId); if (call != null) { call.internalOnRttUpgradeRequest(requestId); } } final void internalOnRttInitiationFailure(String callId, int reason) { - Call call = mCallByTelecomCallId.get(callId); + Call call = getCallById(callId); if (call != null) { call.internalOnRttInitiationFailure(reason); } } final void internalOnHandoverFailed(String callId, int error) { - Call call = mCallByTelecomCallId.get(callId); + Call call = getCallById(callId); if (call != null) { call.internalOnHandoverFailed(error); } } final void internalOnHandoverComplete(String callId) { - Call call = mCallByTelecomCallId.get(callId); + Call call = getCallById(callId); if (call != null) { call.internalOnHandoverComplete(); } -- cgit v1.2.3-59-g8ed1b