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