DataCallSessionStats captures Cross-SIM calling
- This revert^2s commit 6c57c33cce121bf3f198752a165409a23fffe6ad,
- patches the fix on top of this commit, and
- gates the new functionality behind a feature flag.
FIX DESCRIPTION:
- The DefaultNetworkMonitor singleton prevents the memory leak bug with
multiple default network callback registrations, one per DataNetwork.
- DataCallSessionStats gets a reference to DefaultNetworkMonitor
on creation, to determine when a PDN is established on IWLAN, whether
it is WiFi Calling or Backup Calling.
Test: Updated DataCallSessionStatsTest, Live test with flag enabled to
verify data_call_session proto sets 'iwlan_cross_sim' during Backup
Calling. Verified no functional regression when flag is both enabled
and disabled.
Bug: 313956117
Change-Id: I869165a1fecf18a2eeaab18bd3a0b639d1fc8e1b
diff --git a/flags/data.aconfig b/flags/data.aconfig
index a74d279..daddc2e 100644
--- a/flags/data.aconfig
+++ b/flags/data.aconfig
@@ -97,3 +97,10 @@
description: "Ignore existing networks when checking if internet is allowed"
bug: "284420611"
}
+
+flag {
+ name: "data_call_session_stats_captures_cross_sim_calling"
+ namespace: "telephony"
+ description: "The DataCallSessionStats metrics will capture whether the IWLAN PDN is set up on cross-SIM calling."
+ bug: "313956117"
+}
diff --git a/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java b/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java
index afb87dd..e1f6309 100644
--- a/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java
+++ b/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java
@@ -19,6 +19,7 @@
import static com.android.internal.telephony.TelephonyStatsLog.DATA_CALL_SESSION__IP_TYPE__APN_PROTOCOL_IPV4;
import android.annotation.Nullable;
+import android.net.NetworkCapabilities;
import android.os.SystemClock;
import android.telephony.Annotation.ApnType;
import android.telephony.Annotation.DataFailureCause;
@@ -62,8 +63,16 @@
public static final int SIZE_LIMIT_HANDOVER_FAILURES = 15;
+ private final DefaultNetworkMonitor mDefaultNetworkMonitor;
+
public DataCallSessionStats(Phone phone) {
mPhone = phone;
+ mDefaultNetworkMonitor = PhoneFactory.getMetricsCollector().getDefaultNetworkMonitor();
+ }
+
+ private boolean isSystemDefaultNetworkMobile() {
+ NetworkCapabilities nc = mDefaultNetworkMonitor.getNetworkCapabilities();
+ return nc != null && nc.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR);
}
/** Creates a new ongoing atom when data call is set up. */
@@ -101,6 +110,9 @@
(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
+ && isSystemDefaultNetworkMobile();
}
// only set if apn hasn't been set during setup
@@ -199,6 +211,8 @@
if (mDataCallSession.ratAtEnd != currentRat) {
mDataCallSession.ratSwitchCount++;
mDataCallSession.ratAtEnd = currentRat;
+ mDataCallSession.isIwlanCrossSim = currentRat == TelephonyManager.NETWORK_TYPE_IWLAN
+ && isSystemDefaultNetworkMobile();
}
// band may have changed even if RAT was the same
mDataCallSession.bandAtEnd =
@@ -288,6 +302,7 @@
copy.handoverFailureRat = Arrays.copyOf(call.handoverFailureRat,
call.handoverFailureRat.length);
copy.isNonDds = call.isNonDds;
+ copy.isIwlanCrossSim = call.isIwlanCrossSim;
return copy;
}
@@ -313,6 +328,7 @@
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/DefaultNetworkMonitor.java b/src/java/com/android/internal/telephony/metrics/DefaultNetworkMonitor.java
new file mode 100644
index 0000000..1dab10b
--- /dev/null
+++ b/src/java/com/android/internal/telephony/metrics/DefaultNetworkMonitor.java
@@ -0,0 +1,90 @@
+/*
+ * 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 android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.os.Handler;
+import android.os.Looper;
+
+import com.android.internal.telephony.flags.FeatureFlags;
+import com.android.telephony.Rlog;
+
+/**
+ * Monitors the system default network registration and tracks the currently available
+ * {@link Network} and its {@link NetworkCapabilities}.
+ */
+public class DefaultNetworkMonitor extends Handler {
+
+ private static final String TAG = DefaultNetworkMonitor.class.getSimpleName();
+
+ @Nullable private NetworkCallback mDefaultNetworkCallback;
+ @Nullable private Network mNetwork;
+ @Nullable private NetworkCapabilities mNetworkCapabilities;
+
+ private final class DefaultNetworkCallback extends NetworkCallback {
+ @Override
+ public void onAvailable(@NonNull Network network) {
+ mNetwork = network;
+ }
+
+ @Override
+ public void onCapabilitiesChanged(@NonNull Network network,
+ @NonNull NetworkCapabilities nc) {
+ if (network == mNetwork) {
+ mNetworkCapabilities = nc;
+ }
+ }
+
+ @Override
+ public void onLost(@NonNull Network network) {
+ mNetwork = null;
+ mNetworkCapabilities = null;
+ }
+ }
+
+ DefaultNetworkMonitor(@NonNull Context context, @NonNull FeatureFlags featureFlags) {
+ super(Looper.myLooper());
+ if (featureFlags.dataCallSessionStatsCapturesCrossSimCalling()) {
+ registerSystemDefaultNetworkCallback(context);
+ }
+ }
+
+ private void registerSystemDefaultNetworkCallback(@NonNull Context context) {
+ if (mDefaultNetworkCallback != null) {
+ return;
+ }
+ ConnectivityManager connectivityManager =
+ context.getSystemService(ConnectivityManager.class);
+ if (connectivityManager != null) {
+ mDefaultNetworkCallback = new DefaultNetworkCallback();
+ connectivityManager.registerSystemDefaultNetworkCallback(
+ mDefaultNetworkCallback, this);
+ } else {
+ Rlog.e(TAG, "registerSystemDefaultNetworkCallback: ConnectivityManager is null!");
+ }
+ }
+
+ @Nullable public NetworkCapabilities getNetworkCapabilities() {
+ return mNetworkCapabilities;
+ }
+}
diff --git a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
index 8bd2547..da9bb54 100644
--- a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
+++ b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
@@ -171,19 +171,20 @@
private final StatsManager mStatsManager;
private final VonrHelper mVonrHelper;
private final AirplaneModeStats mAirplaneModeStats;
+ private final DefaultNetworkMonitor mDefaultNetworkMonitor;
private final Set<DataCallSessionStats> mOngoingDataCallStats = ConcurrentHashMap.newKeySet();
private static final Random sRandom = new Random();
public MetricsCollector(Context context, @NonNull FeatureFlags featureFlags) {
this(context, new PersistAtomsStorage(context),
- new DeviceStateHelper(context), new VonrHelper(featureFlags));
+ new DeviceStateHelper(context), new VonrHelper(featureFlags), featureFlags);
}
/** Allows dependency injection. Used during unit tests. */
@VisibleForTesting
public MetricsCollector(
Context context, PersistAtomsStorage storage, DeviceStateHelper deviceStateHelper,
- VonrHelper vonrHelper) {
+ VonrHelper vonrHelper, @NonNull FeatureFlags featureFlags) {
mStorage = storage;
mDeviceStateHelper = deviceStateHelper;
mStatsManager = (StatsManager) context.getSystemService(Context.STATS_MANAGER);
@@ -232,6 +233,7 @@
}
mAirplaneModeStats = new AirplaneModeStats(context);
+ mDefaultNetworkMonitor = new DefaultNetworkMonitor(context, featureFlags);
}
/**
@@ -362,6 +364,10 @@
mOngoingDataCallStats.remove(call);
}
+ public DefaultNetworkMonitor getDefaultNetworkMonitor() {
+ return mDefaultNetworkMonitor;
+ }
+
private void concludeDataCallSessionStats() {
for (DataCallSessionStats stats : mOngoingDataCallStats) {
stats.conclude();
diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
index 89e9075..eab52ef 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
@@ -115,6 +115,7 @@
import com.android.internal.telephony.imsphone.ImsNrSaModeHandler;
import com.android.internal.telephony.imsphone.ImsPhone;
import com.android.internal.telephony.imsphone.ImsPhoneCallTracker;
+import com.android.internal.telephony.metrics.DefaultNetworkMonitor;
import com.android.internal.telephony.metrics.DeviceStateHelper;
import com.android.internal.telephony.metrics.ImsStats;
import com.android.internal.telephony.metrics.MetricsCollector;
@@ -265,6 +266,7 @@
protected CarrierPrivilegesTracker mCarrierPrivilegesTracker;
protected VoiceCallSessionStats mVoiceCallSessionStats;
protected PersistAtomsStorage mPersistAtomsStorage;
+ protected DefaultNetworkMonitor mDefaultNetworkMonitor;
protected MetricsCollector mMetricsCollector;
protected SmsStats mSmsStats;
protected TelephonyAnalytics mTelephonyAnalytics;
@@ -538,6 +540,7 @@
mCarrierPrivilegesTracker = Mockito.mock(CarrierPrivilegesTracker.class);
mVoiceCallSessionStats = Mockito.mock(VoiceCallSessionStats.class);
mPersistAtomsStorage = Mockito.mock(PersistAtomsStorage.class);
+ mDefaultNetworkMonitor = Mockito.mock(DefaultNetworkMonitor.class);
mMetricsCollector = Mockito.mock(MetricsCollector.class);
mSmsStats = Mockito.mock(SmsStats.class);
mTelephonyAnalytics = Mockito.mock(TelephonyAnalytics.class);
@@ -887,6 +890,7 @@
// Metrics
doReturn(null).when(mContext).getFileStreamPath(anyString());
doReturn(mPersistAtomsStorage).when(mMetricsCollector).getAtomsStorage();
+ doReturn(mDefaultNetworkMonitor).when(mMetricsCollector).getDefaultNetworkMonitor();
doReturn(mWifiManager).when(mContext).getSystemService(eq(Context.WIFI_SERVICE));
doReturn(mDeviceStateHelper).when(mMetricsCollector).getDeviceStateHelper();
doReturn(CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_UNKNOWN)
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 0000000..d63dc3c
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/DataCallSessionStatsTest.java
@@ -0,0 +1,311 @@
+/*
+ * 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.doReturn;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.net.NetworkCapabilities;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+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.Rule;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+public class DataCallSessionStatsTest extends TelephonyTest {
+
+ private DataCallResponse mDefaultImsResponse = buildDataCallResponse("ims", 0);
+ 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;
+ }
+ }
+
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule =
+ DeviceFlagsValueProvider.createCheckFlagsRule();
+ private TestableDataCallSessionStats mDataCallSessionStats;
+ private NetworkCapabilities mCellularNetworkCapabilities = new NetworkCapabilities.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR).build();
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp(getClass().getSimpleName());
+ when(mServiceState.getDataRegistrationState()).thenReturn(ServiceState.STATE_IN_SERVICE);
+ mDataCallSessionStats = new TestableDataCallSessionStats(mPhone);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mDataCallSessionStats = null;
+ super.tearDown();
+ }
+
+ 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() {
+ doReturn(mCellularNetworkCapabilities)
+ .when(mDefaultNetworkMonitor).getNetworkCapabilities();
+ 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);
+
+ doReturn(mCellularNetworkCapabilities)
+ .when(mDefaultNetworkMonitor).getNetworkCapabilities();
+ 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);
+ }
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/MetricsCollectorTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/MetricsCollectorTest.java
index 0e1135e..07fc2d0 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/metrics/MetricsCollectorTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/MetricsCollectorTest.java
@@ -43,6 +43,7 @@
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneFactory;
import com.android.internal.telephony.TelephonyTest;
+import com.android.internal.telephony.flags.FeatureFlags;
import com.android.internal.telephony.nano.PersistAtomsProto.CellularDataServiceSwitch;
import com.android.internal.telephony.nano.PersistAtomsProto.CellularServiceState;
import com.android.internal.telephony.nano.PersistAtomsProto.OutgoingShortCodeSms;
@@ -96,6 +97,7 @@
private UiccPort mActivePort;
private ServiceStateStats mServiceStateStats;
private VonrHelper mVonrHelper;
+ private FeatureFlags mFeatureFlags;
private MetricsCollector mMetricsCollector;
@@ -109,9 +111,10 @@
mActivePort = mock(UiccPort.class);
mServiceStateStats = mock(ServiceStateStats.class);
mVonrHelper = mock(VonrHelper.class);
+ mFeatureFlags = mock(FeatureFlags.class);
mMetricsCollector =
new MetricsCollector(mContext, mPersistAtomsStorage,
- mDeviceStateHelper, mVonrHelper);
+ mDeviceStateHelper, mVonrHelper, mFeatureFlags);
doReturn(mSST).when(mSecondPhone).getServiceStateTracker();
doReturn(mServiceStateStats).when(mSST).getServiceStateStats();
}