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.internal.telephony.metrics; 18 19 import static android.telephony.TelephonyManager.DATA_CONNECTED; 20 21 import static com.android.internal.telephony.TelephonyStatsLog.VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_CS; 22 import static com.android.internal.telephony.TelephonyStatsLog.VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_IMS; 23 import static com.android.internal.telephony.TelephonyStatsLog.VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_UNKNOWN; 24 25 import android.annotation.NonNull; 26 import android.annotation.Nullable; 27 import android.os.SystemClock; 28 import android.telephony.AccessNetworkConstants; 29 import android.telephony.AccessNetworkUtils; 30 import android.telephony.Annotation.NetworkType; 31 import android.telephony.NetworkRegistrationInfo; 32 import android.telephony.ServiceState; 33 import android.telephony.ServiceState.RoamingType; 34 import android.telephony.SubscriptionManager; 35 import android.telephony.TelephonyManager; 36 import android.telephony.ims.stub.ImsRegistrationImplBase; 37 38 import com.android.internal.annotations.VisibleForTesting; 39 import com.android.internal.telephony.Phone; 40 import com.android.internal.telephony.PhoneFactory; 41 import com.android.internal.telephony.ServiceStateTracker; 42 import com.android.internal.telephony.TelephonyStatsLog; 43 import com.android.internal.telephony.data.DataNetwork; 44 import com.android.internal.telephony.data.DataNetworkController; 45 import com.android.internal.telephony.data.DataNetworkController.DataNetworkControllerCallback; 46 import com.android.internal.telephony.imsphone.ImsPhone; 47 import com.android.internal.telephony.nano.PersistAtomsProto.CellularDataServiceSwitch; 48 import com.android.internal.telephony.nano.PersistAtomsProto.CellularServiceState; 49 import com.android.internal.telephony.satellite.SatelliteController; 50 import com.android.telephony.Rlog; 51 52 import java.util.Set; 53 import java.util.concurrent.atomic.AtomicBoolean; 54 import java.util.concurrent.atomic.AtomicReference; 55 56 /** Tracks service state duration and switch metrics for each phone. */ 57 public class ServiceStateStats extends DataNetworkControllerCallback { 58 private static final String TAG = ServiceStateStats.class.getSimpleName(); 59 60 private final AtomicReference<TimestampedServiceState> mLastState = 61 new AtomicReference<>(new TimestampedServiceState(null, 0L)); 62 private final AtomicBoolean mOverrideVoiceService = new AtomicBoolean(false); 63 private final Phone mPhone; 64 private final PersistAtomsStorage mStorage; 65 private final DeviceStateHelper mDeviceStateHelper; 66 private boolean mExistAnyConnectedInternetPdn; 67 private int mCurrentDataRat = 68 TelephonyStatsLog.DATA_RAT_STATE_CHANGED__DATA_RAT__DATA_RAT_UNSPECIFIED; 69 ServiceStateStats(Phone phone)70 public ServiceStateStats(Phone phone) { 71 super(Runnable::run); 72 mPhone = phone; 73 mStorage = PhoneFactory.getMetricsCollector().getAtomsStorage(); 74 mDeviceStateHelper = PhoneFactory.getMetricsCollector().getDeviceStateHelper(); 75 } 76 77 /** Finalizes the durations of the current service state segment. */ conclude()78 public void conclude() { 79 final long now = getTimeMillis(); 80 TimestampedServiceState lastState = 81 mLastState.getAndUpdate( 82 state -> new TimestampedServiceState(state.mServiceState, now)); 83 addServiceState(lastState, now); 84 } 85 86 /** Updates service state when IMS voice registration changes. */ onImsVoiceRegistrationChanged()87 public void onImsVoiceRegistrationChanged() { 88 final long now = getTimeMillis(); 89 TimestampedServiceState lastState = 90 mLastState.getAndUpdate( 91 state -> { 92 if (state.mServiceState == null) { 93 return new TimestampedServiceState(null, now); 94 } 95 CellularServiceState newServiceState = copyOf(state.mServiceState); 96 newServiceState.voiceRat = 97 getVoiceRat(mPhone, getServiceStateForPhone(mPhone)); 98 newServiceState.isIwlanCrossSim = isCrossSimCallingRegistered(mPhone); 99 return new TimestampedServiceState(newServiceState, now); 100 }); 101 addServiceState(lastState, now); 102 } 103 104 /** Registers for internet pdn connected callback. */ registerDataNetworkControllerCallback()105 public void registerDataNetworkControllerCallback() { 106 mPhone.getDataNetworkController().registerDataNetworkControllerCallback(this); 107 } 108 109 /** Updates service state when internet pdn changed. */ 110 @Override onConnectedInternetDataNetworksChanged(@onNull Set<DataNetwork> internetNetworks)111 public void onConnectedInternetDataNetworksChanged(@NonNull Set<DataNetwork> internetNetworks) { 112 boolean existAnyConnectedInternetPdn = !internetNetworks.isEmpty(); 113 if (mExistAnyConnectedInternetPdn != existAnyConnectedInternetPdn) { 114 mExistAnyConnectedInternetPdn = existAnyConnectedInternetPdn; 115 onInternetDataNetworkChanged(mExistAnyConnectedInternetPdn); 116 } 117 } 118 119 /** Updates the current service state. */ onServiceStateChanged(ServiceState serviceState)120 public void onServiceStateChanged(ServiceState serviceState) { 121 final long now = getTimeMillis(); 122 if (isModemOff(serviceState)) { 123 // Finish the duration of last service state and mark modem off 124 addServiceState(mLastState.getAndSet(new TimestampedServiceState(null, now)), now); 125 } else { 126 SatelliteController satelliteController = SatelliteController.getInstance(); 127 CellularServiceState newState = new CellularServiceState(); 128 newState.voiceRat = getVoiceRat(mPhone, serviceState); 129 newState.dataRat = getRat(serviceState, NetworkRegistrationInfo.DOMAIN_PS); 130 newState.voiceRoamingType = 131 getNetworkRoamingState(serviceState, NetworkRegistrationInfo.DOMAIN_CS); 132 newState.dataRoamingType = 133 getNetworkRoamingState(serviceState, NetworkRegistrationInfo.DOMAIN_PS); 134 newState.isEndc = isEndc(serviceState); 135 newState.simSlotIndex = mPhone.getPhoneId(); 136 newState.isMultiSim = SimSlotState.isMultiSim(); 137 newState.carrierId = mPhone.getCarrierId(); 138 newState.isEmergencyOnly = isEmergencyOnly(serviceState); 139 newState.isInternetPdnUp = isInternetPdnUp(mPhone); 140 newState.foldState = mDeviceStateHelper.getFoldState(); 141 newState.overrideVoiceService = mOverrideVoiceService.get(); 142 newState.isDataEnabled = mPhone.getDataSettingsManager().isDataEnabled(); 143 newState.isIwlanCrossSim = isCrossSimCallingRegistered(mPhone); 144 if (satelliteController != null) { 145 newState.isNtn = satelliteController.isInSatelliteModeForCarrierRoaming(mPhone); 146 newState.isNbIotNtn = satelliteController.isInCarrierRoamingNbIotNtn(mPhone); 147 } else { 148 newState.isNtn = false; 149 newState.isNbIotNtn = false; 150 } 151 TimestampedServiceState prevState = 152 mLastState.getAndSet(new TimestampedServiceState(newState, now)); 153 addServiceStateAndSwitch( 154 prevState, now, getDataServiceSwitch(prevState.mServiceState, newState)); 155 } 156 157 writeDataRatAtom(serviceState); 158 } 159 160 /** Updates the fold state of the device for the current service state. */ onFoldStateChanged(int foldState)161 public void onFoldStateChanged(int foldState) { 162 final long now = getTimeMillis(); 163 CellularServiceState lastServiceState = mLastState.get().mServiceState; 164 if (lastServiceState == null || lastServiceState.foldState == foldState) { 165 // Not need to update the fold state if modem is off or if is the 166 // same fold state 167 return; 168 } else { 169 TimestampedServiceState lastState = 170 mLastState.getAndUpdate( 171 state -> { 172 CellularServiceState newServiceState = copyOf(state.mServiceState); 173 newServiceState.foldState = foldState; 174 return new TimestampedServiceState(newServiceState, now); 175 }); 176 addServiceState(lastState, now); 177 } 178 } 179 180 /** Updates override state for voice service state when voice calling capability changes */ onVoiceServiceStateOverrideChanged(boolean override)181 public void onVoiceServiceStateOverrideChanged(boolean override) { 182 if (override == mOverrideVoiceService.get()) { 183 return; 184 } 185 mOverrideVoiceService.set(override); 186 final long now = getTimeMillis(); 187 TimestampedServiceState lastState = 188 mLastState.getAndUpdate( 189 state -> { 190 if (state.mServiceState == null) { 191 return new TimestampedServiceState(null, now); 192 } 193 CellularServiceState newServiceState = copyOf(state.mServiceState); 194 newServiceState.overrideVoiceService = mOverrideVoiceService.get(); 195 return new TimestampedServiceState(newServiceState, now); 196 }); 197 addServiceState(lastState, now); 198 } 199 addServiceState(TimestampedServiceState prevState, long now)200 private void addServiceState(TimestampedServiceState prevState, long now) { 201 addServiceStateAndSwitch(prevState, now, null); 202 } 203 addServiceStateAndSwitch( TimestampedServiceState prevState, long now, @Nullable CellularDataServiceSwitch serviceSwitch)204 private void addServiceStateAndSwitch( 205 TimestampedServiceState prevState, 206 long now, 207 @Nullable CellularDataServiceSwitch serviceSwitch) { 208 if (prevState.mServiceState == null) { 209 // Skip duration when modem is off 210 return; 211 } 212 if (now >= prevState.mTimestamp) { 213 CellularServiceState state = copyOf(prevState.mServiceState); 214 state.totalTimeMillis = now - prevState.mTimestamp; 215 mStorage.addCellularServiceStateAndCellularDataServiceSwitch(state, serviceSwitch); 216 } else { 217 Rlog.e(TAG, "addServiceState: durationMillis<0"); 218 } 219 } 220 221 @Nullable getDataServiceSwitch( @ullable CellularServiceState prevState, CellularServiceState nextState)222 private CellularDataServiceSwitch getDataServiceSwitch( 223 @Nullable CellularServiceState prevState, CellularServiceState nextState) { 224 // Record switch only if multi-SIM state and carrier ID are the same and data RAT differs. 225 if (prevState != null 226 && prevState.isMultiSim == nextState.isMultiSim 227 && prevState.carrierId == nextState.carrierId 228 && prevState.dataRat != nextState.dataRat) { 229 CellularDataServiceSwitch serviceSwitch = new CellularDataServiceSwitch(); 230 serviceSwitch.ratFrom = prevState.dataRat; 231 serviceSwitch.ratTo = nextState.dataRat; 232 serviceSwitch.isMultiSim = nextState.isMultiSim; 233 serviceSwitch.simSlotIndex = nextState.simSlotIndex; 234 serviceSwitch.carrierId = nextState.carrierId; 235 serviceSwitch.switchCount = 1; 236 return serviceSwitch; 237 } else { 238 return null; 239 } 240 } 241 242 /** Returns the service state for the given phone, or {@code null} if it cannot be obtained. */ 243 @Nullable getServiceStateForPhone(Phone phone)244 private static ServiceState getServiceStateForPhone(Phone phone) { 245 ServiceStateTracker serviceStateTracker = phone.getServiceStateTracker(); 246 return serviceStateTracker != null ? serviceStateTracker.getServiceState() : null; 247 } 248 249 /** 250 * Returns the band used from the given phone, or {@code 0} if it is invalid or cannot be 251 * determined. 252 */ getBand(Phone phone)253 static int getBand(Phone phone) { 254 ServiceState serviceState = getServiceStateForPhone(phone); 255 return getBand(serviceState); 256 } 257 258 /** 259 * Returns the band used from the given service state, or {@code 0} if it is invalid or cannot 260 * be determined. 261 */ getBand(@ullable ServiceState serviceState)262 static int getBand(@Nullable ServiceState serviceState) { 263 if (serviceState == null) { 264 Rlog.w(TAG, "getBand: serviceState=null"); 265 return 0; // Band unknown 266 } 267 int chNumber = serviceState.getChannelNumber(); 268 int band; 269 @NetworkType int rat = getRat(serviceState, NetworkRegistrationInfo.DOMAIN_PS); 270 if (rat == TelephonyManager.NETWORK_TYPE_UNKNOWN) { 271 rat = serviceState.getVoiceNetworkType(); 272 } 273 switch (rat) { 274 case TelephonyManager.NETWORK_TYPE_GSM: 275 case TelephonyManager.NETWORK_TYPE_GPRS: 276 case TelephonyManager.NETWORK_TYPE_EDGE: 277 band = AccessNetworkUtils.getOperatingBandForArfcn(chNumber); 278 break; 279 case TelephonyManager.NETWORK_TYPE_UMTS: 280 case TelephonyManager.NETWORK_TYPE_HSDPA: 281 case TelephonyManager.NETWORK_TYPE_HSUPA: 282 case TelephonyManager.NETWORK_TYPE_HSPA: 283 case TelephonyManager.NETWORK_TYPE_HSPAP: 284 band = AccessNetworkUtils.getOperatingBandForUarfcn(chNumber); 285 break; 286 case TelephonyManager.NETWORK_TYPE_LTE: 287 case TelephonyManager.NETWORK_TYPE_LTE_CA: 288 band = AccessNetworkUtils.getOperatingBandForEarfcn(chNumber); 289 break; 290 case TelephonyManager.NETWORK_TYPE_NR: 291 band = AccessNetworkUtils.getOperatingBandForNrarfcn(chNumber); 292 break; 293 default: 294 Rlog.w(TAG, "getBand: unknown WWAN RAT " + rat); 295 band = 0; 296 break; 297 } 298 if (band == AccessNetworkUtils.INVALID_BAND) { 299 Rlog.w(TAG, "getBand: band invalid for rat=" + rat + " ch=" + chNumber); 300 return 0; 301 } else { 302 return band; 303 } 304 } 305 copyOf(CellularServiceState state)306 private static CellularServiceState copyOf(CellularServiceState state) { 307 // MessageNano does not support clone, have to copy manually 308 CellularServiceState copy = new CellularServiceState(); 309 copy.voiceRat = state.voiceRat; 310 copy.dataRat = state.dataRat; 311 copy.voiceRoamingType = state.voiceRoamingType; 312 copy.dataRoamingType = state.dataRoamingType; 313 copy.isEndc = state.isEndc; 314 copy.simSlotIndex = state.simSlotIndex; 315 copy.isMultiSim = state.isMultiSim; 316 copy.carrierId = state.carrierId; 317 copy.totalTimeMillis = state.totalTimeMillis; 318 copy.isEmergencyOnly = state.isEmergencyOnly; 319 copy.isInternetPdnUp = state.isInternetPdnUp; 320 copy.foldState = state.foldState; 321 copy.overrideVoiceService = state.overrideVoiceService; 322 copy.isDataEnabled = state.isDataEnabled; 323 copy.isIwlanCrossSim = state.isIwlanCrossSim; 324 copy.isNtn = state.isNtn; 325 copy.isNbIotNtn = state.isNbIotNtn; 326 return copy; 327 } 328 329 /** 330 * Returns {@code true} if modem radio is turned off (e.g. airplane mode). 331 * 332 * <p>Currently this is approximated by voice service state being {@code STATE_POWER_OFF}. 333 */ isModemOff(ServiceState state)334 private static boolean isModemOff(ServiceState state) { 335 // TODO(b/189335473): we should get this info from phone's radio power state, which is 336 // updated separately 337 return state.getVoiceRegState() == ServiceState.STATE_POWER_OFF; 338 } 339 340 /** 341 * Returns the current voice RAT from IMS registration if present, otherwise from the service 342 * state. 343 * 344 * <p>If the device is not in service, {@code TelephonyManager.NETWORK_TYPE_UNKNOWN} is returned 345 * despite that the device may have emergency service over a certain RAT. 346 */ getVoiceRat(Phone phone, @Nullable ServiceState state)347 static @NetworkType int getVoiceRat(Phone phone, @Nullable ServiceState state) { 348 return getVoiceRat(phone, state, VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_UNKNOWN); 349 } 350 351 /** 352 * Returns the current voice RAT according to the bearer. 353 * 354 * <p>If the device is not in service, {@code TelephonyManager.NETWORK_TYPE_UNKNOWN} is returned 355 * despite that the device may have emergency service over a certain RAT. 356 */ 357 @VisibleForTesting public getVoiceRat(Phone phone, @Nullable ServiceState state, int bearer)358 static @NetworkType int getVoiceRat(Phone phone, @Nullable ServiceState state, int bearer) { 359 if (state == null) { 360 return TelephonyManager.NETWORK_TYPE_UNKNOWN; 361 } 362 ImsPhone imsPhone = (ImsPhone) phone.getImsPhone(); 363 if (bearer != VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_CS && imsPhone != null) { 364 @NetworkType int imsVoiceRat = imsPhone.getImsStats().getImsVoiceRadioTech(); 365 if (imsVoiceRat != TelephonyManager.NETWORK_TYPE_UNKNOWN) { 366 // If IMS is registered over WWAN but WWAN PS is not in service, 367 // fallback to WWAN CS RAT 368 boolean isImsVoiceRatValid = 369 (imsVoiceRat == TelephonyManager.NETWORK_TYPE_IWLAN 370 || getRat(state, NetworkRegistrationInfo.DOMAIN_PS) 371 != TelephonyManager.NETWORK_TYPE_UNKNOWN); 372 if (isImsVoiceRatValid) { 373 return imsVoiceRat; 374 } 375 } 376 } 377 if (bearer == VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_IMS) { 378 return TelephonyManager.NETWORK_TYPE_UNKNOWN; 379 } else { 380 return getRat(state, NetworkRegistrationInfo.DOMAIN_CS); 381 } 382 } 383 isCrossSimCallingRegistered(Phone phone)384 private boolean isCrossSimCallingRegistered(Phone phone) { 385 if (phone.getImsPhone() != null) { 386 return phone.getImsPhone().getImsRegistrationTech() 387 == ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM; 388 } 389 return false; 390 } 391 392 /** Returns RAT used by WWAN if WWAN is in service. */ getRat( ServiceState state, @NetworkRegistrationInfo.Domain int domain)393 public static @NetworkType int getRat( 394 ServiceState state, @NetworkRegistrationInfo.Domain int domain) { 395 final NetworkRegistrationInfo wwanRegInfo = 396 state.getNetworkRegistrationInfo( 397 domain, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); 398 return wwanRegInfo != null && wwanRegInfo.isInService() 399 ? wwanRegInfo.getAccessNetworkTechnology() 400 : TelephonyManager.NETWORK_TYPE_UNKNOWN; 401 } 402 isEmergencyOnly(ServiceState state)403 private static boolean isEmergencyOnly(ServiceState state) { 404 NetworkRegistrationInfo regInfo = 405 state.getNetworkRegistrationInfo( 406 NetworkRegistrationInfo.DOMAIN_CS, 407 AccessNetworkConstants.TRANSPORT_TYPE_WWAN); 408 return regInfo != null && !regInfo.isInService() && regInfo.isEmergencyEnabled(); 409 } 410 isEndc(ServiceState state)411 private static boolean isEndc(ServiceState state) { 412 if (getRat(state, NetworkRegistrationInfo.DOMAIN_PS) != TelephonyManager.NETWORK_TYPE_LTE) { 413 return false; 414 } 415 int nrState = state.getNrState(); 416 return nrState == NetworkRegistrationInfo.NR_STATE_CONNECTED 417 || nrState == NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED; 418 } 419 isInternetPdnUp(Phone phone)420 private static boolean isInternetPdnUp(Phone phone) { 421 DataNetworkController dataNetworkController = phone.getDataNetworkController(); 422 if (dataNetworkController != null) { 423 return dataNetworkController.getInternetDataNetworkState() == DATA_CONNECTED; 424 } 425 return false; 426 } 427 onInternetDataNetworkChanged(boolean internetPdnUp)428 private void onInternetDataNetworkChanged(boolean internetPdnUp) { 429 final long now = getTimeMillis(); 430 TimestampedServiceState lastState = 431 mLastState.getAndUpdate( 432 state -> { 433 if (state.mServiceState == null) { 434 return new TimestampedServiceState(null, now); 435 } 436 CellularServiceState newServiceState = copyOf(state.mServiceState); 437 newServiceState.isInternetPdnUp = internetPdnUp; 438 return new TimestampedServiceState(newServiceState, now); 439 }); 440 addServiceState(lastState, now); 441 } 442 getNetworkRoamingState( ServiceState ss, @NetworkRegistrationInfo.Domain int domain)443 private static @RoamingType int getNetworkRoamingState( 444 ServiceState ss, @NetworkRegistrationInfo.Domain int domain) { 445 final NetworkRegistrationInfo nri = 446 ss.getNetworkRegistrationInfo(domain, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); 447 if (nri == null) { 448 // No registration for domain 449 return ServiceState.ROAMING_TYPE_NOT_ROAMING; 450 } 451 @RoamingType int roamingType = nri.getRoamingType(); 452 if (nri.isNetworkRoaming() && roamingType == ServiceState.ROAMING_TYPE_NOT_ROAMING) { 453 // Roaming is overridden, exact roaming type unknown. 454 return ServiceState.ROAMING_TYPE_UNKNOWN; 455 } 456 return roamingType; 457 } 458 459 /** Determines whether device is roaming, bypassing carrier overrides. */ isNetworkRoaming( ServiceState ss, @NetworkRegistrationInfo.Domain int domain)460 public static boolean isNetworkRoaming( 461 ServiceState ss, @NetworkRegistrationInfo.Domain int domain) { 462 if (ss == null) { 463 return false; 464 } 465 final NetworkRegistrationInfo nri = 466 ss.getNetworkRegistrationInfo(domain, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); 467 return nri != null && nri.isNetworkRoaming(); 468 } 469 470 /** Determines whether device is roaming in any domain, bypassing carrier overrides. */ isNetworkRoaming(ServiceState ss)471 public static boolean isNetworkRoaming(ServiceState ss) { 472 return isNetworkRoaming(ss, NetworkRegistrationInfo.DOMAIN_CS) 473 || isNetworkRoaming(ss, NetworkRegistrationInfo.DOMAIN_PS); 474 } 475 476 /** Collect data Rat metric. */ writeDataRatAtom(@onNull ServiceState serviceState)477 private void writeDataRatAtom(@NonNull ServiceState serviceState) { 478 if (DataConnectionStateTracker.getActiveDataSubId() != mPhone.getSubId()) { 479 return; 480 } 481 NetworkRegistrationInfo wwanRegInfo = serviceState.getNetworkRegistrationInfo( 482 NetworkRegistrationInfo.DOMAIN_PS, 483 AccessNetworkConstants.TRANSPORT_TYPE_WWAN); 484 if (wwanRegInfo == null) { 485 return; 486 } 487 int dataRat = wwanRegInfo.getAccessNetworkTechnology(); 488 int nrFrequency = serviceState.getNrFrequencyRange(); 489 int nrState = serviceState.getNrState(); 490 int translatedDataRat = 491 TelephonyStatsLog.DATA_RAT_STATE_CHANGED__DATA_RAT__DATA_RAT_UNSPECIFIED; 492 if (!SubscriptionManager.isValidSubscriptionId(mPhone.getSubId())) { 493 translatedDataRat = TelephonyStatsLog.DATA_RAT_STATE_CHANGED__DATA_RAT__NO_SIM; 494 } else if (dataRat == TelephonyManager.NETWORK_TYPE_EHRPD 495 || dataRat == TelephonyManager.NETWORK_TYPE_HSPAP 496 || dataRat == TelephonyManager.NETWORK_TYPE_UMTS 497 || dataRat == TelephonyManager.NETWORK_TYPE_HSDPA 498 || dataRat == TelephonyManager.NETWORK_TYPE_HSUPA 499 || dataRat == TelephonyManager.NETWORK_TYPE_HSPA 500 || dataRat == TelephonyManager.NETWORK_TYPE_EVDO_0 501 || dataRat == TelephonyManager.NETWORK_TYPE_EVDO_A 502 || dataRat == TelephonyManager.NETWORK_TYPE_EVDO_B) { 503 translatedDataRat = TelephonyStatsLog.DATA_RAT_STATE_CHANGED__DATA_RAT__DATA_RAT_3G; 504 } else if (dataRat == TelephonyManager.NETWORK_TYPE_1xRTT 505 || dataRat == TelephonyManager.NETWORK_TYPE_GPRS 506 || dataRat == TelephonyManager.NETWORK_TYPE_EDGE 507 || dataRat == TelephonyManager.NETWORK_TYPE_CDMA 508 || dataRat == TelephonyManager.NETWORK_TYPE_GSM) { 509 translatedDataRat = TelephonyStatsLog.DATA_RAT_STATE_CHANGED__DATA_RAT__DATA_RAT_2G; 510 } else if (dataRat == TelephonyManager.NETWORK_TYPE_NR) { 511 translatedDataRat = nrFrequency != ServiceState.FREQUENCY_RANGE_MMWAVE 512 ? TelephonyStatsLog.DATA_RAT_STATE_CHANGED__DATA_RAT__DATA_RAT_5G_SA_FR1 : 513 TelephonyStatsLog.DATA_RAT_STATE_CHANGED__DATA_RAT__DATA_RAT_5G_SA_FR2; 514 } else if (dataRat == TelephonyManager.NETWORK_TYPE_LTE) { 515 if (nrState == NetworkRegistrationInfo.NR_STATE_CONNECTED) { 516 translatedDataRat = nrFrequency != ServiceState.FREQUENCY_RANGE_MMWAVE 517 ? TelephonyStatsLog.DATA_RAT_STATE_CHANGED__DATA_RAT__DATA_RAT_5G_NSA_FR1 : 518 TelephonyStatsLog.DATA_RAT_STATE_CHANGED__DATA_RAT__DATA_RAT_5G_NSA_FR2; 519 } else if (nrState == NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED) { 520 translatedDataRat = 521 TelephonyStatsLog.DATA_RAT_STATE_CHANGED__DATA_RAT__DATA_RAT_5G_NSA_LTE; 522 } else { 523 translatedDataRat = 524 TelephonyStatsLog.DATA_RAT_STATE_CHANGED__DATA_RAT__DATA_RAT_4G_LTE; 525 } 526 } 527 528 if (translatedDataRat != mCurrentDataRat) { 529 TelephonyStatsLog.write(TelephonyStatsLog.DATA_RAT_STATE_CHANGED, translatedDataRat); 530 mCurrentDataRat = translatedDataRat; 531 } 532 } 533 getCurrentDataRat()534 int getCurrentDataRat() { 535 return mCurrentDataRat; 536 } 537 538 @VisibleForTesting getTimeMillis()539 protected long getTimeMillis() { 540 return SystemClock.elapsedRealtime(); 541 } 542 543 private static final class TimestampedServiceState { 544 private final CellularServiceState mServiceState; 545 private final long mTimestamp; // Start time of the service state segment 546 TimestampedServiceState(CellularServiceState serviceState, long timestamp)547 TimestampedServiceState(CellularServiceState serviceState, long timestamp) { 548 mServiceState = serviceState; 549 mTimestamp = timestamp; 550 } 551 } 552 } 553