Register OnSubscriptionsChangedListener and cache results.
Register a listener to get notified of SubscriptionInfo changes and
store all carrierIds of active subscriptions in a cache. The executor
for the listener callback runs on a different thread to the connectivity
thread but posts the SubscriptionInfo list to the connectivity thread
for caching.
Bug: 273451360
Test: atest FrameworksNetTests
(cherry picked from https://android-review.googlesource.com/q/commit:c48d856976c9fcb8150f4de524d69cc5d68ce46d)
Merged-In: I889d4da725ccda713367309c257622a0bf9939f3
Change-Id: I889d4da725ccda713367309c257622a0bf9939f3
diff --git a/service/src/com/android/server/connectivity/AutomaticOnOffKeepaliveTracker.java b/service/src/com/android/server/connectivity/AutomaticOnOffKeepaliveTracker.java
index b4e466a..3f0d14c 100644
--- a/service/src/com/android/server/connectivity/AutomaticOnOffKeepaliveTracker.java
+++ b/service/src/com/android/server/connectivity/AutomaticOnOffKeepaliveTracker.java
@@ -307,7 +307,7 @@
mContext, mConnectivityServiceHandler);
mAlarmManager = mDependencies.getAlarmManager(context);
- mKeepaliveStatsTracker = new KeepaliveStatsTracker(handler);
+ mKeepaliveStatsTracker = new KeepaliveStatsTracker(context, handler);
}
private void startTcpPollingAlarm(@NonNull AutomaticOnOffKeepalive ki) {
diff --git a/service/src/com/android/server/connectivity/KeepaliveStatsTracker.java b/service/src/com/android/server/connectivity/KeepaliveStatsTracker.java
index 81345ab..9f08673 100644
--- a/service/src/com/android/server/connectivity/KeepaliveStatsTracker.java
+++ b/service/src/com/android/server/connectivity/KeepaliveStatsTracker.java
@@ -16,14 +16,24 @@
package com.android.server.connectivity;
+import static android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
+
import android.annotation.NonNull;
+import android.content.Context;
import android.net.Network;
import android.net.NetworkCapabilities;
+import android.net.NetworkSpecifier;
+import android.net.TelephonyNetworkSpecifier;
+import android.net.TransportInfo;
+import android.net.wifi.WifiInfo;
import android.os.Handler;
import android.os.SystemClock;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.util.SparseArray;
+import android.util.SparseIntArray;
import com.android.internal.annotations.VisibleForTesting;
import com.android.metrics.DailykeepaliveInfoReported;
@@ -31,6 +41,7 @@
import com.android.metrics.DurationPerNumOfKeepalive;
import com.android.metrics.KeepaliveLifetimeForCarrier;
import com.android.metrics.KeepaliveLifetimePerCarrier;
+import com.android.modules.utils.BackgroundThread;
import java.util.ArrayList;
import java.util.HashMap;
@@ -52,6 +63,14 @@
@NonNull private final Handler mConnectivityServiceHandler;
@NonNull private final Dependencies mDependencies;
+ // Mapping of subId to carrierId. Updates are received from OnSubscriptionsChangedListener
+ private final SparseIntArray mCachedCarrierIdPerSubId = new SparseIntArray();
+ // The default subscription id obtained from SubscriptionManager.getDefaultSubscriptionId.
+ // Updates are done from the OnSubscriptionsChangedListener. Note that there is no callback done
+ // to OnSubscriptionsChangedListener when the default sub id changes.
+ // TODO: Register a listener for the default subId when it is possible.
+ private int mCachedDefaultSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+
// Class to store network information, lifetime durations and active state of a keepalive.
private static final class KeepaliveStats {
// The carrier ID for a keepalive, or TelephonyManager.UNKNOWN_CARRIER_ID(-1) if not set.
@@ -214,16 +233,53 @@
}
}
- public KeepaliveStatsTracker(@NonNull Handler handler) {
- this(handler, new Dependencies());
+ public KeepaliveStatsTracker(@NonNull Context context, @NonNull Handler handler) {
+ this(context, handler, new Dependencies());
}
@VisibleForTesting
- public KeepaliveStatsTracker(@NonNull Handler handler, @NonNull Dependencies dependencies) {
+ public KeepaliveStatsTracker(
+ @NonNull Context context,
+ @NonNull Handler handler,
+ @NonNull Dependencies dependencies) {
+ Objects.requireNonNull(context);
mDependencies = Objects.requireNonNull(dependencies);
mConnectivityServiceHandler = Objects.requireNonNull(handler);
+ final SubscriptionManager subscriptionManager =
+ Objects.requireNonNull(context.getSystemService(SubscriptionManager.class));
+
mLastUpdateDurationsTimestamp = mDependencies.getUptimeMillis();
+
+ // The default constructor for OnSubscriptionsChangedListener will always implicitly grab
+ // the looper of the current thread. In the case the current thread does not have a looper,
+ // this will throw. Therefore, post a runnable that creates it there.
+ // When the callback is called on the BackgroundThread, post a message on the CS handler
+ // thread to update the caches, which can only be touched there.
+ BackgroundThread.getHandler().post(() ->
+ subscriptionManager.addOnSubscriptionsChangedListener(
+ r -> r.run(), new OnSubscriptionsChangedListener() {
+ @Override
+ public void onSubscriptionsChanged() {
+ final List<SubscriptionInfo> activeSubInfoList =
+ subscriptionManager.getActiveSubscriptionInfoList();
+ // A null subInfo list here indicates the current state is unknown
+ // but not necessarily empty, simply ignore it. Another call to the
+ // listener will be invoked in the future.
+ if (activeSubInfoList == null) return;
+ final int defaultSubId =
+ subscriptionManager.getDefaultSubscriptionId();
+ mConnectivityServiceHandler.post(() -> {
+ mCachedCarrierIdPerSubId.clear();
+ mCachedDefaultSubscriptionId = defaultSubId;
+
+ for (final SubscriptionInfo subInfo : activeSubInfoList) {
+ mCachedCarrierIdPerSubId.put(subInfo.getSubscriptionId(),
+ subInfo.getCarrierId());
+ }
+ });
+ }
+ }));
}
/** Ensures the list of duration metrics is large enough for number of registered keepalives. */
@@ -279,11 +335,33 @@
mLastUpdateDurationsTimestamp = timeNow;
}
- // TODO(b/273451360): Make use of SubscriptionManager.OnSubscriptionsChangedListener since
- // TelephonyManager.getSimCarrierId will be a cross-process call.
- private int getCarrierId() {
- // No implementation yet.
- return TelephonyManager.UNKNOWN_CARRIER_ID;
+ // TODO: Move this function to frameworks/libs/net/.../NetworkCapabilitiesUtils.java
+ private static int getSubId(@NonNull NetworkCapabilities nc, int defaultSubId) {
+ if (nc.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
+ final NetworkSpecifier networkSpecifier = nc.getNetworkSpecifier();
+ if (networkSpecifier instanceof TelephonyNetworkSpecifier) {
+ return ((TelephonyNetworkSpecifier) networkSpecifier).getSubscriptionId();
+ }
+ // Use the default subscriptionId.
+ return defaultSubId;
+ }
+ if (nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
+ final TransportInfo info = nc.getTransportInfo();
+ if (info instanceof WifiInfo) {
+ return ((WifiInfo) info).getSubscriptionId();
+ }
+ }
+
+ return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ }
+
+ private int getCarrierId(@NonNull NetworkCapabilities networkCapabilities) {
+ // Try to get the correct subscription id.
+ final int subId = getSubId(networkCapabilities, mCachedDefaultSubscriptionId);
+ if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ return TelephonyManager.UNKNOWN_CARRIER_ID;
+ }
+ return mCachedCarrierIdPerSubId.get(subId, TelephonyManager.UNKNOWN_CARRIER_ID);
}
private int getTransportTypes(@NonNull NetworkCapabilities networkCapabilities) {
@@ -313,7 +391,7 @@
final KeepaliveStats newKeepaliveStats =
new KeepaliveStats(
- getCarrierId(), getTransportTypes(nc), intervalSeconds, timeNow);
+ getCarrierId(nc), getTransportTypes(nc), intervalSeconds, timeNow);
mKeepaliveStatsPerId.put(keepaliveId, newKeepaliveStats);
}
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index 595b786..bb55aee 100755
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -355,6 +355,7 @@
import android.provider.Settings;
import android.security.Credentials;
import android.system.Os;
+import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telephony.data.EpsBearerQosSessionAttributes;
import android.telephony.data.NrQosSessionAttributes;
@@ -616,6 +617,7 @@
@Mock BroadcastOptionsShim mBroadcastOptionsShim;
@Mock ActivityManager mActivityManager;
@Mock DestroySocketsWrapper mDestroySocketsWrapper;
+ @Mock SubscriptionManager mSubscriptionManager;
// BatteryStatsManager is final and cannot be mocked with regular mockito, so just mock the
// underlying binder calls.
@@ -740,6 +742,7 @@
if (Context.PAC_PROXY_SERVICE.equals(name)) return mPacProxyManager;
if (Context.TETHERING_SERVICE.equals(name)) return mTetheringManager;
if (Context.ACTIVITY_SERVICE.equals(name)) return mActivityManager;
+ if (Context.TELEPHONY_SUBSCRIPTION_SERVICE.equals(name)) return mSubscriptionManager;
return super.getSystemService(name);
}
diff --git a/tests/unit/java/com/android/server/connectivity/AutomaticOnOffKeepaliveTrackerTest.java b/tests/unit/java/com/android/server/connectivity/AutomaticOnOffKeepaliveTrackerTest.java
index e3d5c64..0aecd64 100644
--- a/tests/unit/java/com/android/server/connectivity/AutomaticOnOffKeepaliveTrackerTest.java
+++ b/tests/unit/java/com/android/server/connectivity/AutomaticOnOffKeepaliveTrackerTest.java
@@ -36,6 +36,7 @@
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.longThat;
import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doCallRealMethod;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.ignoreStubs;
@@ -67,6 +68,7 @@
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
+import android.telephony.SubscriptionManager;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
@@ -121,6 +123,7 @@
@Mock Context mCtx;
@Mock AlarmManager mAlarmManager;
@Mock NetworkAgentInfo mNai;
+ @Mock SubscriptionManager mSubscriptionManager;
TestKeepaliveTracker mKeepaliveTracker;
AOOTestHandler mTestHandler;
@@ -298,10 +301,22 @@
}
}
+ private <T> void mockService(String serviceName, Class<T> serviceClass, T service) {
+ doReturn(serviceName).when(mCtx).getSystemServiceName(serviceClass);
+ doReturn(service).when(mCtx).getSystemService(serviceName);
+ if (mCtx.getSystemService(serviceClass) == null) {
+ // Test is using mockito-extended
+ doCallRealMethod().when(mCtx).getSystemService(serviceClass);
+ }
+ }
+
@Before
public void setup() throws Exception {
MockitoAnnotations.initMocks(this);
+ mockService(Context.TELEPHONY_SUBSCRIPTION_SERVICE, SubscriptionManager.class,
+ mSubscriptionManager);
+
mNai.networkCapabilities =
new NetworkCapabilities.Builder().addTransportType(TRANSPORT_CELLULAR).build();
mNai.networkInfo = new NetworkInfo(TYPE_MOBILE, 0 /* subtype */, "LTE", "LTE");
diff --git a/tests/unit/java/com/android/server/connectivity/KeepaliveStatsTrackerTest.java b/tests/unit/java/com/android/server/connectivity/KeepaliveStatsTrackerTest.java
index 369894d..b469ccd 100644
--- a/tests/unit/java/com/android/server/connectivity/KeepaliveStatsTrackerTest.java
+++ b/tests/unit/java/com/android/server/connectivity/KeepaliveStatsTrackerTest.java
@@ -17,6 +17,7 @@
package com.android.server.connectivity;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static com.android.testutils.HandlerUtils.visibleOnHandlerThread;
@@ -25,13 +26,24 @@
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.doCallRealMethod;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import android.content.Context;
import android.net.Network;
import android.net.NetworkCapabilities;
+import android.net.TelephonyNetworkSpecifier;
+import android.net.wifi.WifiInfo;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
import android.telephony.TelephonyManager;
import androidx.test.filters.SmallTest;
@@ -41,39 +53,68 @@
import com.android.metrics.DurationPerNumOfKeepalive;
import com.android.metrics.KeepaliveLifetimeForCarrier;
import com.android.metrics.KeepaliveLifetimePerCarrier;
+import com.android.modules.utils.BackgroundThread;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRunner;
+import com.android.testutils.HandlerUtils;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.Arrays;
import java.util.HashSet;
+import java.util.List;
import java.util.Set;
@RunWith(DevSdkIgnoreRunner.class)
@SmallTest
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.TIRAMISU)
public class KeepaliveStatsTrackerTest {
+ private static final int TIMEOUT_MS = 30_000;
+
private static final int TEST_SLOT = 1;
private static final int TEST_SLOT2 = 2;
private static final int TEST_KEEPALIVE_INTERVAL_SEC = 10;
private static final int TEST_KEEPALIVE_INTERVAL2_SEC = 20;
- // Carrier id not yet implemented, assume it returns unknown for now.
- private static final int TEST_CARRIER_ID = TelephonyManager.UNKNOWN_CARRIER_ID;
+ private static final int TEST_SUB_ID_1 = 1;
+ private static final int TEST_SUB_ID_2 = 2;
+ private static final int TEST_CARRIER_ID_1 = 135;
+ private static final int TEST_CARRIER_ID_2 = 246;
private static final Network TEST_NETWORK = new Network(123);
private static final NetworkCapabilities TEST_NETWORK_CAPABILITIES =
- new NetworkCapabilities.Builder().addTransportType(TRANSPORT_CELLULAR).build();
+ buildCellNetworkCapabilitiesWithSubId(TEST_SUB_ID_1);
+ private static final NetworkCapabilities TEST_NETWORK_CAPABILITIES_2 =
+ buildCellNetworkCapabilitiesWithSubId(TEST_SUB_ID_2);
+
+ private static NetworkCapabilities buildCellNetworkCapabilitiesWithSubId(int subId) {
+ final TelephonyNetworkSpecifier telephonyNetworkSpecifier =
+ new TelephonyNetworkSpecifier.Builder().setSubscriptionId(subId).build();
+ return new NetworkCapabilities.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+ .setNetworkSpecifier(telephonyNetworkSpecifier)
+ .build();
+ }
private HandlerThread mHandlerThread;
private Handler mTestHandler;
private KeepaliveStatsTracker mKeepaliveStatsTracker;
+ @Mock private Context mContext;
@Mock private KeepaliveStatsTracker.Dependencies mDependencies;
+ @Mock private SubscriptionManager mSubscriptionManager;
+
+ private OnSubscriptionsChangedListener getOnSubscriptionsChangedListener() {
+ final ArgumentCaptor<OnSubscriptionsChangedListener> listenerCaptor =
+ ArgumentCaptor.forClass(OnSubscriptionsChangedListener.class);
+ verify(mSubscriptionManager)
+ .addOnSubscriptionsChangedListener(any(), listenerCaptor.capture());
+ return listenerCaptor.getValue();
+ }
private static final class KeepaliveCarrierStats {
public final int carrierId;
@@ -116,23 +157,53 @@
// Use the default test carrier id, transportType and keepalive interval.
private KeepaliveCarrierStats getDefaultCarrierStats(int lifetimeMs, int activeLifetimeMs) {
return new KeepaliveCarrierStats(
- TEST_CARRIER_ID,
+ TEST_CARRIER_ID_1,
/* transportTypes= */ (1 << TRANSPORT_CELLULAR),
TEST_KEEPALIVE_INTERVAL_SEC * 1000,
lifetimeMs,
activeLifetimeMs);
}
+ private <T> void mockService(String serviceName, Class<T> serviceClass, T service) {
+ doReturn(serviceName).when(mContext).getSystemServiceName(serviceClass);
+ doReturn(service).when(mContext).getSystemService(serviceName);
+ if (mContext.getSystemService(serviceClass) == null) {
+ // Test is using mockito-extended
+ doCallRealMethod().when(mContext).getSystemService(serviceClass);
+ }
+ }
+
+ private SubscriptionInfo makeSubInfoMock(int subId, int carrierId) {
+ final SubscriptionInfo subInfo = mock(SubscriptionInfo.class);
+ doReturn(subId).when(subInfo).getSubscriptionId();
+ doReturn(carrierId).when(subInfo).getCarrierId();
+ return subInfo;
+ }
+
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+ mockService(Context.TELEPHONY_SUBSCRIPTION_SERVICE, SubscriptionManager.class,
+ mSubscriptionManager);
+
+ final SubscriptionInfo subInfo1 = makeSubInfoMock(TEST_SUB_ID_1, TEST_CARRIER_ID_1);
+ final SubscriptionInfo subInfo2 = makeSubInfoMock(TEST_SUB_ID_2, TEST_CARRIER_ID_2);
+
+ doReturn(List.of(subInfo1, subInfo2))
+ .when(mSubscriptionManager)
+ .getActiveSubscriptionInfoList();
mHandlerThread = new HandlerThread("KeepaliveStatsTrackerTest");
mHandlerThread.start();
mTestHandler = new Handler(mHandlerThread.getLooper());
setUptimeMillis(0);
- mKeepaliveStatsTracker = new KeepaliveStatsTracker(mTestHandler, mDependencies);
+ mKeepaliveStatsTracker = new KeepaliveStatsTracker(mContext, mTestHandler, mDependencies);
+ HandlerUtils.waitForIdle(BackgroundThread.getHandler(), TIMEOUT_MS);
+
+ // Initial onSubscriptionsChanged.
+ getOnSubscriptionsChangedListener().onSubscriptionsChanged();
+ HandlerUtils.waitForIdle(mTestHandler, TIMEOUT_MS);
}
private void setUptimeMillis(long time) {
@@ -158,13 +229,18 @@
}
private void onStartKeepalive(long time, int slot, int intervalSeconds) {
+ onStartKeepalive(time, slot, TEST_NETWORK_CAPABILITIES, intervalSeconds);
+ }
+
+ private void onStartKeepalive(long time, int slot, NetworkCapabilities nc) {
+ onStartKeepalive(time, slot, nc, TEST_KEEPALIVE_INTERVAL_SEC);
+ }
+
+ private void onStartKeepalive(
+ long time, int slot, NetworkCapabilities nc, int intervalSeconds) {
setUptimeMillis(time);
visibleOnHandlerThread(mTestHandler, () ->
- mKeepaliveStatsTracker.onStartKeepalive(
- TEST_NETWORK,
- slot,
- TEST_NETWORK_CAPABILITIES,
- intervalSeconds));
+ mKeepaliveStatsTracker.onStartKeepalive(TEST_NETWORK, slot, nc, intervalSeconds));
}
private void onPauseKeepalive(long time, int slot) {
@@ -732,7 +808,8 @@
onStartKeepalive(startTime1, TEST_SLOT);
- onStartKeepalive(startTime2, TEST_SLOT2, TEST_KEEPALIVE_INTERVAL2_SEC);
+ onStartKeepalive(startTime2, TEST_SLOT2, TEST_NETWORK_CAPABILITIES_2,
+ TEST_KEEPALIVE_INTERVAL2_SEC);
onStopKeepalive(stopTime1, TEST_SLOT);
@@ -759,7 +836,7 @@
getDefaultCarrierStats(stopTime1 - startTime1, stopTime1 - startTime1);
final KeepaliveCarrierStats expectKeepaliveCarrierStats2 =
new KeepaliveCarrierStats(
- TEST_CARRIER_ID,
+ TEST_CARRIER_ID_2,
/* transportTypes= */ (1 << TRANSPORT_CELLULAR),
TEST_KEEPALIVE_INTERVAL2_SEC * 1000,
writeTime - startTime2,
@@ -783,7 +860,7 @@
// Only the keepalive with interval of intervalSec2 is present.
final KeepaliveCarrierStats expectKeepaliveCarrierStats3 =
new KeepaliveCarrierStats(
- TEST_CARRIER_ID,
+ TEST_CARRIER_ID_2,
/* transportTypes= */ (1 << TRANSPORT_CELLULAR),
TEST_KEEPALIVE_INTERVAL2_SEC * 1000,
writeTime2 - writeTime,
@@ -861,4 +938,86 @@
getDefaultCarrierStats(expectRegisteredDurations[1], expectActiveDurations[1])
});
}
+
+ @Test
+ public void testCarrierIdChange_changeBeforeStart() {
+ // Update the list to only have sub_id_2 with carrier_id_1.
+ final SubscriptionInfo subInfo = makeSubInfoMock(TEST_SUB_ID_2, TEST_CARRIER_ID_1);
+ doReturn(List.of(subInfo)).when(mSubscriptionManager).getActiveSubscriptionInfoList();
+
+ getOnSubscriptionsChangedListener().onSubscriptionsChanged();
+ HandlerUtils.waitForIdle(mTestHandler, TIMEOUT_MS);
+
+ final int startTime = 1000;
+ final int writeTime = 5000;
+
+ onStartKeepalive(startTime, TEST_SLOT, TEST_NETWORK_CAPABILITIES);
+ onStartKeepalive(startTime, TEST_SLOT2, TEST_NETWORK_CAPABILITIES_2);
+
+ final DailykeepaliveInfoReported dailyKeepaliveInfoReported =
+ buildKeepaliveMetrics(writeTime);
+
+ // The network with sub_id_1 has an unknown carrier id.
+ final KeepaliveCarrierStats expectKeepaliveCarrierStats1 =
+ new KeepaliveCarrierStats(
+ TelephonyManager.UNKNOWN_CARRIER_ID,
+ /* transportTypes= */ (1 << TRANSPORT_CELLULAR),
+ TEST_KEEPALIVE_INTERVAL_SEC * 1000,
+ writeTime - startTime,
+ writeTime - startTime);
+
+ // The network with sub_id_2 has carrier_id_1.
+ final KeepaliveCarrierStats expectKeepaliveCarrierStats2 =
+ new KeepaliveCarrierStats(
+ TEST_CARRIER_ID_1,
+ /* transportTypes= */ (1 << TRANSPORT_CELLULAR),
+ TEST_KEEPALIVE_INTERVAL_SEC * 1000,
+ writeTime - startTime,
+ writeTime - startTime);
+ assertDailyKeepaliveInfoReported(
+ dailyKeepaliveInfoReported,
+ /* expectRegisteredDurations= */ new int[] {startTime, 0, writeTime - startTime},
+ /* expectActiveDurations= */ new int[] {startTime, 0, writeTime - startTime},
+ new KeepaliveCarrierStats[] {
+ expectKeepaliveCarrierStats1, expectKeepaliveCarrierStats2
+ });
+ }
+
+ @Test
+ public void testCarrierIdFromWifiInfo() {
+ final int startTime = 1000;
+ final int writeTime = 5000;
+
+ final WifiInfo wifiInfo = mock(WifiInfo.class);
+ final WifiInfo wifiInfoCopy = mock(WifiInfo.class);
+
+ // Building NetworkCapabilities stores a copy of the WifiInfo with makeCopy.
+ doReturn(wifiInfoCopy).when(wifiInfo).makeCopy(anyLong());
+ doReturn(TEST_SUB_ID_1).when(wifiInfo).getSubscriptionId();
+ doReturn(TEST_SUB_ID_1).when(wifiInfoCopy).getSubscriptionId();
+ final NetworkCapabilities nc =
+ new NetworkCapabilities.Builder()
+ .addTransportType(TRANSPORT_WIFI)
+ .setTransportInfo(wifiInfo)
+ .build();
+
+ onStartKeepalive(startTime, TEST_SLOT, nc);
+
+ final DailykeepaliveInfoReported dailyKeepaliveInfoReported =
+ buildKeepaliveMetrics(writeTime);
+
+ final KeepaliveCarrierStats expectKeepaliveCarrierStats =
+ new KeepaliveCarrierStats(
+ TEST_CARRIER_ID_1,
+ /* transportTypes= */ (1 << TRANSPORT_WIFI),
+ TEST_KEEPALIVE_INTERVAL_SEC * 1000,
+ writeTime - startTime,
+ writeTime - startTime);
+
+ assertDailyKeepaliveInfoReported(
+ dailyKeepaliveInfoReported,
+ /* expectRegisteredDurations= */ new int[] {startTime, writeTime - startTime},
+ /* expectActiveDurations= */ new int[] {startTime, writeTime - startTime},
+ new KeepaliveCarrierStats[] {expectKeepaliveCarrierStats});
+ }
}