[Passpoint] Ignore expired profiles in network evaluator

When matching Passpoint profiles while scanning, consider the
expiration date of the profile, if set. Ignore expired profiles.
This prevents the case where the system will continuously try to
connect to networks with expired credentials.

Bug: 141474717
Test: atest PasspointManagerTest
Test: Provision a profile with expiration date in the past, confirm
that network selection does not select it, and does not connect to
it, even when in range.

Change-Id: Iec329d2f69a905646a5ee85172060fb3c5d5f164
diff --git a/service/java/com/android/server/wifi/hotspot2/PasspointManager.java b/service/java/com/android/server/wifi/hotspot2/PasspointManager.java
index 0c795dc..af4a6c8 100644
--- a/service/java/com/android/server/wifi/hotspot2/PasspointManager.java
+++ b/service/java/com/android/server/wifi/hotspot2/PasspointManager.java
@@ -767,12 +767,14 @@
         }
         Pair<PasspointProvider, PasspointMatch> bestMatch = null;
         for (Pair<PasspointProvider, PasspointMatch> match : allMatches) {
-            if (match.second == PasspointMatch.HomeProvider) {
-                bestMatch = match;
-                break;
-            }
-            if (match.second == PasspointMatch.RoamingProvider && bestMatch == null) {
-                bestMatch = match;
+            if (!isExpired(match.first.getConfig())) {
+                if (match.second == PasspointMatch.HomeProvider) {
+                    bestMatch = match;
+                    break;
+                }
+                if (match.second == PasspointMatch.RoamingProvider && bestMatch == null) {
+                    bestMatch = match;
+                }
             }
         }
         if (bestMatch != null) {
@@ -1209,4 +1211,28 @@
             IProvisioningCallback callback) {
         return mPasspointProvisioner.startSubscriptionProvisioning(callingUid, provider, callback);
     }
+
+    /**
+     * Check if a Passpoint configuration is expired
+     *
+     * @param config {@link PasspointConfiguration} Passpoint configuration
+     * @return True if the configuration is expired, false if not or expiration is unset
+     */
+    private boolean isExpired(@NonNull PasspointConfiguration config) {
+        long expirationTime = config.getSubscriptionExpirationTimeInMillis();
+
+        if (expirationTime != Long.MIN_VALUE) {
+            long curTime = System.currentTimeMillis();
+
+            // Check expiration and return true for expired profiles
+            if (curTime >= expirationTime) {
+                Log.d(TAG, "Profile for " + config.getServiceFriendlyName() + " has expired, "
+                        + "expiration time: " + expirationTime + ", current time: "
+                        + curTime);
+                return true;
+            }
+        }
+
+        return false;
+    }
 }
diff --git a/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java
index a4288fb..41cf336 100644
--- a/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java
@@ -2172,4 +2172,144 @@
             session.finishMocking();
         }
     }
+
+    /**
+     * Verify that the HomeProvider provider will be returned when a HomeProvider profile has
+     * not expired and RoamingProvider expiration is unset (still valid).
+     *
+     * @throws Exception
+     */
+    @Test
+    public void matchHomeProviderWhenHomeProviderNotExpired() throws Exception {
+        // static mocking
+        MockitoSession session =
+                com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession().mockStatic(
+                        InformationElementUtil.class).startMocking();
+        try {
+            PasspointProvider providerHome = addTestProvider(TEST_FQDN, TEST_FRIENDLY_NAME,
+                    TEST_PACKAGE);
+            providerHome.getConfig().setSubscriptionExpirationTimeInMillis(
+                    System.currentTimeMillis() + 100000);
+            providerHome.getWifiConfig().isHomeProviderNetwork = true;
+            PasspointProvider providerRoaming = addTestProvider(TEST_FQDN2, TEST_FRIENDLY_NAME,
+                    TEST_PACKAGE);
+            PasspointProvider providerNone = addTestProvider(TEST_FQDN + 2, TEST_FRIENDLY_NAME,
+                    TEST_PACKAGE, new WifiConfiguration());
+            ANQPData entry = new ANQPData(mClock, null);
+            InformationElementUtil.Vsa vsa = new InformationElementUtil.Vsa();
+            vsa.anqpDomainID = TEST_ANQP_DOMAIN_ID;
+
+            when(mAnqpCache.getEntry(TEST_ANQP_KEY)).thenReturn(entry);
+            when(InformationElementUtil.getHS2VendorSpecificIE(isNull())).thenReturn(vsa);
+            when(providerHome.match(anyMap(), isNull()))
+                    .thenReturn(PasspointMatch.HomeProvider);
+            when(providerRoaming.match(anyMap(), isNull()))
+                    .thenReturn(PasspointMatch.RoamingProvider);
+            when(providerNone.match(anyMap(), isNull()))
+                    .thenReturn(PasspointMatch.None);
+
+            Pair<PasspointProvider, PasspointMatch> result =
+                    mManager.matchProvider(createTestScanResult());
+
+            assertEquals(PasspointMatch.HomeProvider, result.second);
+            assertEquals(TEST_FQDN, result.first.getConfig().getHomeSp().getFqdn());
+
+        } finally {
+            session.finishMocking();
+        }
+    }
+
+    /**
+     * Verify that the RoamingProvider provider will be returned when a HomeProvider profile has
+     * expired and RoamingProvider expiration is unset (still valid).
+     *
+     * @throws Exception
+     */
+    @Test
+    public void matchRoamingProviderUnsetWhenHomeProviderExpired() throws Exception {
+        // static mocking
+        MockitoSession session =
+                com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession().mockStatic(
+                        InformationElementUtil.class).startMocking();
+        try {
+            PasspointProvider providerHome = addTestProvider(TEST_FQDN, TEST_FRIENDLY_NAME,
+                    TEST_PACKAGE);
+            providerHome.getConfig().setSubscriptionExpirationTimeInMillis(
+                    System.currentTimeMillis() - 10000);
+            providerHome.getWifiConfig().isHomeProviderNetwork = true;
+            PasspointProvider providerRoaming = addTestProvider(TEST_FQDN2, TEST_FRIENDLY_NAME,
+                    TEST_PACKAGE);
+            PasspointProvider providerNone = addTestProvider(TEST_FQDN + 2, TEST_FRIENDLY_NAME,
+                    TEST_PACKAGE, new WifiConfiguration());
+            ANQPData entry = new ANQPData(mClock, null);
+            InformationElementUtil.Vsa vsa = new InformationElementUtil.Vsa();
+            vsa.anqpDomainID = TEST_ANQP_DOMAIN_ID;
+
+            when(mAnqpCache.getEntry(TEST_ANQP_KEY)).thenReturn(entry);
+            when(InformationElementUtil.getHS2VendorSpecificIE(isNull())).thenReturn(vsa);
+            when(providerHome.match(anyMap(), isNull()))
+                    .thenReturn(PasspointMatch.HomeProvider);
+            when(providerRoaming.match(anyMap(), isNull()))
+                    .thenReturn(PasspointMatch.RoamingProvider);
+            when(providerNone.match(anyMap(), isNull()))
+                    .thenReturn(PasspointMatch.None);
+
+            Pair<PasspointProvider, PasspointMatch> result =
+                        mManager.matchProvider(createTestScanResult());
+
+            assertEquals(PasspointMatch.RoamingProvider, result.second);
+            assertEquals(TEST_FQDN2, result.first.getConfig().getHomeSp().getFqdn());
+
+        } finally {
+            session.finishMocking();
+        }
+    }
+
+    /**
+     * Verify that the RoamingProvider provider will be returned when a HomeProvider profile has
+     * expired and RoamingProvider expiration is still valid.
+     *
+     * @throws Exception
+     */
+    @Test
+    public void matchRoamingProviderNonExpiredWhenHomeProviderExpired() throws Exception {
+        // static mocking
+        MockitoSession session =
+                com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession().mockStatic(
+                        InformationElementUtil.class).startMocking();
+        try {
+            PasspointProvider providerHome = addTestProvider(TEST_FQDN, TEST_FRIENDLY_NAME,
+                    TEST_PACKAGE);
+            providerHome.getConfig().setSubscriptionExpirationTimeInMillis(
+                    System.currentTimeMillis() - 10000);
+            providerHome.getWifiConfig().isHomeProviderNetwork = true;
+            PasspointProvider providerRoaming = addTestProvider(TEST_FQDN2, TEST_FRIENDLY_NAME,
+                    TEST_PACKAGE);
+            providerRoaming.getConfig().setSubscriptionExpirationTimeInMillis(
+                    System.currentTimeMillis() + 100000);
+            PasspointProvider providerNone = addTestProvider(TEST_FQDN + 2, TEST_FRIENDLY_NAME,
+                    TEST_PACKAGE, new WifiConfiguration());
+            ANQPData entry = new ANQPData(mClock, null);
+            InformationElementUtil.Vsa vsa = new InformationElementUtil.Vsa();
+            vsa.anqpDomainID = TEST_ANQP_DOMAIN_ID;
+
+            when(mAnqpCache.getEntry(TEST_ANQP_KEY)).thenReturn(entry);
+            when(InformationElementUtil.getHS2VendorSpecificIE(isNull())).thenReturn(vsa);
+            when(providerHome.match(anyMap(), isNull()))
+                    .thenReturn(PasspointMatch.HomeProvider);
+            when(providerRoaming.match(anyMap(), isNull()))
+                    .thenReturn(PasspointMatch.RoamingProvider);
+            when(providerNone.match(anyMap(), isNull()))
+                    .thenReturn(PasspointMatch.None);
+
+            Pair<PasspointProvider, PasspointMatch> result =
+                    mManager.matchProvider(createTestScanResult());
+
+            assertEquals(PasspointMatch.RoamingProvider, result.second);
+            assertEquals(TEST_FQDN2, result.first.getConfig().getHomeSp().getFqdn());
+
+        } finally {
+            session.finishMocking();
+        }
+    }
 }