IMS RCS API Improvements-SipDelegate
Bug: b/197892699, b/205194548
Test: atest DelegateStateTrackerTest
Change-Id: I3c5a7834688e6aa1294f9be7d8a37984c43ed26a
diff --git a/src/com/android/phone/ImsRcsController.java b/src/com/android/phone/ImsRcsController.java
index 7d594d1..3618d58 100644
--- a/src/com/android/phone/ImsRcsController.java
+++ b/src/com/android/phone/ImsRcsController.java
@@ -582,6 +582,7 @@
throw new SecurityException("Passed in PackageName can not be found on device");
}
+ final int uid = Binder.getCallingUid();
final long identity = Binder.clearCallingIdentity();
SipTransportController transport = getRcsFeatureController(subId).getFeature(
SipTransportController.class);
@@ -590,7 +591,7 @@
"This subscription does not support the creation of SIP delegates");
}
try {
- transport.createSipDelegate(subId, request, packageName, delegateState,
+ transport.createSipDelegate(subId, uid, request, packageName, delegateState,
delegateMessage);
} catch (ImsException e) {
throw new ServiceSpecificException(e.getCode(), e.getMessage());
diff --git a/src/com/android/services/telephony/rcs/DelegateStateTracker.java b/src/com/android/services/telephony/rcs/DelegateStateTracker.java
index 18aab88..64090d5 100644
--- a/src/com/android/services/telephony/rcs/DelegateStateTracker.java
+++ b/src/com/android/services/telephony/rcs/DelegateStateTracker.java
@@ -16,6 +16,10 @@
package com.android.services.telephony.rcs;
+import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
+import android.os.Build;
import android.os.RemoteException;
import android.telephony.ims.DelegateRegistrationState;
import android.telephony.ims.FeatureTagState;
@@ -28,6 +32,7 @@
import android.util.LocalLog;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.metrics.RcsStats;
import java.io.PrintWriter;
@@ -43,25 +48,58 @@
private static final String LOG_TAG = "DelegateST";
private final int mSubId;
+ private final int mUid;
private final ISipDelegateConnectionStateCallback mAppStateCallback;
private final ISipDelegate mLocalDelegateImpl;
private final LocalLog mLocalLog = new LocalLog(SipTransportController.LOG_SIZE);
+ private final RcsStats mRcsStats;
+
private List<FeatureTagState> mDelegateDeniedTags;
private DelegateRegistrationState mLastRegState;
private boolean mCreatedCalled = false;
private int mRegistrationStateOverride = -1;
-
+ private CompatChangesFactory mCompatChangesFactory;
private Set<String> mDelegateSupportedTags;
- private final RcsStats mRcsStats;
- public DelegateStateTracker(int subId, ISipDelegateConnectionStateCallback appStateCallback,
+ /**
+ * Interface for checking compatibility of apps
+ */
+ public interface CompatChangesFactory {
+ /**
+ * @param changeId The ID of the compatibility change.
+ * @param uid The UID of the app.
+ * @return {@code true} if the change is enabled for the current app.
+ */
+ boolean isChangeEnabled(long changeId, int uid);
+ }
+
+ /**
+ * For apps targeting Android T and above, support the REGISTERING state on APIs, such as
+ * {@code DelegateRegistrationState#addRegisteringFeatureTags} and
+ * {@code DelegateRegistrationState#getRegisteringFeatureTags}
+ * @hide
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S)
+ @VisibleForTesting
+ public static final long SUPPORT_REGISTERING_DELEGATE_STATE = 205194548;
+
+ public DelegateStateTracker(int subId, int uid,
+ ISipDelegateConnectionStateCallback appStateCallback,
ISipDelegate localDelegateImpl, RcsStats rcsStats) {
mSubId = subId;
+ mUid = uid;
mAppStateCallback = appStateCallback;
mLocalDelegateImpl = localDelegateImpl;
mRcsStats = rcsStats;
+ setCompatChangesFactory((changeId, uid1) -> CompatChanges.isChangeEnabled(changeId, uid1));
+ }
+
+ @VisibleForTesting
+ protected void setCompatChangesFactory(CompatChangesFactory factory) {
+ mCompatChangesFactory = factory;
}
/**
@@ -140,6 +178,9 @@
*/
@Override
public void onRegistrationStateChanged(DelegateRegistrationState registrationState) {
+ if (!mCompatChangesFactory.isChangeEnabled(SUPPORT_REGISTERING_DELEGATE_STATE, mUid)) {
+ registrationState = overrideRegistrationForCompatibility(registrationState);
+ }
if (mRegistrationStateOverride > DelegateRegistrationState.DEREGISTERED_REASON_UNKNOWN) {
logi("onRegistrationStateChanged: overriding registered state to "
+ mRegistrationStateOverride);
@@ -204,6 +245,7 @@
private DelegateRegistrationState overrideRegistrationForDelegateChange(
int registerOverrideReason, DelegateRegistrationState state) {
Set<String> registeredFeatures = state.getRegisteredFeatureTags();
+ Set<String> registeringFeatures = state.getRegisteringFeatureTags();
DelegateRegistrationState.Builder overriddenState = new DelegateRegistrationState.Builder();
// keep other deregistering/deregistered tags the same.
for (FeatureTagState dereging : state.getDeregisteringFeatureTags()) {
@@ -214,13 +256,41 @@
overriddenState.addDeregisteredFeatureTag(dereged.getFeatureTag(),
dereged.getState());
}
- // Override REGISTERED only
+ // Override REGISTERING/REGISTERED
+ for (String ft : registeringFeatures) {
+ overriddenState.addDeregisteringFeatureTag(ft, registerOverrideReason);
+ }
for (String ft : registeredFeatures) {
overriddenState.addDeregisteringFeatureTag(ft, registerOverrideReason);
}
return overriddenState.build();
}
+ private DelegateRegistrationState overrideRegistrationForCompatibility(
+ DelegateRegistrationState state) {
+ Set<String> registeredFeatures = state.getRegisteredFeatureTags();
+ Set<String> registeringFeatures = state.getRegisteringFeatureTags();
+ DelegateRegistrationState.Builder overriddenState = new DelegateRegistrationState.Builder();
+ // keep other registered/deregistering/deregistered tags the same.
+ for (FeatureTagState dereging : state.getDeregisteringFeatureTags()) {
+ overriddenState.addDeregisteringFeatureTag(dereging.getFeatureTag(),
+ dereging.getState());
+ }
+ for (FeatureTagState dereged : state.getDeregisteredFeatureTags()) {
+ overriddenState.addDeregisteredFeatureTag(dereged.getFeatureTag(),
+ dereged.getState());
+ }
+ overriddenState.addRegisteredFeatureTags(registeredFeatures);
+
+ // move the REGISTERING state to the DEREGISTERED state.
+ for (String tag : registeringFeatures) {
+ overriddenState.addDeregisteredFeatureTag(tag,
+ DelegateRegistrationState.DEREGISTERED_REASON_NOT_REGISTERED);
+ }
+
+ return overriddenState.build();
+ }
+
private void notifySipDelegateCreated() {
try {
mAppStateCallback.onCreated(mLocalDelegateImpl);
diff --git a/src/com/android/services/telephony/rcs/SipDelegateController.java b/src/com/android/services/telephony/rcs/SipDelegateController.java
index c728141..860a6d9 100644
--- a/src/com/android/services/telephony/rcs/SipDelegateController.java
+++ b/src/com/android/services/telephony/rcs/SipDelegateController.java
@@ -78,6 +78,7 @@
}
private final int mSubId;
+ private final int mUid;
private final String mPackageName;
private final DelegateRequest mInitialRequest;
private final ScheduledExecutorService mExecutorService;
@@ -89,12 +90,13 @@
private DelegateBinderStateManager mBinderConnection;
private Set<String> mTrackedFeatureTags;
- public SipDelegateController(int subId, DelegateRequest initialRequest, String packageName,
- ISipTransport transportImpl, IImsRegistration registrationImpl,
+ public SipDelegateController(int subId, int uid, DelegateRequest initialRequest,
+ String packageName, ISipTransport transportImpl, IImsRegistration registrationImpl,
ScheduledExecutorService executorService,
ISipDelegateConnectionStateCallback stateCallback,
ISipDelegateMessageCallback messageCallback) {
mSubId = subId;
+ mUid = uid;
mPackageName = packageName;
mInitialRequest = initialRequest;
mExecutorService = executorService;
@@ -102,7 +104,8 @@
mMessageTransportWrapper = new MessageTransportWrapper(mSubId, executorService,
messageCallback);
- mDelegateStateTracker = new DelegateStateTracker(mSubId, stateCallback,
+
+ mDelegateStateTracker = new DelegateStateTracker(mSubId, mUid, stateCallback,
mMessageTransportWrapper.getDelegateConnection(), RcsStats.getInstance());
}
@@ -110,12 +113,13 @@
* Inject dependencies for testing only.
*/
@VisibleForTesting
- public SipDelegateController(int subId, DelegateRequest initialRequest, String packageName,
- ScheduledExecutorService executorService,
+ public SipDelegateController(int subId, int uid, DelegateRequest initialRequest,
+ String packageName, ScheduledExecutorService executorService,
MessageTransportWrapper messageTransportWrapper,
DelegateStateTracker delegateStateTracker,
DelegateBinderStateManager.Factory connectionFactory) {
mSubId = subId;
+ mUid = uid;
mInitialRequest = initialRequest;
mPackageName = packageName;
mExecutorService = executorService;
diff --git a/src/com/android/services/telephony/rcs/SipTransportController.java b/src/com/android/services/telephony/rcs/SipTransportController.java
index 709e142..0aa3aa0 100644
--- a/src/com/android/services/telephony/rcs/SipTransportController.java
+++ b/src/com/android/services/telephony/rcs/SipTransportController.java
@@ -243,9 +243,9 @@
@VisibleForTesting
public interface SipDelegateControllerFactory {
/** See {@link SipDelegateController} */
- SipDelegateController create(int subId, DelegateRequest initialRequest, String packageName,
- ISipTransport sipTransportImpl, IImsRegistration registrationImpl,
- ScheduledExecutorService executorService,
+ SipDelegateController create(int subId, int uid, DelegateRequest initialRequest,
+ String packageName, ISipTransport sipTransportImpl,
+ IImsRegistration registrationImpl, ScheduledExecutorService executorService,
ISipDelegateConnectionStateCallback stateCallback,
ISipDelegateMessageCallback messageCallback);
}
@@ -364,17 +364,18 @@
* {@link ISipDelegateConnectionStateCallback#onCreated(ISipDelegate)} must be called with
* the AIDL instance corresponding to the remote {@link SipDelegate}.
* @param subId the subId associated with the request.
+ * @param uid the uid associated with the request
* @param request The request parameters used to create the {@link SipDelegate}.
* @param delegateState The {@link DelegateConnectionStateCallback} Binder connection.
* @param delegateMessage The {@link DelegateConnectionMessageCallback} Binder Connection
* @throws ImsException if the request to create the {@link SipDelegate} did not complete.
*/
- public void createSipDelegate(int subId, DelegateRequest request, String packageName,
+ public void createSipDelegate(int subId, int uid, DelegateRequest request, String packageName,
ISipDelegateConnectionStateCallback delegateState,
ISipDelegateMessageCallback delegateMessage) throws ImsException {
logi("createSipDelegate: request= " + request + ", packageName= " + packageName);
CompletableFuture<ImsException> result = new CompletableFuture<>();
- mExecutorService.submit(() -> createSipDelegateInternal(subId, request, packageName,
+ mExecutorService.submit(() -> createSipDelegateInternal(subId, uid, request, packageName,
delegateState,
// Capture any ImsExceptions generated during the process.
delegateMessage, result::complete));
@@ -423,8 +424,8 @@
return result;
}
- private void createSipDelegateInternal(int subId, DelegateRequest request, String packageName,
- ISipDelegateConnectionStateCallback delegateState,
+ private void createSipDelegateInternal(int subId, int uid, DelegateRequest request,
+ String packageName, ISipDelegateConnectionStateCallback delegateState,
ISipDelegateMessageCallback delegateMessage,
Consumer<ImsException> startedErrorConsumer) {
ISipTransport transport;
@@ -450,8 +451,9 @@
return;
}
- SipDelegateController c = mDelegateControllerFactory.create(subId, request, packageName,
- transport, registration, mExecutorService, delegateState, delegateMessage);
+ SipDelegateController c = mDelegateControllerFactory.create(subId, uid, request,
+ packageName, transport, registration, mExecutorService, delegateState,
+ delegateMessage);
logi("createSipDelegateInternal: request= " + request + ", packageName= " + packageName
+ ", controller created: " + c);
addPendingCreateAndEvaluate(c);