summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmds/statsd/src/atoms.proto6
-rw-r--r--core/java/android/net/NetworkTemplate.java12
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java15
-rw-r--r--services/core/java/com/android/server/stats/pull/StatsPullAtomService.java12
-rw-r--r--tests/net/java/android/net/NetworkTemplateTest.kt7
-rw-r--r--tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java55
6 files changed, 102 insertions, 5 deletions
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 7a016522d597..36b46c3d03a3 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -5178,6 +5178,12 @@ message DataUsageBytesTransfer {
// 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/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index eba7ff348328..7234eb1d81cd 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -87,6 +87,15 @@ public class NetworkTemplate implements Parcelable {
* @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 @@ public class NetworkTemplate implements Parcelable {
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 a0ab5eae7315..cb1c7e4fd0de 100644
--- a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
+++ b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
@@ -16,11 +16,13 @@
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.telephony.Annotation;
+import android.telephony.NetworkRegistrationInfo;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
@@ -195,7 +197,18 @@ public class NetworkStatsSubscriptionsMonitor extends
@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/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index dbdef2368c7c..8979d8c6ba10 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -1145,6 +1145,15 @@ public class StatsPullAtomService extends SystemService {
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);
@@ -1156,7 +1165,7 @@ public class StatsPullAtomService extends SystemService {
.writeLong(entry.rxPackets)
.writeLong(entry.txBytes)
.writeLong(entry.txPackets)
- .writeInt(statsExt.ratType)
+ .writeInt(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.
.writeString(statsExt.subInfo.mcc)
@@ -1165,6 +1174,7 @@ public class StatsPullAtomService extends SystemService {
.writeInt(statsExt.subInfo.isOpportunistic
? DATA_USAGE_BYTES_TRANSFER__OPPORTUNISTIC_DATA_SUB__OPPORTUNISTIC
: DATA_USAGE_BYTES_TRANSFER__OPPORTUNISTIC_DATA_SUB__NOT_OPPORTUNISTIC)
+ .writeBoolean(isNR)
.build();
pulledData.add(e);
}
diff --git a/tests/net/java/android/net/NetworkTemplateTest.kt b/tests/net/java/android/net/NetworkTemplateTest.kt
index 5dd0fda4da28..9ba56e44fe88 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.METERED_ALL
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 @@ class NetworkTemplateTest {
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 058856dcd6fb..c91dfecf041b 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.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.eq;
@@ -29,7 +30,9 @@ import static org.mockito.Mockito.when;
import android.annotation.NonNull;
import android.content.Context;
+import android.net.NetworkTemplate;
import android.os.Looper;
+import android.telephony.NetworkRegistrationInfo;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
@@ -61,7 +64,6 @@ public final class NetworkStatsSubscriptionsMonitorTest {
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 Delegate mDelegate;
@@ -215,4 +217,55 @@ public final class NetworkStatsSubscriptionsMonitorTest {
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);
+ }
}