Collect DataRatStateChanged atom

Bug: 318519337
Test: Build and Inpected log on device
Change-Id: Ic565a7a0f789a954f5a3983bdb013035ff80c732
diff --git a/flags/data.aconfig b/flags/data.aconfig
index fbd8508..54b6580 100644
--- a/flags/data.aconfig
+++ b/flags/data.aconfig
@@ -148,4 +148,12 @@
   namespace: "telephony"
   description: "Enable DSRS diagnostics."
   bug: "319601607"
-}
\ No newline at end of file
+}
+
+# OWNER=jackyu TARGET=24Q3
+flag {
+  name: "data_rat_metric_enabled"
+  namespace: "telephony"
+  description: "Write DataRatStateChanged atom"
+  bug:"318519337"
+}
diff --git a/src/java/com/android/internal/telephony/metrics/DataConnectionStateTracker.java b/src/java/com/android/internal/telephony/metrics/DataConnectionStateTracker.java
index c7ef625..0197e36 100644
--- a/src/java/com/android/internal/telephony/metrics/DataConnectionStateTracker.java
+++ b/src/java/com/android/internal/telephony/metrics/DataConnectionStateTracker.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.telephony.metrics;
 
+import static com.android.internal.telephony.flags.Flags.dataRatMetricEnabled;
+
 import android.os.Handler;
 import android.os.HandlerExecutor;
 import android.os.HandlerThread;
@@ -27,6 +29,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.TelephonyStatsLog;
 
 import java.util.HashMap;
 import java.util.List;
@@ -48,6 +51,7 @@
     private HashMap<Integer, PreciseDataConnectionState> mLastPreciseDataConnectionState =
             new HashMap<>();
     private PreciseDataConnectionStateListenerImpl mDataConnectionStateListener;
+    private int mActiveDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 
     private final SubscriptionManager.OnSubscriptionsChangedListener mSubscriptionsChangedListener =
             new SubscriptionManager.OnSubscriptionsChangedListener() {
@@ -156,8 +160,37 @@
         mPhone.getVoiceCallSessionStats().onPreciseDataConnectionStateChanged(connectionState);
     }
 
+    static int getActiveDataSubId() {
+        if (sDataConnectionStateTracker.size() == 0) {
+            return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+        }
+        return sDataConnectionStateTracker.valueAt(0).mActiveDataSubId;
+    }
+
+    /** Log RAT if the active data subId changes to another subId with a different RAT */
+    private void logRATChanges(int subId) {
+        if (mSubId == subId && mActiveDataSubId != subId) {
+            int newDataRat = mPhone.getServiceStateTracker()
+                    .getServiceStateStats().getCurrentDataRat();
+            for (int i = 0; i < sDataConnectionStateTracker.size(); i++) {
+                DataConnectionStateTracker dataConnectionStateTracker =
+                        sDataConnectionStateTracker.valueAt(0);
+                if (dataConnectionStateTracker.mSubId == mActiveDataSubId) {
+                    int previousDataRat = dataConnectionStateTracker.mPhone
+                            .getServiceStateTracker().getServiceStateStats()
+                            .getCurrentDataRat();
+                    if (newDataRat != previousDataRat) {
+                        TelephonyStatsLog.write(TelephonyStatsLog.DATA_RAT_STATE_CHANGED,
+                                newDataRat);
+                    }
+                }
+            }
+        }
+    }
+
     private class PreciseDataConnectionStateListenerImpl extends TelephonyCallback
-            implements TelephonyCallback.PreciseDataConnectionStateListener {
+            implements TelephonyCallback.PreciseDataConnectionStateListener,
+            TelephonyCallback.ActiveDataSubscriptionIdListener {
         private final Executor mExecutor;
         private TelephonyManager mTelephonyManager = null;
 
@@ -185,5 +218,13 @@
                 PreciseDataConnectionState connectionState) {
             notifyDataConnectionStateChanged(connectionState);
         }
+
+        @Override
+        public void onActiveDataSubscriptionIdChanged(int subId) {
+            if (dataRatMetricEnabled()) {
+                logRATChanges(subId);
+                mActiveDataSubId = subId;
+            }
+        }
     }
 }
diff --git a/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java b/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java
index d400c22..91b191f 100644
--- a/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java
+++ b/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java
@@ -21,6 +21,7 @@
 import static com.android.internal.telephony.TelephonyStatsLog.VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_CS;
 import static com.android.internal.telephony.TelephonyStatsLog.VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_IMS;
 import static com.android.internal.telephony.TelephonyStatsLog.VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_UNKNOWN;
+import static com.android.internal.telephony.flags.Flags.dataRatMetricEnabled;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -31,6 +32,7 @@
 import android.telephony.NetworkRegistrationInfo;
 import android.telephony.ServiceState;
 import android.telephony.ServiceState.RoamingType;
+import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.telephony.ims.stub.ImsRegistrationImplBase;
 
@@ -38,6 +40,7 @@
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneFactory;
 import com.android.internal.telephony.ServiceStateTracker;
+import com.android.internal.telephony.TelephonyStatsLog;
 import com.android.internal.telephony.data.DataNetwork;
 import com.android.internal.telephony.data.DataNetworkController;
 import com.android.internal.telephony.data.DataNetworkController.DataNetworkControllerCallback;
@@ -61,6 +64,8 @@
     private final PersistAtomsStorage mStorage;
     private final DeviceStateHelper mDeviceStateHelper;
     private boolean mExistAnyConnectedInternetPdn;
+    private int mCurrentDataRat =
+            TelephonyStatsLog.DATA_RAT_STATE_CHANGED__DATA_RAT__DATA_RAT_UNSPECIFIED;
 
     public ServiceStateStats(Phone phone) {
         super(Runnable::run);
@@ -140,6 +145,10 @@
             addServiceStateAndSwitch(
                     prevState, now, getDataServiceSwitch(prevState.mServiceState, newState));
         }
+
+        if (dataRatMetricEnabled()) {
+            writeDataRatAtom(serviceState);
+        }
     }
 
     /** Updates the fold state of the device for the current service state. */
@@ -456,6 +465,68 @@
                 || isNetworkRoaming(ss, NetworkRegistrationInfo.DOMAIN_PS);
     }
 
+    /** Collect data Rat metric. */
+    private void writeDataRatAtom(@NonNull ServiceState serviceState) {
+        if (DataConnectionStateTracker.getActiveDataSubId() != mPhone.getSubId()) {
+            return;
+        }
+        NetworkRegistrationInfo wwanRegInfo = serviceState.getNetworkRegistrationInfo(
+                NetworkRegistrationInfo.DOMAIN_PS,
+                AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+        if (wwanRegInfo == null) {
+            return;
+        }
+        int dataRat = wwanRegInfo.getAccessNetworkTechnology();
+        int nrFrequency = serviceState.getNrFrequencyRange();
+        int nrState = serviceState.getNrState();
+        int translatedDataRat =
+                TelephonyStatsLog.DATA_RAT_STATE_CHANGED__DATA_RAT__DATA_RAT_UNSPECIFIED;
+        if (!SubscriptionManager.isValidSubscriptionId(mPhone.getSubId())) {
+            translatedDataRat = TelephonyStatsLog.DATA_RAT_STATE_CHANGED__DATA_RAT__NO_SIM;
+        } else if (dataRat == TelephonyManager.NETWORK_TYPE_EHRPD
+                || dataRat == TelephonyManager.NETWORK_TYPE_HSPAP
+                || dataRat == TelephonyManager.NETWORK_TYPE_UMTS
+                || dataRat == TelephonyManager.NETWORK_TYPE_HSDPA
+                || dataRat == TelephonyManager.NETWORK_TYPE_HSUPA
+                || dataRat == TelephonyManager.NETWORK_TYPE_HSPA
+                || dataRat == TelephonyManager.NETWORK_TYPE_EVDO_0
+                || dataRat == TelephonyManager.NETWORK_TYPE_EVDO_A
+                || dataRat == TelephonyManager.NETWORK_TYPE_EVDO_B) {
+            translatedDataRat = TelephonyStatsLog.DATA_RAT_STATE_CHANGED__DATA_RAT__DATA_RAT_3G;
+        } else if (dataRat == TelephonyManager.NETWORK_TYPE_1xRTT
+                || dataRat == TelephonyManager.NETWORK_TYPE_GPRS
+                || dataRat == TelephonyManager.NETWORK_TYPE_EDGE
+                || dataRat == TelephonyManager.NETWORK_TYPE_CDMA
+                || dataRat == TelephonyManager.NETWORK_TYPE_GSM) {
+            translatedDataRat = TelephonyStatsLog.DATA_RAT_STATE_CHANGED__DATA_RAT__DATA_RAT_2G;
+        } else if (dataRat == TelephonyManager.NETWORK_TYPE_NR) {
+            translatedDataRat = nrFrequency != ServiceState.FREQUENCY_RANGE_MMWAVE
+                    ? TelephonyStatsLog.DATA_RAT_STATE_CHANGED__DATA_RAT__DATA_RAT_5G_SA_FR1 :
+                    TelephonyStatsLog.DATA_RAT_STATE_CHANGED__DATA_RAT__DATA_RAT_5G_SA_FR2;
+        } else if (dataRat == TelephonyManager.NETWORK_TYPE_LTE) {
+            if (nrState == NetworkRegistrationInfo.NR_STATE_CONNECTED) {
+                translatedDataRat = nrFrequency != ServiceState.FREQUENCY_RANGE_MMWAVE
+                    ? TelephonyStatsLog.DATA_RAT_STATE_CHANGED__DATA_RAT__DATA_RAT_5G_NSA_FR1 :
+                    TelephonyStatsLog.DATA_RAT_STATE_CHANGED__DATA_RAT__DATA_RAT_5G_NSA_FR2;
+            } else if (nrState == NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED) {
+                translatedDataRat =
+                        TelephonyStatsLog.DATA_RAT_STATE_CHANGED__DATA_RAT__DATA_RAT_5G_NSA_LTE;
+            } else {
+                translatedDataRat =
+                        TelephonyStatsLog.DATA_RAT_STATE_CHANGED__DATA_RAT__DATA_RAT_4G_LTE;
+            }
+        }
+
+        if (translatedDataRat != mCurrentDataRat) {
+            TelephonyStatsLog.write(TelephonyStatsLog.DATA_RAT_STATE_CHANGED, translatedDataRat);
+            mCurrentDataRat = translatedDataRat;
+        }
+    }
+
+    int getCurrentDataRat() {
+        return mCurrentDataRat;
+    }
+
     @VisibleForTesting
     protected long getTimeMillis() {
         return SystemClock.elapsedRealtime();