Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ff6d28c6 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Retry metadata sync for RESULT_ABORTED code." into main

parents a97934e2 8de8f06f
Loading
Loading
Loading
Loading
+42 −7
Original line number Diff line number Diff line
@@ -414,6 +414,16 @@ public class MetadataSyncAdapter {
     * This method returns a map of package names to a set of function ids from the AppFunction
     * metadata.
     *
     * <p>Retry Conditions:
     *
     * <ul>
     *   <li>If an {@link AppSearchException} with {@code RESULT_ABORTED} (code 13) is thrown during
     *       the first attempt, the query will be retried once.
     *   <li>If the number of function ids returned equals {@code DEFAULT_RESULT_COUNT_PER_PAGE},
     *       which may indicate an incomplete result due to known issue b/400670498, the query will
     *       be retried with an increased page size ({@code RETRY_RESULT_COUNT_PER_PAGE}).
     * </ul>
     *
     * @param searchSession The {@link FutureAppSearchSession} to search the AppFunction metadata.
     * @param schemaType The schema type of the AppFunction metadata.
     * @param propertyFunctionId The property name of the function id in the AppFunction metadata.
@@ -429,13 +439,38 @@ public class MetadataSyncAdapter {
            @NonNull String propertyFunctionId,
            @NonNull String propertyPackageName)
            throws ExecutionException, InterruptedException {
        ArrayMap<String, ArraySet<String>> packageToFunctionIdMap =
        ArrayMap<String, ArraySet<String>> packageToFunctionIdMap;
        try {
            packageToFunctionIdMap =
                    getPackageToFunctionIdMap(
                            searchSession,
                            schemaType,
                            propertyFunctionId,
                            propertyPackageName,
                            DEFAULT_RESULT_COUNT_PER_PAGE);
        } catch (ExecutionException e) {
            // TODO: b/416177384 - Use AppSearchResult#RESULT_ABORTED instead of 13.
            if (!(e.getCause() instanceof AppSearchException)
                    || (((AppSearchException) e.getCause()).getResultCode() != 13)) {
                throw e;
            }

            Slog.d(
                    TAG,
                    "Retrying to fetch app functions because AppSearch resulted in RESULT_ABORTED",
                    e.getCause());

            packageToFunctionIdMap =
                    getPackageToFunctionIdMap(
                            searchSession,
                            schemaType,
                            propertyFunctionId,
                            propertyPackageName,
                            DEFAULT_RESULT_COUNT_PER_PAGE);
        }

        // Since older mainline versions won't throw an exception we rely on checking if results
        // returned are same as DEFAULT_RESULT_COUNT_PER_PAGE.
        int functionIdCount = countTotalStringsInValueSets(packageToFunctionIdMap);
        if (functionIdCount == DEFAULT_RESULT_COUNT_PER_PAGE) {
            // We might run into b/400670498 where only the first page is returned while there
+33 −0
Original line number Diff line number Diff line
@@ -35,10 +35,17 @@ import android.util.Log
import androidx.test.platform.app.InstrumentationRegistry
import com.android.internal.infra.AndroidFuture
import com.google.common.truth.Truth.assertThat
import org.mockito.kotlin.mock
import java.util.concurrent.atomic.AtomicBoolean
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.mockito.kotlin.any
import org.mockito.kotlin.doAnswer
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.times
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever

@RunWith(JUnit4::class)
class MetadataSyncAdapterTest {
@@ -295,6 +302,32 @@ class MetadataSyncAdapterTest {
        assertThat(removedFunctionsDiffMap.isEmpty()).isEqualTo(true)
    }

    @Test
    fun getPackageToFunctionIdMapWithRetry_result_aborted_retries() {
        val futureSearchSession = mock<FutureAppSearchSession>()
        val futureSearchResults = mock<FutureSearchResults> {
            on { nextPage } doReturn AndroidFuture.completedFuture(listOf())
            on { close() } doAnswer {}
        }

        whenever(futureSearchSession.search(any(), any()))
            .thenReturn(
                AndroidFuture<FutureSearchResults?>().apply {
                    completeExceptionally(AppSearchException(/* resultCode= */ 13, ""))
                }
            )
            .thenReturn(AndroidFuture.completedFuture(futureSearchResults))

        MetadataSyncAdapter.getPackageToFunctionIdMapWithRetry(
            futureSearchSession,
            /* schemaType= */ "fakeSchema",
            AppFunctionRuntimeMetadata.PROPERTY_FUNCTION_ID,
            AppFunctionRuntimeMetadata.PROPERTY_PACKAGE_NAME,
        )

        verify(futureSearchSession, times(2)).search(any(), any())
    }

    private companion object {
        const val TEST_DB: String = "test_db"
        const val TEST_TARGET_PKG_NAME = "com.android.frameworks.appfunctionstests"