Merge "Attribute data usage to virtual RAT type for 5G non-standalone mode" am: 88f47d4d32 am: 416911a122 am: 2c50b0efd7 am: 29de2f5fff

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1364497

Change-Id: Iee2d99fa2288d026a7bda193ade2105d5a5b8454
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index eba7ff3..7234eb1 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -87,6 +87,15 @@
      * @hide
      */
     public static final int NETWORK_TYPE_ALL = -1;
+    /**
+     * Virtual RAT type to represent 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. This should not be overlapped with any of the
+     * {@code TelephonyManager.NETWORK_TYPE_*} constants.
+     *
+     * @hide
+     */
+    public static final int NETWORK_TYPE_5G_NSA = -2;
 
     private static boolean isKnownMatchRule(final int rule) {
         switch (rule) {
@@ -475,6 +484,9 @@
                 return TelephonyManager.NETWORK_TYPE_LTE;
             case TelephonyManager.NETWORK_TYPE_NR:
                 return TelephonyManager.NETWORK_TYPE_NR;
+            // Virtual RAT type for 5G NSA mode, see {@link NetworkTemplate#NETWORK_TYPE_5G_NSA}.
+            case NetworkTemplate.NETWORK_TYPE_5G_NSA:
+                return NetworkTemplate.NETWORK_TYPE_5G_NSA;
             default:
                 return TelephonyManager.NETWORK_TYPE_UNKNOWN;
         }
diff --git a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
index db553ee..0575ac6 100644
--- a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
+++ b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
@@ -16,12 +16,14 @@
 
 package com.android.server.net;
 
+import static android.net.NetworkTemplate.NETWORK_TYPE_5G_NSA;
 import static android.net.NetworkTemplate.getCollapsedRatType;
 
 import android.annotation.NonNull;
 import android.content.Context;
 import android.os.Looper;
 import android.telephony.Annotation;
+import android.telephony.NetworkRegistrationInfo;
 import android.telephony.PhoneStateListener;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionManager;
@@ -196,7 +198,18 @@
 
         @Override
         public void onServiceStateChanged(@NonNull ServiceState ss) {
-            final int networkType = ss.getDataNetworkType();
+            // In 5G SA (Stand Alone) mode, the primary cell itself will be 5G hence telephony
+            // would report RAT = 5G_NR.
+            // However, in 5G NSA (Non Stand Alone) mode, the primary cell is still LTE and
+            // network allocates a secondary 5G cell so telephony reports RAT = LTE along with
+            // NR state as connected. In such case, attributes the data usage to NR.
+            // See b/160727498.
+            final boolean is5GNsa = (ss.getDataNetworkType() == TelephonyManager.NETWORK_TYPE_LTE
+                    || ss.getDataNetworkType() == TelephonyManager.NETWORK_TYPE_LTE_CA)
+                    && ss.getNrState() == NetworkRegistrationInfo.NR_STATE_CONNECTED;
+
+            final int networkType =
+                    (is5GNsa ? NETWORK_TYPE_5G_NSA : ss.getDataNetworkType());
             final int collapsedRatType = getCollapsedRatType(networkType);
             if (collapsedRatType == mLastCollapsedRatType) return;
 
diff --git a/tests/net/java/android/net/NetworkTemplateTest.kt b/tests/net/java/android/net/NetworkTemplateTest.kt
index 5dd0fda..9ba56e4 100644
--- a/tests/net/java/android/net/NetworkTemplateTest.kt
+++ b/tests/net/java/android/net/NetworkTemplateTest.kt
@@ -26,6 +26,7 @@
 import android.net.NetworkStats.ROAMING_ALL
 import android.net.NetworkTemplate.MATCH_MOBILE
 import android.net.NetworkTemplate.MATCH_WIFI
+import android.net.NetworkTemplate.NETWORK_TYPE_5G_NSA
 import android.net.NetworkTemplate.NETWORK_TYPE_ALL
 import android.net.NetworkTemplate.buildTemplateMobileWithRatType
 import android.telephony.TelephonyManager
@@ -145,11 +146,13 @@
         assertParcelSane(templateWifi, 8)
     }
 
-    // Verify NETWORK_TYPE_ALL does not conflict with TelephonyManager#NETWORK_TYPE_* constants.
+    // Verify NETWORK_TYPE_* constants in NetworkTemplate do not conflict with
+    // TelephonyManager#NETWORK_TYPE_* constants.
     @Test
-    fun testNetworkTypeAll() {
+    fun testNetworkTypeConstants() {
         for (ratType in TelephonyManager.getAllNetworkTypes()) {
             assertNotEquals(NETWORK_TYPE_ALL, ratType)
+            assertNotEquals(NETWORK_TYPE_5G_NSA, ratType)
         }
     }
 }
diff --git a/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java b/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java
index 16fed39..6dc4fce 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java
@@ -17,6 +17,7 @@
 package com.android.server.net;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.fail;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyInt;
@@ -30,7 +31,9 @@
 
 import android.annotation.NonNull;
 import android.content.Context;
+import android.net.NetworkTemplate;
 import android.os.test.TestLooper;
+import android.telephony.NetworkRegistrationInfo;
 import android.telephony.PhoneStateListener;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionManager;
@@ -61,7 +64,6 @@
     private static final String TEST_IMSI3 = "466929999999999";
 
     @Mock private Context mContext;
-    @Mock private PhoneStateListener mPhoneStateListener;
     @Mock private SubscriptionManager mSubscriptionManager;
     @Mock private TelephonyManager mTelephonyManager;
     @Mock private NetworkStatsSubscriptionsMonitor.Delegate mDelegate;
@@ -215,4 +217,55 @@
         verify(mTelephonyManager, times(2)).listen(any(), eq(PhoneStateListener.LISTEN_NONE));
         assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
     }
+
+
+    @Test
+    public void test5g() {
+        mMonitor.start();
+        // Insert sim1, verify RAT type is NETWORK_TYPE_UNKNOWN, and never get any callback
+        // before changing RAT type. Also capture listener for later use.
+        addTestSub(TEST_SUBID1, TEST_IMSI1);
+        assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
+        final ArgumentCaptor<RatTypeListener> ratTypeListenerCaptor =
+                ArgumentCaptor.forClass(RatTypeListener.class);
+        verify(mTelephonyManager, times(1)).listen(ratTypeListenerCaptor.capture(),
+                eq(PhoneStateListener.LISTEN_SERVICE_STATE));
+        final RatTypeListener listener = CollectionUtils
+                .find(ratTypeListenerCaptor.getAllValues(), it -> it.getSubId() == TEST_SUBID1);
+        assertNotNull(listener);
+
+        // Set RAT type to 5G NSA (non-standalone) mode, verify the monitor outputs
+        // NETWORK_TYPE_5G_NSA.
+        final ServiceState serviceState = mock(ServiceState.class);
+        when(serviceState.getDataNetworkType()).thenReturn(TelephonyManager.NETWORK_TYPE_LTE);
+        when(serviceState.getNrState()).thenReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED);
+        listener.onServiceStateChanged(serviceState);
+        assertRatTypeChangedForSub(TEST_IMSI1, NetworkTemplate.NETWORK_TYPE_5G_NSA);
+        reset(mDelegate);
+
+        // Set RAT type to LTE without NR connected, the RAT type should be downgraded to LTE.
+        when(serviceState.getNrState()).thenReturn(NetworkRegistrationInfo.NR_STATE_NONE);
+        listener.onServiceStateChanged(serviceState);
+        assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_LTE);
+        reset(mDelegate);
+
+        // Verify NR connected with other RAT type does not take effect.
+        when(serviceState.getDataNetworkType()).thenReturn(TelephonyManager.NETWORK_TYPE_UMTS);
+        when(serviceState.getNrState()).thenReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED);
+        listener.onServiceStateChanged(serviceState);
+        assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UMTS);
+        reset(mDelegate);
+
+        // Set RAT type to 5G standalone mode, the RAT type should be NR.
+        setRatTypeForSub(ratTypeListenerCaptor.getAllValues(), TEST_SUBID1,
+                TelephonyManager.NETWORK_TYPE_NR);
+        assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_NR);
+        reset(mDelegate);
+
+        // Set NR state to none in standalone mode does not change anything.
+        when(serviceState.getDataNetworkType()).thenReturn(TelephonyManager.NETWORK_TYPE_NR);
+        when(serviceState.getNrState()).thenReturn(NetworkRegistrationInfo.NR_STATE_NONE);
+        listener.onServiceStateChanged(serviceState);
+        assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_NR);
+    }
 }