Report NR connected state to provide resolution of 5G NSA mode

Test: adb shell cmd stats pull-source 10082
Test: atest UidAtomTests#testDataUsageBytesTransfer
Bug: 160727498

Change-Id: I7d98ab425852ffa064c68f5dc50bd1f5a4a49ab9
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 02c0d93..4a2f20b 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -5191,6 +5191,12 @@
     // record is combined across opportunistic data subscriptions.
     // See {@link SubscriptionManager#setOpportunistic}.
     optional DataSubscriptionState opportunistic_data_sub = 10;
+
+    // Indicate whether NR is connected, server side could use this with RAT type to determine if
+    // the record is for 5G NSA (Non Stand Alone) mode, where the primary cell is still LTE and
+    // network allocates a secondary 5G cell so telephony reports RAT = LTE along with NR state as
+    // connected.
+    optional bool is_nr_connected = 11;
 }
 
 /**
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index f716dbd..f74cd611 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -1130,19 +1130,29 @@
 
     private void addDataUsageBytesTransferAtoms(@NonNull NetworkStatsExt statsExt,
             @NonNull List<StatsEvent> pulledData) {
+
+        // Workaround for 5G NSA mode, see {@link NetworkTemplate#NETWORK_TYPE_5G_NSA}.
+        // 5G NSA mode means the primary cell is LTE with a secondary connection to an
+        // NR cell. To mitigate risk, NetworkStats is currently storing this state as
+        // a fake RAT type rather than storing the boolean separately.
+        final boolean is5GNsa = statsExt.ratType == NetworkTemplate.NETWORK_TYPE_5G_NSA;
+        // Report NR connected in 5G non-standalone mode, or if the RAT type is NR to begin with.
+        final boolean isNR = is5GNsa || statsExt.ratType == TelephonyManager.NETWORK_TYPE_NR;
+
         final NetworkStats.Entry entry = new NetworkStats.Entry(); // for recycling
         for (int i = 0; i < statsExt.stats.size(); i++) {
             statsExt.stats.getValues(i, entry);
             pulledData.add(FrameworkStatsLog.buildStatsEvent(
                     FrameworkStatsLog.DATA_USAGE_BYTES_TRANSFER, entry.set, entry.rxBytes,
-                    entry.rxPackets, entry.txBytes, entry.txPackets, statsExt.ratType,
+                    entry.rxPackets, entry.txBytes, entry.txPackets,
+                    is5GNsa ? TelephonyManager.NETWORK_TYPE_LTE : statsExt.ratType,
                     // Fill information about subscription, these cannot be null since invalid data
                     // would be filtered when adding into subInfo list.
                     statsExt.subInfo.mcc, statsExt.subInfo.mnc, statsExt.subInfo.carrierId,
                     statsExt.subInfo.isOpportunistic
                             ? DATA_USAGE_BYTES_TRANSFER__OPPORTUNISTIC_DATA_SUB__OPPORTUNISTIC
-                            : DATA_USAGE_BYTES_TRANSFER__OPPORTUNISTIC_DATA_SUB__NOT_OPPORTUNISTIC)
-            );
+                            : DATA_USAGE_BYTES_TRANSFER__OPPORTUNISTIC_DATA_SUB__NOT_OPPORTUNISTIC,
+                    isNR));
         }
     }