Loading flags/data.aconfig +7 −0 Original line number Diff line number Diff line Loading @@ -97,3 +97,10 @@ flag { 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" } src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java +16 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.internal.telephony.metrics; 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; Loading Loading @@ -62,8 +63,16 @@ public class DataCallSessionStats { 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. */ Loading Loading @@ -101,6 +110,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 && isSystemDefaultNetworkMobile(); } // only set if apn hasn't been set during setup Loading Loading @@ -199,6 +211,8 @@ public class DataCallSessionStats { 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 = Loading Loading @@ -288,6 +302,7 @@ public class DataCallSessionStats { copy.handoverFailureRat = Arrays.copyOf(call.handoverFailureRat, call.handoverFailureRat.length); copy.isNonDds = call.isNonDds; copy.isIwlanCrossSim = call.isIwlanCrossSim; return copy; } Loading @@ -313,6 +328,7 @@ public class DataCallSessionStats { proto.handoverFailureCauses = new int[0]; proto.handoverFailureRat = new int[0]; proto.isNonDds = false; proto.isIwlanCrossSim = false; return proto; } Loading src/java/com/android/internal/telephony/metrics/DefaultNetworkMonitor.java 0 → 100644 +90 −0 Original line number Diff line number Diff line /* * 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; } } src/java/com/android/internal/telephony/metrics/MetricsCollector.java +8 −2 Original line number Diff line number Diff line Loading @@ -171,19 +171,20 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { 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); Loading Loading @@ -232,6 +233,7 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { } mAirplaneModeStats = new AirplaneModeStats(context); mDefaultNetworkMonitor = new DefaultNetworkMonitor(context, featureFlags); } /** Loading Loading @@ -362,6 +364,10 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { mOngoingDataCallStats.remove(call); } public DefaultNetworkMonitor getDefaultNetworkMonitor() { return mDefaultNetworkMonitor; } private void concludeDataCallSessionStats() { for (DataCallSessionStats stats : mOngoingDataCallStats) { stats.conclude(); Loading tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java +4 −0 Original line number Diff line number Diff line Loading @@ -115,6 +115,7 @@ import com.android.internal.telephony.imsphone.ImsExternalCallTracker; 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; Loading Loading @@ -265,6 +266,7 @@ public abstract class TelephonyTest { protected CarrierPrivilegesTracker mCarrierPrivilegesTracker; protected VoiceCallSessionStats mVoiceCallSessionStats; protected PersistAtomsStorage mPersistAtomsStorage; protected DefaultNetworkMonitor mDefaultNetworkMonitor; protected MetricsCollector mMetricsCollector; protected SmsStats mSmsStats; protected TelephonyAnalytics mTelephonyAnalytics; Loading Loading @@ -538,6 +540,7 @@ public abstract class TelephonyTest { 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); Loading Loading @@ -887,6 +890,7 @@ public abstract class TelephonyTest { // 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) Loading Loading
flags/data.aconfig +7 −0 Original line number Diff line number Diff line Loading @@ -97,3 +97,10 @@ flag { 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" }
src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java +16 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.internal.telephony.metrics; 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; Loading Loading @@ -62,8 +63,16 @@ public class DataCallSessionStats { 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. */ Loading Loading @@ -101,6 +110,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 && isSystemDefaultNetworkMobile(); } // only set if apn hasn't been set during setup Loading Loading @@ -199,6 +211,8 @@ public class DataCallSessionStats { 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 = Loading Loading @@ -288,6 +302,7 @@ public class DataCallSessionStats { copy.handoverFailureRat = Arrays.copyOf(call.handoverFailureRat, call.handoverFailureRat.length); copy.isNonDds = call.isNonDds; copy.isIwlanCrossSim = call.isIwlanCrossSim; return copy; } Loading @@ -313,6 +328,7 @@ public class DataCallSessionStats { proto.handoverFailureCauses = new int[0]; proto.handoverFailureRat = new int[0]; proto.isNonDds = false; proto.isIwlanCrossSim = false; return proto; } Loading
src/java/com/android/internal/telephony/metrics/DefaultNetworkMonitor.java 0 → 100644 +90 −0 Original line number Diff line number Diff line /* * 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; } }
src/java/com/android/internal/telephony/metrics/MetricsCollector.java +8 −2 Original line number Diff line number Diff line Loading @@ -171,19 +171,20 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { 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); Loading Loading @@ -232,6 +233,7 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { } mAirplaneModeStats = new AirplaneModeStats(context); mDefaultNetworkMonitor = new DefaultNetworkMonitor(context, featureFlags); } /** Loading Loading @@ -362,6 +364,10 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { mOngoingDataCallStats.remove(call); } public DefaultNetworkMonitor getDefaultNetworkMonitor() { return mDefaultNetworkMonitor; } private void concludeDataCallSessionStats() { for (DataCallSessionStats stats : mOngoingDataCallStats) { stats.conclude(); Loading
tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java +4 −0 Original line number Diff line number Diff line Loading @@ -115,6 +115,7 @@ import com.android.internal.telephony.imsphone.ImsExternalCallTracker; 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; Loading Loading @@ -265,6 +266,7 @@ public abstract class TelephonyTest { protected CarrierPrivilegesTracker mCarrierPrivilegesTracker; protected VoiceCallSessionStats mVoiceCallSessionStats; protected PersistAtomsStorage mPersistAtomsStorage; protected DefaultNetworkMonitor mDefaultNetworkMonitor; protected MetricsCollector mMetricsCollector; protected SmsStats mSmsStats; protected TelephonyAnalytics mTelephonyAnalytics; Loading Loading @@ -538,6 +540,7 @@ public abstract class TelephonyTest { 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); Loading Loading @@ -887,6 +890,7 @@ public abstract class TelephonyTest { // 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) Loading