Count total number of eligible updates in FLEDGE background fetch

FLEDGE needs to check the total number of eligible updates since the
main gathering method limits the number of CAs updated in a single job
for system health and privacy concerns.

Test: cd packages/modules/AdServices/adservices && atest
Bug: 240206000
Change-Id: I69f359bb06056e3d1a53d065a4315976c13ff02d
diff --git a/adservices/service-core/java/com/android/adservices/data/customaudience/CustomAudienceDao.java b/adservices/service-core/java/com/android/adservices/data/customaudience/CustomAudienceDao.java
index aa0ea6b..bbd638c 100644
--- a/adservices/service-core/java/com/android/adservices/data/customaudience/CustomAudienceDao.java
+++ b/adservices/service-core/java/com/android/adservices/data/customaudience/CustomAudienceDao.java
@@ -346,8 +346,8 @@
             List<String> buyers, Instant currentTime);
 
     /**
-     * Gets all {@link DBCustomAudienceBackgroundFetchData} for custom audiences that are active,
-     * not expired, and eligible for update.
+     * Gets up to {@code maxRowsReturned} rows of {@link DBCustomAudienceBackgroundFetchData} which
+     * correspond to custom audiences that are active, not expired, and eligible for update.
      */
     @Query(
             "SELECT bgf.* FROM custom_audience_background_fetch_data AS bgf "
@@ -363,6 +363,20 @@
             getActiveEligibleCustomAudienceBackgroundFetchData(
                     @NonNull Instant currentTime, long maxRowsReturned);
 
+    /**
+     * Gets the number of all {@link DBCustomAudienceBackgroundFetchData} for custom audiences that
+     * are active, not expired, and eligible for update.
+     */
+    @Query(
+            "SELECT COUNT(DISTINCT bgf.ROWID) FROM custom_audience_background_fetch_data AS bgf "
+                    + "INNER JOIN custom_audience AS ca "
+                    + "ON bgf.buyer = ca.buyer AND bgf.owner = ca.owner AND bgf.name = ca.name "
+                    + "WHERE bgf.eligible_update_time <= :currentTime "
+                    + "AND ca.activation_time <= :currentTime "
+                    + "AND :currentTime < ca.expiration_time")
+    public abstract int getNumActiveEligibleCustomAudienceBackgroundFetchData(
+            @NonNull Instant currentTime);
+
     /** Class represents custom audience stats query result. */
     public static class CustomAudienceStats {
         private final String mOwner;
diff --git a/adservices/tests/unittest/service-core/src/com/android/adservices/data/customaudience/CustomAudienceDaoTest.java b/adservices/tests/unittest/service-core/src/com/android/adservices/data/customaudience/CustomAudienceDaoTest.java
index d2a2ec5..83797de 100644
--- a/adservices/tests/unittest/service-core/src/com/android/adservices/data/customaudience/CustomAudienceDaoTest.java
+++ b/adservices/tests/unittest/service-core/src/com/android/adservices/data/customaudience/CustomAudienceDaoTest.java
@@ -308,7 +308,7 @@
             new DBCustomAudience.Builder()
                     .setOwner(OWNER_1)
                     .setBuyer(BUYER_1)
-                    .setName(NAME_1)
+                    .setName(NAME_3)
                     .setActivationTime(ACTIVATION_TIME_MINUS_ONE_HOUR)
                     .setCreationTime(CREATION_TIME_MINUS_THREE_DAYS)
                     .setExpirationTime(EXPIRATION_TIME_1)
@@ -319,6 +319,18 @@
                     .setTrustedBiddingData(TRUSTED_BIDDING_DATA_2)
                     .build();
 
+    private static final DBCustomAudienceBackgroundFetchData CUSTOM_AUDIENCE_BGF_DATA_UPDATED =
+            DBCustomAudienceBackgroundFetchData.builder()
+                    .setOwner(OWNER_1)
+                    .setBuyer(BUYER_1)
+                    .setName(NAME_3)
+                    .setDailyUpdateUrl(DAILY_UPDATE_URL_1)
+                    .setEligibleUpdateTime(
+                            DBCustomAudienceBackgroundFetchData
+                                    .computeNextEligibleUpdateTimeAfterSuccessfulUpdate(
+                                            CREATION_TIME_MINUS_THREE_DAYS, TEST_FLAGS))
+                    .build();
+
     private static final DBCustomAudience CUSTOM_AUDIENCE_OUTDATED =
             new DBCustomAudience.Builder()
                     .setOwner(OWNER_2)
@@ -901,6 +913,63 @@
     }
 
     @Test
+    public void testGetNumActiveEligibleCustomAudienceBackgroundFetchData() {
+        doReturn(TEST_FLAGS).when(FlagsFactory::getFlags);
+
+        // Prepopulate with three CAs, only one of which is eligible for update
+        mCustomAudienceDao.insertOrOverwriteCustomAudience(CUSTOM_AUDIENCE_1, DAILY_UPDATE_URL_1);
+        mCustomAudienceDao.insertOrOverwriteCustomAudience(
+                CUSTOM_AUDIENCE_UPDATED, DAILY_UPDATE_URL_1);
+        mCustomAudienceDao.insertOrOverwriteCustomAudience(
+                CUSTOM_AUDIENCE_EXPIRED, DAILY_UPDATE_URL_2);
+        assertEquals(
+                CUSTOM_AUDIENCE_1,
+                mCustomAudienceDao.getCustomAudienceByPrimaryKey(
+                        CUSTOM_AUDIENCE_1.getOwner(),
+                        CUSTOM_AUDIENCE_1.getBuyer(),
+                        CUSTOM_AUDIENCE_1.getName()));
+        assertEquals(
+                CUSTOM_AUDIENCE_BGF_DATA_1,
+                mCustomAudienceDao.getCustomAudienceBackgroundFetchDataByPrimaryKey(
+                        CUSTOM_AUDIENCE_1.getOwner(),
+                        CUSTOM_AUDIENCE_1.getBuyer(),
+                        CUSTOM_AUDIENCE_1.getName()));
+        assertEquals(
+                CUSTOM_AUDIENCE_UPDATED,
+                mCustomAudienceDao.getCustomAudienceByPrimaryKey(
+                        CUSTOM_AUDIENCE_UPDATED.getOwner(),
+                        CUSTOM_AUDIENCE_UPDATED.getBuyer(),
+                        CUSTOM_AUDIENCE_UPDATED.getName()));
+        assertEquals(
+                CUSTOM_AUDIENCE_BGF_DATA_UPDATED,
+                mCustomAudienceDao.getCustomAudienceBackgroundFetchDataByPrimaryKey(
+                        CUSTOM_AUDIENCE_UPDATED.getOwner(),
+                        CUSTOM_AUDIENCE_UPDATED.getBuyer(),
+                        CUSTOM_AUDIENCE_UPDATED.getName()));
+        assertEquals(
+                CUSTOM_AUDIENCE_EXPIRED,
+                mCustomAudienceDao.getCustomAudienceByPrimaryKey(
+                        CUSTOM_AUDIENCE_EXPIRED.getOwner(),
+                        CUSTOM_AUDIENCE_EXPIRED.getBuyer(),
+                        CUSTOM_AUDIENCE_EXPIRED.getName()));
+        assertEquals(
+                CUSTOM_AUDIENCE_BGF_DATA_EXPIRED,
+                mCustomAudienceDao.getCustomAudienceBackgroundFetchDataByPrimaryKey(
+                        CUSTOM_AUDIENCE_EXPIRED.getOwner(),
+                        CUSTOM_AUDIENCE_EXPIRED.getBuyer(),
+                        CUSTOM_AUDIENCE_EXPIRED.getName()));
+
+        assertEquals(
+                1,
+                mCustomAudienceDao.getNumActiveEligibleCustomAudienceBackgroundFetchData(
+                        CURRENT_TIME));
+        assertThat(
+                        mCustomAudienceDao.getActiveEligibleCustomAudienceBackgroundFetchData(
+                                CURRENT_TIME, 10))
+                .containsExactly(CUSTOM_AUDIENCE_BGF_DATA_UPDATED);
+    }
+
+    @Test
     public void testDeleteAllExpiredCustomAudienceData() {
         doReturn(TEST_FLAGS).when(FlagsFactory::getFlags);