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.os.RemoteException; 20 import android.telephony.ims.DelegateRegistrationState; 21 import android.telephony.ims.FeatureTagState; 22 import android.telephony.ims.SipDelegateConfiguration; 23 import android.telephony.ims.SipDelegateImsConfiguration; 24 import android.telephony.ims.aidl.ISipDelegate; 25 import android.telephony.ims.aidl.ISipDelegateConnectionStateCallback; 26 import android.telephony.ims.stub.DelegateConnectionStateCallback; 27 import android.util.ArraySet; 28 import android.util.LocalLog; 29 import android.util.Log; 30 31 import com.android.internal.telephony.metrics.RcsStats; 32 33 import java.io.PrintWriter; 34 import java.util.ArrayList; 35 import java.util.List; 36 import java.util.Set; 37 38 /** 39 * Manages the events sent back to the remote IMS application using the AIDL backing for the 40 * {@link DelegateConnectionStateCallback} interface. 41 */ 42 public class DelegateStateTracker implements DelegateBinderStateManager.StateCallback { 43 private static final String LOG_TAG = "DelegateST"; 44 45 private final int mSubId; 46 private final ISipDelegateConnectionStateCallback mAppStateCallback; 47 private final ISipDelegate mLocalDelegateImpl; 48 49 private final LocalLog mLocalLog = new LocalLog(SipTransportController.LOG_SIZE); 50 51 private List<FeatureTagState> mDelegateDeniedTags; 52 private DelegateRegistrationState mLastRegState; 53 private boolean mCreatedCalled = false; 54 private int mRegistrationStateOverride = -1; 55 56 private Set<String> mDelegateSupportedTags; 57 private final RcsStats mRcsStats; 58 DelegateStateTracker(int subId, ISipDelegateConnectionStateCallback appStateCallback, ISipDelegate localDelegateImpl, RcsStats rcsStats)59 public DelegateStateTracker(int subId, ISipDelegateConnectionStateCallback appStateCallback, 60 ISipDelegate localDelegateImpl, RcsStats rcsStats) { 61 mSubId = subId; 62 mAppStateCallback = appStateCallback; 63 mLocalDelegateImpl = localDelegateImpl; 64 mRcsStats = rcsStats; 65 } 66 67 /** 68 * Notify this state tracker that a new internal SipDelegate has been connected. 69 * 70 * Registration and state updates will be send via the 71 * {@link SipDelegateBinderConnection.StateCallback} callback implemented by this class as they 72 * arrive. 73 * @param supportedTags the tags supported by the SipTransportController and ImsService creating 74 * the SipDelegate. These tags will be used as a key for SipDelegate 75 * metrics. 76 * @param deniedTags The tags denied by the SipTransportController and ImsService creating the 77 * SipDelegate. These tags will need to be notified back to the IMS application. 78 */ sipDelegateConnected(Set<String> supportedTags, Set<FeatureTagState> deniedTags)79 public void sipDelegateConnected(Set<String> supportedTags, Set<FeatureTagState> deniedTags) { 80 logi("SipDelegate connected with denied tags:" + deniedTags); 81 // From the IMS application perspective, we only call onCreated/onDestroyed once and 82 // provide the local implementation of ISipDelegate, which doesn't change, even though 83 // SipDelegates may be changing underneath. 84 if (!mCreatedCalled) { 85 mCreatedCalled = true; 86 notifySipDelegateCreated(); 87 mDelegateSupportedTags = supportedTags; 88 mRcsStats.createSipDelegateStats(mSubId, mDelegateSupportedTags); 89 } 90 mRegistrationStateOverride = -1; 91 mDelegateDeniedTags = new ArrayList<>(deniedTags); 92 } 93 94 /** 95 * The underlying SipDelegate is changing due to a state change in the SipDelegateController. 96 * 97 * This will trigger an override of the IMS application's registration state. All feature tags 98 * in the REGISTERED state will be overridden to move to the deregistering state specified until 99 * a new SipDelegate was successfully created and {@link #sipDelegateConnected(Set, Set)} was 100 * called or it was destroyed and {@link #sipDelegateDestroyed(int)} was called. 101 * @param deregisteringReason The new deregistering reason that all feature tags in the 102 * registered state should now report. 103 */ sipDelegateChanging(int deregisteringReason)104 public void sipDelegateChanging(int deregisteringReason) { 105 logi("SipDelegate Changing"); 106 mRegistrationStateOverride = deregisteringReason; 107 if (mLastRegState == null) { 108 logw("sipDelegateChanging: invalid state, onRegistrationStateChanged never called."); 109 mLastRegState = new DelegateRegistrationState.Builder().build(); 110 } 111 onRegistrationStateChanged(mLastRegState); 112 } 113 114 /** 115 * The underlying SipDelegate has been destroyed. 116 * 117 * This should only be called when the entire {@link SipDelegateController} is going down 118 * because the application has requested that the SipDelegate be destroyed. 119 * 120 * This can also be called in error conditions where the IMS application or ImsService has 121 * crashed. 122 * @param reason The reason that will be sent to the IMS application for why the SipDelegate 123 * is being destroyed. 124 */ sipDelegateDestroyed(int reason)125 public void sipDelegateDestroyed(int reason) { 126 logi("SipDelegate destroyed:" + reason); 127 mRegistrationStateOverride = -1; 128 try { 129 mAppStateCallback.onDestroyed(reason); 130 mRcsStats.onSipDelegateStats(mSubId, mDelegateSupportedTags, reason); 131 } catch (RemoteException e) { 132 logw("sipDelegateDestroyed: IMS application is dead: " + e); 133 } 134 } 135 136 /** 137 * The underlying SipDelegate has reported that its registration state has changed. 138 * @param registrationState The RegistrationState reported by the SipDelegate to be sent to the 139 * IMS application. 140 */ 141 @Override onRegistrationStateChanged(DelegateRegistrationState registrationState)142 public void onRegistrationStateChanged(DelegateRegistrationState registrationState) { 143 if (mRegistrationStateOverride > DelegateRegistrationState.DEREGISTERED_REASON_UNKNOWN) { 144 logi("onRegistrationStateChanged: overriding registered state to " 145 + mRegistrationStateOverride); 146 registrationState = overrideRegistrationForDelegateChange(mRegistrationStateOverride, 147 registrationState); 148 } 149 if (registrationState.equals(mLastRegState)) { 150 logi("onRegistrationStateChanged: skipping notification, state is the same."); 151 return; 152 } 153 mLastRegState = registrationState; 154 logi("onRegistrationStateChanged: sending reg state " + registrationState); 155 try { 156 mAppStateCallback.onFeatureTagStatusChanged(registrationState, mDelegateDeniedTags); 157 Set<String> registeredFeatureTags = registrationState.getRegisteredFeatureTags(); 158 mRcsStats.onSipTransportFeatureTagStats(mSubId, 159 new ArraySet<FeatureTagState>(mDelegateDeniedTags), 160 registrationState.getDeregisteredFeatureTags(), 161 registeredFeatureTags); 162 } catch (RemoteException e) { 163 logw("onRegistrationStateChanged: IMS application is dead: " + e); 164 } 165 } 166 167 /** 168 * THe underlying SipDelegate has reported that the IMS configuration has changed. 169 * @param config The config to be sent to the IMS application. 170 */ 171 @Override onImsConfigurationChanged(SipDelegateImsConfiguration config)172 public void onImsConfigurationChanged(SipDelegateImsConfiguration config) { 173 logi("onImsConfigurationChanged: Sending new IMS configuration."); 174 try { 175 mAppStateCallback.onImsConfigurationChanged(config); 176 } catch (RemoteException e) { 177 logw("onImsConfigurationChanged: IMS application is dead: " + e); 178 } 179 } 180 181 /** 182 * THe underlying SipDelegate has reported that the IMS configuration has changed. 183 * @param config The config to be sent to the IMS application. 184 */ 185 @Override onConfigurationChanged(SipDelegateConfiguration config)186 public void onConfigurationChanged(SipDelegateConfiguration config) { 187 logi("onImsConfigurationChanged: Sending new IMS configuration."); 188 try { 189 mAppStateCallback.onConfigurationChanged(config); 190 } catch (RemoteException e) { 191 logw("onImsConfigurationChanged: IMS application is dead: " + e); 192 } 193 } 194 195 /** Write state about this tracker into the PrintWriter to be included in the dumpsys */ dump(PrintWriter printWriter)196 public void dump(PrintWriter printWriter) { 197 printWriter.println("Last reg state: " + mLastRegState); 198 printWriter.println("Denied tags: " + mDelegateDeniedTags); 199 printWriter.println(); 200 printWriter.println("Most recent logs: "); 201 mLocalLog.dump(printWriter); 202 } 203 overrideRegistrationForDelegateChange( int registerOverrideReason, DelegateRegistrationState state)204 private DelegateRegistrationState overrideRegistrationForDelegateChange( 205 int registerOverrideReason, DelegateRegistrationState state) { 206 Set<String> registeredFeatures = state.getRegisteredFeatureTags(); 207 DelegateRegistrationState.Builder overriddenState = new DelegateRegistrationState.Builder(); 208 // keep other deregistering/deregistered tags the same. 209 for (FeatureTagState dereging : state.getDeregisteringFeatureTags()) { 210 overriddenState.addDeregisteringFeatureTag(dereging.getFeatureTag(), 211 dereging.getState()); 212 } 213 for (FeatureTagState dereged : state.getDeregisteredFeatureTags()) { 214 overriddenState.addDeregisteredFeatureTag(dereged.getFeatureTag(), 215 dereged.getState()); 216 } 217 // Override REGISTERED only 218 for (String ft : registeredFeatures) { 219 overriddenState.addDeregisteringFeatureTag(ft, registerOverrideReason); 220 } 221 return overriddenState.build(); 222 } 223 notifySipDelegateCreated()224 private void notifySipDelegateCreated() { 225 try { 226 mAppStateCallback.onCreated(mLocalDelegateImpl); 227 } catch (RemoteException e) { 228 logw("notifySipDelegateCreated: IMS application is dead: " + e); 229 } 230 } 231 logi(String log)232 private void logi(String log) { 233 Log.i(SipTransportController.LOG_TAG, LOG_TAG + "[" + mSubId + "] " + log); 234 mLocalLog.log("[I] " + log); 235 } logw(String log)236 private void logw(String log) { 237 Log.w(SipTransportController.LOG_TAG, LOG_TAG + "[" + mSubId + "] " + log); 238 mLocalLog.log("[W] " + log); 239 } 240 } 241