summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--proto/src/persist_atoms.proto1
-rw-r--r--src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java54
-rw-r--r--src/java/com/android/internal/telephony/metrics/MetricsCollector.java3
-rw-r--r--tests/telephonytests/src/com/android/internal/telephony/metrics/DataCallSessionStatsTest.java322
4 files changed, 379 insertions, 1 deletions
diff --git a/proto/src/persist_atoms.proto b/proto/src/persist_atoms.proto
index 288852f03e..0a1d5530f9 100644
--- a/proto/src/persist_atoms.proto
+++ b/proto/src/persist_atoms.proto
@@ -365,6 +365,7 @@ message DataCallSession {
repeated int32 handover_failure_causes = 20;
repeated int32 handover_failure_rat = 21;
optional bool is_non_dds = 22;
+ optional bool is_iwlan_cross_sim = 23;
}
message CellularServiceState {
diff --git a/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java b/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java
index afb87dd8ae..2b3ed825a1 100644
--- a/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java
+++ b/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java
@@ -18,7 +18,13 @@ package com.android.internal.telephony.metrics;
import static com.android.internal.telephony.TelephonyStatsLog.DATA_CALL_SESSION__IP_TYPE__APN_PROTOCOL_IPV4;
+import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.os.Handler;
+import android.os.HandlerThread;
import android.os.SystemClock;
import android.telephony.Annotation.ApnType;
import android.telephony.Annotation.DataFailureCause;
@@ -55,6 +61,8 @@ public class DataCallSessionStats {
private long mStartTime;
@Nullable private DataCallSession mDataCallSession;
+ private Network mSystemDefaultNetwork;
+ private boolean mIsSystemDefaultNetworkMobile;
private final PersistAtomsStorage mAtomsStorage =
PhoneFactory.getMetricsCollector().getAtomsStorage();
@@ -62,8 +70,47 @@ public class DataCallSessionStats {
public static final int SIZE_LIMIT_HANDOVER_FAILURES = 15;
+ final class DefaultNetworkCallback extends ConnectivityManager.NetworkCallback {
+ @Override
+ public void onAvailable(@NonNull Network network) {
+ mSystemDefaultNetwork = network;
+ }
+
+ @Override
+ public void onCapabilitiesChanged(@NonNull Network network,
+ @NonNull NetworkCapabilities nc) {
+ if (network == mSystemDefaultNetwork) {
+ mIsSystemDefaultNetworkMobile = nc.hasTransport(
+ NetworkCapabilities.TRANSPORT_CELLULAR);
+ }
+ }
+
+ @Override
+ public void onLost(@NonNull Network network) {
+ mIsSystemDefaultNetworkMobile = false;
+ mSystemDefaultNetwork = null;
+ }
+ }
+
public DataCallSessionStats(Phone phone) {
mPhone = phone;
+ registerSystemDefaultNetworkCallback(phone);
+ }
+
+ private void registerSystemDefaultNetworkCallback(@NonNull Phone phone) {
+ ConnectivityManager connectivityManager = phone.getContext()
+ .getSystemService(ConnectivityManager.class);
+ if (connectivityManager != null) {
+ HandlerThread handlerThread = new HandlerThread(
+ DataCallSessionStats.class.getSimpleName());
+ handlerThread.start();
+ Handler callbackHandler = new Handler(handlerThread.getLooper());
+ DefaultNetworkCallback mDefaultNetworkCallback = new DefaultNetworkCallback();
+ connectivityManager.registerSystemDefaultNetworkCallback(
+ mDefaultNetworkCallback, callbackHandler);
+ } else {
+ loge("registerSystemDefaultNetworkCallback: ConnectivityManager is null!");
+ }
}
/** Creates a new ongoing atom when data call is set up. */
@@ -101,6 +148,9 @@ public class DataCallSessionStats {
(currentRat == TelephonyManager.NETWORK_TYPE_IWLAN)
? 0
: ServiceStateStats.getBand(mPhone);
+ // Limitation: Will not capture IKE mobility between Backup Calling <-> WiFi Calling.
+ mDataCallSession.isIwlanCrossSim = currentRat == TelephonyManager.NETWORK_TYPE_IWLAN
+ && mIsSystemDefaultNetworkMobile;
}
// only set if apn hasn't been set during setup
@@ -199,6 +249,8 @@ public class DataCallSessionStats {
if (mDataCallSession.ratAtEnd != currentRat) {
mDataCallSession.ratSwitchCount++;
mDataCallSession.ratAtEnd = currentRat;
+ mDataCallSession.isIwlanCrossSim = currentRat == TelephonyManager.NETWORK_TYPE_IWLAN
+ && mIsSystemDefaultNetworkMobile;
}
// band may have changed even if RAT was the same
mDataCallSession.bandAtEnd =
@@ -288,6 +340,7 @@ public class DataCallSessionStats {
copy.handoverFailureRat = Arrays.copyOf(call.handoverFailureRat,
call.handoverFailureRat.length);
copy.isNonDds = call.isNonDds;
+ copy.isIwlanCrossSim = call.isIwlanCrossSim;
return copy;
}
@@ -313,6 +366,7 @@ public class DataCallSessionStats {
proto.handoverFailureCauses = new int[0];
proto.handoverFailureRat = new int[0];
proto.isNonDds = false;
+ proto.isIwlanCrossSim = false;
return proto;
}
diff --git a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
index 3171f86b21..2ac10e7eee 100644
--- a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
+++ b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
@@ -1061,7 +1061,8 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback {
dataCallSession.bandAtEnd,
dataCallSession.handoverFailureCauses,
dataCallSession.handoverFailureRat,
- dataCallSession.isNonDds);
+ dataCallSession.isNonDds,
+ dataCallSession.isIwlanCrossSim);
}
private static StatsEvent buildStatsEvent(ImsRegistrationStats stats) {
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/DataCallSessionStatsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/DataCallSessionStatsTest.java
new file mode 100644
index 0000000000..700b4cfefa
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/DataCallSessionStatsTest.java
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.metrics;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.net.ConnectivityManager.NetworkCallback;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.telephony.DataFailCause;
+import android.telephony.ServiceState;
+import android.telephony.TelephonyManager;
+import android.telephony.data.ApnSetting;
+import android.telephony.data.DataCallResponse;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.TelephonyTest;
+import com.android.internal.telephony.nano.PersistAtomsProto.DataCallSession;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+public class DataCallSessionStatsTest extends TelephonyTest {
+
+ private ArgumentCaptor<NetworkCallback> mNetworkCallbackCaptor =
+ ArgumentCaptor.forClass(NetworkCallback.class);
+ private DataCallResponse mDefaultImsResponse = buildDataCallResponse("ims", 0);
+ private Network mMockNetwork;
+ private NetworkCapabilities mCellularNetworkCapabilities = new NetworkCapabilities.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR).build();
+
+ private static class TestableDataCallSessionStats extends DataCallSessionStats {
+ private long mTimeMillis = 0L;
+
+ TestableDataCallSessionStats(Phone phone) {
+ super(phone);
+ }
+
+ @Override
+ protected long getTimeMillis() {
+ return mTimeMillis;
+ }
+
+ private void setTimeMillis(long timeMillis) {
+ mTimeMillis = timeMillis;
+ }
+ }
+
+ private TestableDataCallSessionStats mDataCallSessionStats;
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp(getClass().getSimpleName());
+ doNothing().when(mConnectivityManager).registerSystemDefaultNetworkCallback(
+ mNetworkCallbackCaptor.capture(), any());
+ mMockNetwork = mock(Network.class);
+ when(mServiceState.getDataRegistrationState()).thenReturn(ServiceState.STATE_IN_SERVICE);
+ mDataCallSessionStats = new TestableDataCallSessionStats(mPhone);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mDataCallSessionStats = null;
+ super.tearDown();
+ }
+
+ private NetworkCallback getNetworkMonitorCallback() {
+ return mNetworkCallbackCaptor.getValue();
+ }
+
+ private DataCallResponse buildDataCallResponse(String apn, long retryDurationMillis) {
+ return new DataCallResponse.Builder()
+ .setId(apn.hashCode())
+ .setRetryDurationMillis(retryDurationMillis)
+ .build();
+ }
+
+ @Test
+ @SmallTest
+ public void testSetupDataCallOnCellularIms_success() {
+ mDataCallSessionStats.onSetupDataCall(ApnSetting.TYPE_IMS);
+ mDataCallSessionStats.onSetupDataCallResponse(
+ mDefaultImsResponse,
+ TelephonyManager.NETWORK_TYPE_LTE,
+ ApnSetting.TYPE_IMS,
+ ApnSetting.PROTOCOL_IP,
+ DataFailCause.NONE);
+
+ mDataCallSessionStats.setTimeMillis(60000L);
+ mDataCallSessionStats.conclude();
+
+ ArgumentCaptor<DataCallSession> callCaptor =
+ ArgumentCaptor.forClass(DataCallSession.class);
+ verify(mPersistAtomsStorage, times(1)).addDataCallSession(
+ callCaptor.capture());
+ DataCallSession stats = callCaptor.getValue();
+
+ assertEquals(ApnSetting.TYPE_IMS, stats.apnTypeBitmask);
+ assertEquals(1, stats.durationMinutes);
+ assertEquals(TelephonyManager.NETWORK_TYPE_LTE, stats.ratAtEnd);
+ assertTrue(stats.ongoing);
+ }
+
+ @Test
+ @SmallTest
+ public void testSetupDataCallOnIwlan_success() {
+ mDataCallSessionStats.onSetupDataCall(ApnSetting.TYPE_IMS);
+ mDataCallSessionStats.onSetupDataCallResponse(
+ mDefaultImsResponse,
+ TelephonyManager.NETWORK_TYPE_IWLAN,
+ ApnSetting.TYPE_IMS,
+ ApnSetting.PROTOCOL_IP,
+ DataFailCause.NONE);
+
+ mDataCallSessionStats.setTimeMillis(120000L);
+ mDataCallSessionStats.conclude();
+
+ ArgumentCaptor<DataCallSession> callCaptor =
+ ArgumentCaptor.forClass(DataCallSession.class);
+ verify(mPersistAtomsStorage, times(1)).addDataCallSession(
+ callCaptor.capture());
+ DataCallSession stats = callCaptor.getValue();
+
+ assertEquals(ApnSetting.TYPE_IMS, stats.apnTypeBitmask);
+ assertEquals(2, stats.durationMinutes);
+ assertEquals(TelephonyManager.NETWORK_TYPE_IWLAN, stats.ratAtEnd);
+ assertFalse(stats.isIwlanCrossSim);
+ assertTrue(stats.ongoing);
+ }
+
+ @Test
+ @SmallTest
+ public void testSetupDataCallOnCrossSimCalling_success() {
+ getNetworkMonitorCallback().onAvailable(mMockNetwork);
+ getNetworkMonitorCallback().onCapabilitiesChanged(
+ mMockNetwork, mCellularNetworkCapabilities);
+ mDataCallSessionStats.onSetupDataCall(ApnSetting.TYPE_IMS);
+ mDataCallSessionStats.onSetupDataCallResponse(
+ mDefaultImsResponse,
+ TelephonyManager.NETWORK_TYPE_IWLAN,
+ ApnSetting.TYPE_IMS,
+ ApnSetting.PROTOCOL_IP,
+ DataFailCause.NONE);
+
+ mDataCallSessionStats.setTimeMillis(60000L);
+ mDataCallSessionStats.conclude();
+
+ ArgumentCaptor<DataCallSession> callCaptor =
+ ArgumentCaptor.forClass(DataCallSession.class);
+ verify(mPersistAtomsStorage, times(1)).addDataCallSession(
+ callCaptor.capture());
+ DataCallSession stats = callCaptor.getValue();
+
+ assertEquals(ApnSetting.TYPE_IMS, stats.apnTypeBitmask);
+ assertEquals(1, stats.durationMinutes);
+ assertEquals(TelephonyManager.NETWORK_TYPE_IWLAN, stats.ratAtEnd);
+ assertTrue(stats.isIwlanCrossSim);
+ assertTrue(stats.ongoing);
+ }
+
+ @Test
+ @SmallTest
+ public void testSetupDataCallOnCellularIms_failure() {
+ mDataCallSessionStats.onSetupDataCall(ApnSetting.TYPE_IMS);
+ mDataCallSessionStats.onSetupDataCallResponse(
+ mDefaultImsResponse,
+ TelephonyManager.NETWORK_TYPE_LTE,
+ ApnSetting.TYPE_IMS,
+ ApnSetting.PROTOCOL_IP,
+ DataFailCause.NETWORK_FAILURE);
+
+ ArgumentCaptor<DataCallSession> callCaptor =
+ ArgumentCaptor.forClass(DataCallSession.class);
+ verify(mPersistAtomsStorage, times(1)).addDataCallSession(
+ callCaptor.capture());
+ DataCallSession stats = callCaptor.getValue();
+
+ assertEquals(ApnSetting.TYPE_IMS, stats.apnTypeBitmask);
+ assertEquals(0, stats.durationMinutes);
+ assertEquals(TelephonyManager.NETWORK_TYPE_LTE, stats.ratAtEnd);
+ assertFalse(stats.ongoing);
+ }
+
+ @Test
+ @SmallTest
+ public void testHandoverFromCellularToIwlan_success() {
+ mDataCallSessionStats.onSetupDataCall(ApnSetting.TYPE_IMS);
+ mDataCallSessionStats.onSetupDataCallResponse(
+ mDefaultImsResponse,
+ TelephonyManager.NETWORK_TYPE_LTE,
+ ApnSetting.TYPE_IMS,
+ ApnSetting.PROTOCOL_IP,
+ DataFailCause.NONE);
+
+ mDataCallSessionStats.onDrsOrRatChanged(TelephonyManager.NETWORK_TYPE_IWLAN);
+ mDataCallSessionStats.conclude();
+
+ ArgumentCaptor<DataCallSession> callCaptor =
+ ArgumentCaptor.forClass(DataCallSession.class);
+ verify(mPersistAtomsStorage, times(1)).addDataCallSession(
+ callCaptor.capture());
+ DataCallSession stats = callCaptor.getValue();
+
+ assertEquals(ApnSetting.TYPE_IMS, stats.apnTypeBitmask);
+ assertEquals(TelephonyManager.NETWORK_TYPE_IWLAN, stats.ratAtEnd);
+ assertEquals(1, stats.ratSwitchCount);
+ assertTrue(stats.ongoing);
+ }
+
+ @Test
+ @SmallTest
+ public void testHandoverFromCellularToCrossSimCalling_success() {
+ mDataCallSessionStats.onSetupDataCall(ApnSetting.TYPE_IMS);
+ mDataCallSessionStats.onSetupDataCallResponse(
+ mDefaultImsResponse,
+ TelephonyManager.NETWORK_TYPE_LTE,
+ ApnSetting.TYPE_IMS,
+ ApnSetting.PROTOCOL_IP,
+ DataFailCause.NONE);
+
+ getNetworkMonitorCallback().onAvailable(mMockNetwork);
+ getNetworkMonitorCallback().onCapabilitiesChanged(
+ mMockNetwork, mCellularNetworkCapabilities);
+ mDataCallSessionStats.onDrsOrRatChanged(TelephonyManager.NETWORK_TYPE_IWLAN);
+ mDataCallSessionStats.conclude();
+
+ ArgumentCaptor<DataCallSession> callCaptor =
+ ArgumentCaptor.forClass(DataCallSession.class);
+ verify(mPersistAtomsStorage, times(1)).addDataCallSession(
+ callCaptor.capture());
+ DataCallSession stats = callCaptor.getValue();
+
+ assertEquals(ApnSetting.TYPE_IMS, stats.apnTypeBitmask);
+ assertEquals(TelephonyManager.NETWORK_TYPE_IWLAN, stats.ratAtEnd);
+ assertEquals(1, stats.ratSwitchCount);
+ assertTrue(stats.isIwlanCrossSim);
+ assertTrue(stats.ongoing);
+ }
+
+ @Test
+ @SmallTest
+ public void testHandoverFromCellularToIwlan_failure() {
+ mDataCallSessionStats.onSetupDataCall(ApnSetting.TYPE_IMS);
+ mDataCallSessionStats.onSetupDataCallResponse(
+ mDefaultImsResponse,
+ TelephonyManager.NETWORK_TYPE_LTE,
+ ApnSetting.TYPE_IMS,
+ ApnSetting.PROTOCOL_IP,
+ DataFailCause.NONE);
+
+ mDataCallSessionStats.onHandoverFailure(DataFailCause.IWLAN_DNS_RESOLUTION_TIMEOUT,
+ TelephonyManager.NETWORK_TYPE_LTE, TelephonyManager.NETWORK_TYPE_IWLAN);
+ mDataCallSessionStats.conclude();
+
+ ArgumentCaptor<DataCallSession> callCaptor =
+ ArgumentCaptor.forClass(DataCallSession.class);
+ verify(mPersistAtomsStorage, times(1)).addDataCallSession(
+ callCaptor.capture());
+ DataCallSession stats = callCaptor.getValue();
+
+ assertEquals(ApnSetting.TYPE_IMS, stats.apnTypeBitmask);
+ assertEquals(TelephonyManager.NETWORK_TYPE_LTE, stats.ratAtEnd);
+ assertTrue(stats.ongoing);
+ assertEquals(DataFailCause.IWLAN_DNS_RESOLUTION_TIMEOUT,
+ stats.handoverFailureCauses[0]);
+
+ int cellularToIwlanFailureDirection = TelephonyManager.NETWORK_TYPE_LTE
+ | (TelephonyManager.NETWORK_TYPE_IWLAN << 16);
+ assertEquals(cellularToIwlanFailureDirection, stats.handoverFailureRat[0]);
+ }
+
+ @Test
+ @SmallTest
+ public void testSetupDataCallOnIwlan_success_thenOOS() {
+ mDataCallSessionStats.onSetupDataCall(ApnSetting.TYPE_IMS);
+ mDataCallSessionStats.onSetupDataCallResponse(
+ mDefaultImsResponse,
+ TelephonyManager.NETWORK_TYPE_IWLAN,
+ ApnSetting.TYPE_IMS,
+ ApnSetting.PROTOCOL_IP,
+ DataFailCause.NONE);
+ when(mServiceState.getDataRegistrationState())
+ .thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
+ mDataCallSessionStats.onDataCallDisconnected(DataFailCause.IWLAN_IKE_DPD_TIMEOUT);
+
+ ArgumentCaptor<DataCallSession> callCaptor =
+ ArgumentCaptor.forClass(DataCallSession.class);
+ verify(mPersistAtomsStorage, times(1)).addDataCallSession(
+ callCaptor.capture());
+ DataCallSession stats = callCaptor.getValue();
+
+ assertEquals(ApnSetting.TYPE_IMS, stats.apnTypeBitmask);
+ assertEquals(TelephonyManager.NETWORK_TYPE_IWLAN, stats.ratAtEnd);
+ assertTrue(stats.oosAtEnd);
+ assertFalse(stats.ongoing);
+ }
+}