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