• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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