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