1 /* 2 * Copyright (C) 2021 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.telephony.qns; 18 19 import android.annotation.IntDef; 20 import android.os.Handler; 21 import android.os.Looper; 22 import android.os.Message; 23 import android.telephony.AccessNetworkConstants; 24 import android.telephony.PreciseDataConnectionState; 25 import android.telephony.TelephonyManager; 26 import android.telephony.data.ApnSetting; 27 import android.util.Log; 28 import android.util.SparseArray; 29 30 import com.android.internal.annotations.VisibleForTesting; 31 32 class DataConnectionStatusTracker { 33 private static final int EVENT_DATA_CONNECTION_STATE_CHANGED = 11001; 34 protected final int mSlotIndex; 35 private final String mLogTag; 36 private final int mNetCapability; 37 @VisibleForTesting protected final Handler mHandler; 38 private DataConnectionChangedInfo mLastUpdatedDcChangedInfo; 39 private final QnsTelephonyListener mQnsTelephonyListener; 40 static final int STATE_INACTIVE = 0; 41 static final int STATE_CONNECTING = 1; 42 static final int STATE_CONNECTED = 2; 43 static final int STATE_HANDOVER = 3; 44 45 @IntDef( 46 value = { 47 STATE_INACTIVE, 48 STATE_CONNECTING, 49 STATE_CONNECTED, 50 STATE_HANDOVER, 51 }) 52 @interface DataConnectionState {} 53 54 static final int EVENT_DATA_CONNECTION_DISCONNECTED = 0; 55 static final int EVENT_DATA_CONNECTION_STARTED = 1; 56 static final int EVENT_DATA_CONNECTION_CONNECTED = 2; 57 static final int EVENT_DATA_CONNECTION_FAILED = 3; 58 static final int EVENT_DATA_CONNECTION_HANDOVER_STARTED = 4; 59 static final int EVENT_DATA_CONNECTION_HANDOVER_SUCCESS = 5; 60 static final int EVENT_DATA_CONNECTION_HANDOVER_FAILED = 6; 61 62 @IntDef( 63 value = { 64 EVENT_DATA_CONNECTION_DISCONNECTED, 65 EVENT_DATA_CONNECTION_STARTED, 66 EVENT_DATA_CONNECTION_CONNECTED, 67 EVENT_DATA_CONNECTION_FAILED, 68 EVENT_DATA_CONNECTION_HANDOVER_STARTED, 69 EVENT_DATA_CONNECTION_HANDOVER_SUCCESS, 70 EVENT_DATA_CONNECTION_HANDOVER_FAILED, 71 }) 72 @interface DataConnectionChangedEvent {} 73 74 private final QnsRegistrantList mDataConnectionStatusRegistrants; 75 private int mState = STATE_INACTIVE; 76 private int mDataConnectionFailCause; 77 private int mTransportType = AccessNetworkConstants.TRANSPORT_TYPE_INVALID; 78 private SparseArray<ApnSetting> mLastApnSettings = new SparseArray<>(); 79 80 /** 81 * Constructor to instantiate CellularQualityMonitor 82 * 83 * @param qnsTelephonyListener QnsTelephonyListener instance 84 * @param looper looper to bind class' handler. 85 * @param slotIndex slot index 86 * @param netCapability integer value of network capability 87 */ DataConnectionStatusTracker( QnsTelephonyListener qnsTelephonyListener, Looper looper, int slotIndex, int netCapability)88 DataConnectionStatusTracker( 89 QnsTelephonyListener qnsTelephonyListener, 90 Looper looper, 91 int slotIndex, 92 int netCapability) { 93 mLogTag = 94 QnsConstants.QNS_TAG 95 + "_" 96 + DataConnectionStatusTracker.class.getSimpleName() 97 + "_" 98 + slotIndex 99 + "_" 100 + QnsUtils.getNameOfNetCapability(netCapability); 101 102 mSlotIndex = slotIndex; 103 mNetCapability = netCapability; 104 105 mHandler = new DataConnectionStatusTrackerHandler(looper); 106 mDataConnectionStatusRegistrants = new QnsRegistrantList(); 107 mQnsTelephonyListener = qnsTelephonyListener; 108 mQnsTelephonyListener.registerPreciseDataConnectionStateChanged( 109 mNetCapability, mHandler, EVENT_DATA_CONNECTION_STATE_CHANGED, null, true); 110 } 111 log(String s)112 protected void log(String s) { 113 Log.d(mLogTag, s); 114 } 115 isInactiveState()116 boolean isInactiveState() { 117 return mState == STATE_INACTIVE; 118 } 119 isActiveState()120 boolean isActiveState() { 121 return mState == STATE_CONNECTED || mState == STATE_HANDOVER; 122 } 123 isHandoverState()124 boolean isHandoverState() { 125 return mState == STATE_HANDOVER; 126 } 127 isConnectionInProgress()128 boolean isConnectionInProgress() { 129 return mState == STATE_CONNECTING || mState == STATE_HANDOVER; 130 } 131 getLastTransportType()132 int getLastTransportType() { 133 return mTransportType; 134 } 135 getLastFailCause()136 int getLastFailCause() { 137 return mDataConnectionFailCause; 138 } 139 140 /** Returns Latest APN setting for the transport type */ getLastApnSetting(int transportType)141 ApnSetting getLastApnSetting(int transportType) { 142 try { 143 return mLastApnSettings.get(transportType); 144 } catch (Exception e) { 145 return null; 146 } 147 } 148 registerDataConnectionStatusChanged(Handler h, int what)149 void registerDataConnectionStatusChanged(Handler h, int what) { 150 if (h != null) { 151 mDataConnectionStatusRegistrants.addUnique(h, what, null); 152 } 153 if (mLastUpdatedDcChangedInfo != null) { 154 QnsRegistrant r = new QnsRegistrant(h, what, null); 155 r.notifyResult(mLastUpdatedDcChangedInfo); 156 } 157 } 158 unRegisterDataConnectionStatusChanged(Handler h)159 void unRegisterDataConnectionStatusChanged(Handler h) { 160 if (h != null) { 161 mDataConnectionStatusRegistrants.remove(h); 162 } 163 } 164 onDataConnectionStateChanged(PreciseDataConnectionState status)165 private void onDataConnectionStateChanged(PreciseDataConnectionState status) { 166 int transportType = status.getTransportType(); 167 int state = status.getState(); 168 mDataConnectionFailCause = status.getLastCauseCode(); 169 log( 170 "onDataConnectionChanged transportType:" 171 + QnsConstants.transportTypeToString(transportType) 172 + " state:" 173 + QnsConstants.dataStateToString(status.getState()) 174 + " cause:" 175 + status.getLastCauseCode()); 176 177 switch (state) { 178 case TelephonyManager.DATA_DISCONNECTED: 179 if (mState == STATE_CONNECTED || mState == STATE_HANDOVER) { 180 mState = STATE_INACTIVE; 181 mTransportType = AccessNetworkConstants.TRANSPORT_TYPE_INVALID; 182 log("Connection Disconnected"); 183 notifyDataConnectionStatusChangedEvent(EVENT_DATA_CONNECTION_DISCONNECTED); 184 } else { 185 if (mState == STATE_CONNECTING) { 186 // Initial connect Failed. 187 mState = STATE_INACTIVE; 188 mTransportType = AccessNetworkConstants.TRANSPORT_TYPE_INVALID; 189 log("Initial connect failed"); 190 notifyDataConnectionFailed(transportType); 191 } 192 } 193 break; 194 195 case TelephonyManager.DATA_CONNECTING: 196 if (mState == STATE_INACTIVE) { 197 mState = STATE_CONNECTING; 198 log( 199 "Initial Connect inited transport: " 200 + QnsConstants.transportTypeToString(transportType)); 201 notifyDataConnectionStarted(transportType); 202 } 203 break; 204 205 case TelephonyManager.DATA_CONNECTED: 206 if (mState == STATE_CONNECTING || mState == STATE_INACTIVE) { 207 mState = STATE_CONNECTED; 208 mTransportType = transportType; 209 log( 210 "Data Connected Transport: " 211 + QnsConstants.transportTypeToString(mTransportType)); 212 notifyDataConnectionStatusChangedEvent(EVENT_DATA_CONNECTION_CONNECTED); 213 } else if (mState == STATE_HANDOVER && mTransportType != transportType) { 214 mState = STATE_CONNECTED; 215 mTransportType = transportType; 216 log( 217 "Handover completed to: " 218 + QnsConstants.transportTypeToString(mTransportType)); 219 notifyDataConnectionStatusChangedEvent(EVENT_DATA_CONNECTION_HANDOVER_SUCCESS); 220 } else if (mState == STATE_HANDOVER && mTransportType == transportType) { 221 mState = STATE_CONNECTED; 222 log( 223 "Handover failed and return to: " 224 + QnsConstants.transportTypeToString(mTransportType)); 225 notifyDataConnectionStatusChangedEvent(EVENT_DATA_CONNECTION_HANDOVER_FAILED); 226 } 227 break; 228 229 case TelephonyManager.DATA_SUSPENDED: 230 if (mState == STATE_HANDOVER && mTransportType != transportType) { 231 mState = STATE_CONNECTED; 232 mTransportType = transportType; 233 log( 234 "QNS assumes Handover completed to: " 235 + QnsConstants.transportTypeToString(mTransportType)); 236 notifyDataConnectionStatusChangedEvent(EVENT_DATA_CONNECTION_HANDOVER_SUCCESS); 237 } 238 break; 239 240 case TelephonyManager.DATA_HANDOVER_IN_PROGRESS: 241 if (mState == STATE_CONNECTED && mTransportType == transportType) { 242 mState = STATE_HANDOVER; 243 log( 244 "Handover initiated from " 245 + QnsConstants.transportTypeToString(transportType)); 246 notifyDataConnectionStatusChangedEvent(EVENT_DATA_CONNECTION_HANDOVER_STARTED); 247 } else { 248 log( 249 "Ignore STATE_HANDOVER since request is not for Src TransportType: " 250 + QnsConstants.transportTypeToString(mTransportType)); 251 } 252 break; 253 254 default: 255 break; 256 } 257 mLastApnSettings.put(mTransportType, status.getApnSetting()); 258 } 259 notifyDataConnectionStarted(int transportType)260 private void notifyDataConnectionStarted(int transportType) { 261 DataConnectionChangedInfo info = 262 new DataConnectionChangedInfo(EVENT_DATA_CONNECTION_STARTED, mState, transportType); 263 mLastUpdatedDcChangedInfo = info; 264 mDataConnectionStatusRegistrants.notifyResult(info); 265 } 266 notifyDataConnectionFailed(int transportType)267 private void notifyDataConnectionFailed(int transportType) { 268 DataConnectionChangedInfo info = 269 new DataConnectionChangedInfo(EVENT_DATA_CONNECTION_FAILED, mState, transportType); 270 mLastUpdatedDcChangedInfo = info; 271 mDataConnectionStatusRegistrants.notifyResult(info); 272 } 273 notifyDataConnectionStatusChangedEvent(int event)274 private void notifyDataConnectionStatusChangedEvent(int event) { 275 DataConnectionChangedInfo info = 276 new DataConnectionChangedInfo(event, mState, mTransportType); 277 mLastUpdatedDcChangedInfo = info; 278 mDataConnectionStatusRegistrants.notifyResult(info); 279 } 280 close()281 void close() { 282 mQnsTelephonyListener.unregisterPreciseDataConnectionStateChanged(mNetCapability, mHandler); 283 mDataConnectionStatusRegistrants.removeAll(); 284 } 285 stateToString(int state)286 static String stateToString(int state) { 287 switch (state) { 288 case STATE_INACTIVE: 289 return "STATE_INCATIVE"; 290 case STATE_CONNECTING: 291 return "STATE_CONNCTING"; 292 case STATE_CONNECTED: 293 return "STATE_CONNECTED"; 294 case STATE_HANDOVER: 295 return "STATE_HANDOVER"; 296 } 297 return "INVALID"; 298 } 299 eventToString(int event)300 static String eventToString(int event) { 301 switch (event) { 302 case EVENT_DATA_CONNECTION_DISCONNECTED: 303 return "EVENT_DATA_CONNECTION_DISCONNECTED"; 304 case EVENT_DATA_CONNECTION_STARTED: 305 return "EVENT_DATA_CONNECTION_STARTED"; 306 case EVENT_DATA_CONNECTION_CONNECTED: 307 return "EVENT_DATA_CONNECTION_CONNECTED"; 308 case EVENT_DATA_CONNECTION_FAILED: 309 return "EVENT_DATA_CONNECTION_FAILED"; 310 case EVENT_DATA_CONNECTION_HANDOVER_STARTED: 311 return "EVENT_DATA_CONNECTION_HANDOVER_STARTED"; 312 case EVENT_DATA_CONNECTION_HANDOVER_SUCCESS: 313 return "EVENT_DATA_CONNECTION_HANDOVER_SUCCESS"; 314 case EVENT_DATA_CONNECTION_HANDOVER_FAILED: 315 return "EVENT_DATA_CONNECTION_HANDOVER_FAILED"; 316 } 317 return "INVALID"; 318 } 319 320 static class DataConnectionChangedInfo { 321 private final int mEvent; 322 private final int mState; 323 private final int mCurrentTransportType; 324 325 @Override toString()326 public String toString() { 327 return "DataConnectionChangedInfo{" 328 + "mEvent=" 329 + eventToString(mEvent) 330 + ", mState=" 331 + stateToString(mState) 332 + ", mCurrentTransportType=" 333 + QnsConstants.transportTypeToString(mCurrentTransportType) 334 + '}'; 335 } 336 DataConnectionChangedInfo( @ataConnectionChangedEvent int event, @DataConnectionState int state, @AccessNetworkConstants.TransportType int transportType)337 DataConnectionChangedInfo( 338 @DataConnectionChangedEvent int event, 339 @DataConnectionState int state, 340 @AccessNetworkConstants.TransportType int transportType) { 341 mEvent = event; 342 mState = state; 343 mCurrentTransportType = transportType; 344 } 345 getState()346 int getState() { 347 return mState; 348 } 349 getEvent()350 int getEvent() { 351 return mEvent; 352 } 353 getTransportType()354 int getTransportType() { 355 return mCurrentTransportType; 356 } 357 } 358 359 class DataConnectionStatusTrackerHandler extends Handler { DataConnectionStatusTrackerHandler(Looper l)360 DataConnectionStatusTrackerHandler(Looper l) { 361 super(l); 362 } 363 364 @Override handleMessage(Message message)365 public void handleMessage(Message message) { 366 log("handleMessage msg=" + message.what); 367 QnsAsyncResult ar = (QnsAsyncResult) message.obj; 368 switch (message.what) { 369 case EVENT_DATA_CONNECTION_STATE_CHANGED: 370 onDataConnectionStateChanged((PreciseDataConnectionState) ar.mResult); 371 break; 372 default: 373 log("never reach here msg=" + message.what); 374 } 375 } 376 } 377 } 378