1 /* 2 * Copyright (C) 2020 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.services.telephony.rcs; 18 19 import android.app.compat.CompatChanges; 20 import android.compat.annotation.ChangeId; 21 import android.compat.annotation.EnabledAfter; 22 import android.os.Build; 23 import android.os.RemoteException; 24 import android.telephony.ims.DelegateRegistrationState; 25 import android.telephony.ims.FeatureTagState; 26 import android.telephony.ims.SipDelegateConfiguration; 27 import android.telephony.ims.SipDelegateImsConfiguration; 28 import android.telephony.ims.aidl.ISipDelegate; 29 import android.telephony.ims.aidl.ISipDelegateConnectionStateCallback; 30 import android.telephony.ims.stub.DelegateConnectionStateCallback; 31 import android.util.ArraySet; 32 import android.util.LocalLog; 33 import android.util.Log; 34 35 import com.android.internal.annotations.VisibleForTesting; 36 import com.android.internal.telephony.metrics.RcsStats; 37 38 import java.io.PrintWriter; 39 import java.util.ArrayList; 40 import java.util.List; 41 import java.util.Set; 42 43 /** 44 * Manages the events sent back to the remote IMS application using the AIDL backing for the 45 * {@link DelegateConnectionStateCallback} interface. 46 */ 47 public class DelegateStateTracker implements DelegateBinderStateManager.StateCallback { 48 private static final String LOG_TAG = "DelegateST"; 49 50 private final int mSubId; 51 private final int mUid; 52 private final ISipDelegateConnectionStateCallback mAppStateCallback; 53 private final ISipDelegate mLocalDelegateImpl; 54 55 private final LocalLog mLocalLog = new LocalLog(SipTransportController.LOG_SIZE); 56 57 private final RcsStats mRcsStats; 58 59 private List<FeatureTagState> mDelegateDeniedTags; 60 private DelegateRegistrationState mLastRegState; 61 private boolean mCreatedCalled = false; 62 private int mRegistrationStateOverride = -1; 63 private CompatChangesFactory mCompatChangesFactory; 64 private Set<String> mDelegateSupportedTags; 65 66 /** 67 * Interface for checking compatibility of apps 68 */ 69 public interface CompatChangesFactory { 70 /** 71 * @param changeId The ID of the compatibility change. 72 * @param uid The UID of the app. 73 * @return {@code true} if the change is enabled for the current app. 74 */ isChangeEnabled(long changeId, int uid)75 boolean isChangeEnabled(long changeId, int uid); 76 } 77 78 /** 79 * For apps targeting Android T and above, support the REGISTERING state on APIs, such as 80 * {@code DelegateRegistrationState#addRegisteringFeatureTags} and 81 * {@code DelegateRegistrationState#getRegisteringFeatureTags} 82 * @hide 83 */ 84 @ChangeId 85 @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S) 86 @VisibleForTesting 87 public static final long SUPPORT_REGISTERING_DELEGATE_STATE = 205194548; 88 89 /** 90 * For apps targeting Android T and above, support the DEREGISTERING_REASON_LOSING_PDN state 91 * on APIs, such as {@code DelegateRegistrationState#addDeregisteringFeatureTag} and 92 * {@code DelegateRegistrationState#getDeregisteringFeatureTags} 93 * @hide 94 */ 95 @ChangeId 96 @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S) 97 @VisibleForTesting 98 public static final long SUPPORT_DEREGISTERING_LOSING_PDN_STATE = 201522903; 99 DelegateStateTracker(int subId, int uid, ISipDelegateConnectionStateCallback appStateCallback, ISipDelegate localDelegateImpl, RcsStats rcsStats)100 public DelegateStateTracker(int subId, int uid, 101 ISipDelegateConnectionStateCallback appStateCallback, 102 ISipDelegate localDelegateImpl, RcsStats rcsStats) { 103 mSubId = subId; 104 mUid = uid; 105 mAppStateCallback = appStateCallback; 106 mLocalDelegateImpl = localDelegateImpl; 107 mRcsStats = rcsStats; 108 setCompatChangesFactory((changeId, uid1) -> CompatChanges.isChangeEnabled(changeId, uid1)); 109 } 110 111 @VisibleForTesting setCompatChangesFactory(CompatChangesFactory factory)112 protected void setCompatChangesFactory(CompatChangesFactory factory) { 113 mCompatChangesFactory = factory; 114 } 115 116 /** 117 * Notify this state tracker that a new internal SipDelegate has been connected. 118 * 119 * Registration and state updates will be send via the 120 * {@link SipDelegateBinderConnection.StateCallback} callback implemented by this class as they 121 * arrive. 122 * @param supportedTags the tags supported by the SipTransportController and ImsService creating 123 * the SipDelegate. These tags will be used as a key for SipDelegate 124 * metrics. 125 * @param deniedTags The tags denied by the SipTransportController and ImsService creating the 126 * SipDelegate. These tags will need to be notified back to the IMS application. 127 */ sipDelegateConnected(Set<String> supportedTags, Set<FeatureTagState> deniedTags)128 public void sipDelegateConnected(Set<String> supportedTags, Set<FeatureTagState> deniedTags) { 129 logi("SipDelegate connected with denied tags:" + deniedTags); 130 // From the IMS application perspective, we only call onCreated/onDestroyed once and 131 // provide the local implementation of ISipDelegate, which doesn't change, even though 132 // SipDelegates may be changing underneath. 133 if (!mCreatedCalled) { 134 mCreatedCalled = true; 135 notifySipDelegateCreated(); 136 mDelegateSupportedTags = supportedTags; 137 mRcsStats.createSipDelegateStats(mSubId, mDelegateSupportedTags); 138 } 139 mRegistrationStateOverride = -1; 140 mDelegateDeniedTags = new ArrayList<>(deniedTags); 141 } 142 143 /** 144 * The underlying SipDelegate is changing due to a state change in the SipDelegateController. 145 * 146 * This will trigger an override of the IMS application's registration state. All feature tags 147 * in the REGISTERED state will be overridden to move to the deregistering state specified until 148 * a new SipDelegate was successfully created and {@link #sipDelegateConnected(Set, Set)} was 149 * called or it was destroyed and {@link #sipDelegateDestroyed(int)} was called. 150 * @param deregisteringReason The new deregistering reason that all feature tags in the 151 * registered state should now report. 152 */ sipDelegateChanging(int deregisteringReason)153 public void sipDelegateChanging(int deregisteringReason) { 154 logi("SipDelegate Changing"); 155 mRegistrationStateOverride = deregisteringReason; 156 if (mLastRegState == null) { 157 logw("sipDelegateChanging: invalid state, onRegistrationStateChanged never called."); 158 mLastRegState = new DelegateRegistrationState.Builder().build(); 159 } 160 onRegistrationStateChanged(mLastRegState); 161 } 162 163 /** 164 * The underlying SipDelegate has been destroyed. 165 * 166 * This should only be called when the entire {@link SipDelegateController} is going down 167 * because the application has requested that the SipDelegate be destroyed. 168 * 169 * This can also be called in error conditions where the IMS application or ImsService has 170 * crashed. 171 * @param reason The reason that will be sent to the IMS application for why the SipDelegate 172 * is being destroyed. 173 */ sipDelegateDestroyed(int reason)174 public void sipDelegateDestroyed(int reason) { 175 logi("SipDelegate destroyed:" + reason); 176 mRegistrationStateOverride = -1; 177 try { 178 mAppStateCallback.onDestroyed(reason); 179 mRcsStats.onSipDelegateStats(mSubId, mDelegateSupportedTags, reason); 180 } catch (RemoteException e) { 181 logw("sipDelegateDestroyed: IMS application is dead: " + e); 182 } 183 } 184 185 /** 186 * The underlying SipDelegate has reported that its registration state has changed. 187 * @param registrationState The RegistrationState reported by the SipDelegate to be sent to the 188 * IMS application. 189 */ 190 @Override onRegistrationStateChanged(DelegateRegistrationState registrationState)191 public void onRegistrationStateChanged(DelegateRegistrationState registrationState) { 192 if (!mCompatChangesFactory.isChangeEnabled(SUPPORT_DEREGISTERING_LOSING_PDN_STATE, mUid)) { 193 registrationState = overrideDeregisteringStateForCompatibility(registrationState); 194 } 195 if (!mCompatChangesFactory.isChangeEnabled(SUPPORT_REGISTERING_DELEGATE_STATE, mUid)) { 196 registrationState = overrideRegistrationForCompatibility(registrationState); 197 } 198 199 if (mRegistrationStateOverride > DelegateRegistrationState.DEREGISTERED_REASON_UNKNOWN) { 200 logi("onRegistrationStateChanged: overriding registered state to " 201 + mRegistrationStateOverride); 202 registrationState = overrideRegistrationForDelegateChange(mRegistrationStateOverride, 203 registrationState); 204 } 205 if (registrationState.equals(mLastRegState)) { 206 logi("onRegistrationStateChanged: skipping notification, state is the same."); 207 return; 208 } 209 mLastRegState = registrationState; 210 logi("onRegistrationStateChanged: sending reg state " + registrationState); 211 try { 212 mAppStateCallback.onFeatureTagStatusChanged(registrationState, mDelegateDeniedTags); 213 Set<String> registeredFeatureTags = registrationState.getRegisteredFeatureTags(); 214 mRcsStats.onSipTransportFeatureTagStats(mSubId, 215 new ArraySet<FeatureTagState>(mDelegateDeniedTags), 216 registrationState.getDeregisteredFeatureTags(), 217 registeredFeatureTags); 218 } catch (RemoteException e) { 219 logw("onRegistrationStateChanged: IMS application is dead: " + e); 220 } 221 } 222 223 /** 224 * THe underlying SipDelegate has reported that the IMS configuration has changed. 225 * @param config The config to be sent to the IMS application. 226 */ 227 @Override onImsConfigurationChanged(SipDelegateImsConfiguration config)228 public void onImsConfigurationChanged(SipDelegateImsConfiguration config) { 229 logi("onImsConfigurationChanged: Sending new IMS configuration."); 230 try { 231 mAppStateCallback.onImsConfigurationChanged(config); 232 } catch (RemoteException e) { 233 logw("onImsConfigurationChanged: IMS application is dead: " + e); 234 } 235 } 236 237 /** 238 * THe underlying SipDelegate has reported that the IMS configuration has changed. 239 * @param config The config to be sent to the IMS application. 240 */ 241 @Override onConfigurationChanged(SipDelegateConfiguration config)242 public void onConfigurationChanged(SipDelegateConfiguration config) { 243 logi("onImsConfigurationChanged: Sending new IMS configuration."); 244 try { 245 mAppStateCallback.onConfigurationChanged(config); 246 } catch (RemoteException e) { 247 logw("onImsConfigurationChanged: IMS application is dead: " + e); 248 } 249 } 250 251 /** Write state about this tracker into the PrintWriter to be included in the dumpsys */ dump(PrintWriter printWriter)252 public void dump(PrintWriter printWriter) { 253 printWriter.println("Last reg state: " + mLastRegState); 254 printWriter.println("Denied tags: " + mDelegateDeniedTags); 255 printWriter.println(); 256 printWriter.println("Most recent logs: "); 257 mLocalLog.dump(printWriter); 258 } 259 overrideRegistrationForDelegateChange( int registerOverrideReason, DelegateRegistrationState state)260 private DelegateRegistrationState overrideRegistrationForDelegateChange( 261 int registerOverrideReason, DelegateRegistrationState state) { 262 Set<String> registeredFeatures = state.getRegisteredFeatureTags(); 263 Set<String> registeringFeatures = state.getRegisteringFeatureTags(); 264 DelegateRegistrationState.Builder overriddenState = new DelegateRegistrationState.Builder(); 265 // keep other deregistering/deregistered tags the same. 266 for (FeatureTagState dereging : state.getDeregisteringFeatureTags()) { 267 overriddenState.addDeregisteringFeatureTag(dereging.getFeatureTag(), 268 dereging.getState()); 269 } 270 for (FeatureTagState dereged : state.getDeregisteredFeatureTags()) { 271 overriddenState.addDeregisteredFeatureTag(dereged.getFeatureTag(), 272 dereged.getState()); 273 } 274 // Override REGISTERING/REGISTERED 275 for (String ft : registeringFeatures) { 276 overriddenState.addDeregisteringFeatureTag(ft, registerOverrideReason); 277 } 278 for (String ft : registeredFeatures) { 279 overriddenState.addDeregisteringFeatureTag(ft, registerOverrideReason); 280 } 281 return overriddenState.build(); 282 } 283 overrideRegistrationForCompatibility( DelegateRegistrationState state)284 private DelegateRegistrationState overrideRegistrationForCompatibility( 285 DelegateRegistrationState state) { 286 Set<String> registeredFeatures = state.getRegisteredFeatureTags(); 287 Set<String> registeringFeatures = state.getRegisteringFeatureTags(); 288 DelegateRegistrationState.Builder overriddenState = new DelegateRegistrationState.Builder(); 289 // keep other registered/deregistering/deregistered tags the same. 290 for (FeatureTagState dereging : state.getDeregisteringFeatureTags()) { 291 overriddenState.addDeregisteringFeatureTag(dereging.getFeatureTag(), 292 dereging.getState()); 293 } 294 for (FeatureTagState dereged : state.getDeregisteredFeatureTags()) { 295 overriddenState.addDeregisteredFeatureTag(dereged.getFeatureTag(), 296 dereged.getState()); 297 } 298 overriddenState.addRegisteredFeatureTags(registeredFeatures); 299 300 // move the REGISTERING state to the DEREGISTERED state. 301 for (String tag : registeringFeatures) { 302 overriddenState.addDeregisteredFeatureTag(tag, 303 DelegateRegistrationState.DEREGISTERED_REASON_NOT_REGISTERED); 304 } 305 306 return overriddenState.build(); 307 } 308 309 /** 310 * @param state The RegistrationState reported by the SipDelegate to be sent to the 311 * IMS application . 312 * @return DEREGISTERING_REASON_PDN_CHANGE instead of DEREGISTERING_REASON_LOSING_PDN 313 * if the SUPPORT_DEREGISTERING_LOSING_PDN_STATE compat key is not enabled for the application 314 * consuming the registration change events. 315 */ overrideDeregisteringStateForCompatibility( DelegateRegistrationState state)316 private DelegateRegistrationState overrideDeregisteringStateForCompatibility( 317 DelegateRegistrationState state) { 318 Set<String> registeredFeatures = state.getRegisteredFeatureTags(); 319 Set<String> registeringFeatures = state.getRegisteringFeatureTags(); 320 DelegateRegistrationState.Builder overriddenState = new DelegateRegistrationState.Builder(); 321 322 // keep other registered/registering/deregistered tags the same. 323 for (FeatureTagState dereged : state.getDeregisteredFeatureTags()) { 324 overriddenState.addDeregisteredFeatureTag(dereged.getFeatureTag(), 325 dereged.getState()); 326 } 327 overriddenState.addRegisteredFeatureTags(registeredFeatures); 328 overriddenState.addRegisteringFeatureTags(registeringFeatures); 329 330 // change DEREGISTERING_REASON_LOSING_PDN to DEREGISTERING_REASON_PDN_CHANGE 331 for (FeatureTagState dereging : state.getDeregisteringFeatureTags()) { 332 overriddenState.addDeregisteringFeatureTag(dereging.getFeatureTag(), 333 getDeregisteringReasonForCompatibility(dereging.getState())); 334 } 335 336 return overriddenState.build(); 337 } 338 getDeregisteringReasonForCompatibility(int reason)339 private int getDeregisteringReasonForCompatibility(int reason) { 340 if (reason == DelegateRegistrationState.DEREGISTERING_REASON_LOSING_PDN) { 341 reason = DelegateRegistrationState.DEREGISTERING_REASON_PDN_CHANGE; 342 } 343 return reason; 344 } 345 notifySipDelegateCreated()346 private void notifySipDelegateCreated() { 347 try { 348 mAppStateCallback.onCreated(mLocalDelegateImpl); 349 } catch (RemoteException e) { 350 logw("notifySipDelegateCreated: IMS application is dead: " + e); 351 } 352 } 353 logi(String log)354 private void logi(String log) { 355 Log.i(SipTransportController.LOG_TAG, LOG_TAG + "[" + mSubId + "] " + log); 356 mLocalLog.log("[I] " + log); 357 } logw(String log)358 private void logw(String log) { 359 Log.w(SipTransportController.LOG_TAG, LOG_TAG + "[" + mSubId + "] " + log); 360 mLocalLog.log("[W] " + log); 361 } 362 } 363