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

Commit 16e83d2a authored by Dmitri Plotnikov's avatar Dmitri Plotnikov
Browse files

Throw an explicit exception if content provider process times out

Fixes: 149110957
Test: atest FrameworksCoreTests:android.content.ContentResolverTest

Change-Id: If4beac53d8b47c31503fd980f9a1e38d34e9c671
parent 17a63e29
Loading
Loading
Loading
Loading
+46 −14
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@ import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.AndroidTimeoutException;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.DeadObjectException;
@@ -2188,14 +2189,8 @@ public abstract class ContentResolver implements ContentInterface {
            return null;
        }

        ContentProviderClient provider = acquireContentProviderClient(authority);
        if (provider == null) {
            throw new IllegalArgumentException("Unknown authority " + authority);
        }
        try {
        try (ContentProviderClient provider = acquireRequiredContentProviderClient(authority)) {
            return provider.applyBatch(operations);
        } finally {
            provider.release();
        }
    }

@@ -2397,10 +2392,7 @@ public abstract class ContentResolver implements ContentInterface {
            return null;
        }

        IContentProvider provider = acquireProvider(authority);
        if (provider == null) {
            throw new IllegalArgumentException("Unknown authority " + authority);
        }
        IContentProvider provider = acquireRequiredProvider(authority);
        try {
            final Bundle res = provider.call(mPackageName, mAttributionTag, authority, method, arg,
                    extras);
@@ -2419,7 +2411,9 @@ public abstract class ContentResolver implements ContentInterface {
     * Returns the content provider for the given content URI.
     *
     * @param uri The URI to a content provider
     * @return The ContentProvider for the given URI, or null if no content provider is found.
     * @return The ContentProvider for the given URI, or null if the content provider initialization
     * times out.
     *
     * @hide
     */
    @UnsupportedAppUsage
@@ -2429,11 +2423,31 @@ public abstract class ContentResolver implements ContentInterface {
        }
        final String auth = uri.getAuthority();
        if (auth != null) {
            try {
                return acquireProvider(mContext, auth);
            } catch (AndroidTimeoutException ate) {
                Log.e(TAG, ate.getMessage());
                return null;
            }
        }
        return null;
    }

    /**
     * Same as {@link #acquireProvider(String)}, except it throws an exception
     * if the content provider does not exist or times out on start.
     *
     * @hide
     */
    @NonNull
    private IContentProvider acquireRequiredProvider(@NonNull String name) {
        IContentProvider provider = acquireProvider(mContext, name);
        if (provider == null) {
            throw new IllegalArgumentException("Unknown authority " + name);
        }
        return provider;
    }

    /**
     * Returns the content provider for the given content URI if the process
     * already has a reference on it.
@@ -2462,7 +2476,12 @@ public abstract class ContentResolver implements ContentInterface {
        if (name == null) {
            return null;
        }
        try {
            return acquireProvider(mContext, name);
        } catch (AndroidTimeoutException ate) {
            Log.e(TAG, ate.getMessage());
            return null;
        }
    }

    /**
@@ -2536,6 +2555,19 @@ public abstract class ContentResolver implements ContentInterface {
        return null;
    }

    /**
     * Same as {@link #acquireContentProviderClient(String)}, except it throws an exception
     * if the content provider does not exist or times out on start.
     *
     * @hide
     */
    private @NonNull ContentProviderClient acquireRequiredContentProviderClient(
            @NonNull String name) {
        Objects.requireNonNull(name, "name");
        IContentProvider provider = acquireRequiredProvider(name);
        return new ContentProviderClient(this, provider, name, true);
    }

    /**
     * Like {@link #acquireContentProviderClient(Uri)}, but for use when you do
     * not trust the stability of the target content provider.  This turns off
+33 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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 android.os;

import android.annotation.NonNull;
import android.util.AndroidRuntimeException;

/**
 * An exception that indicates that the request timed out, for example because
 * the requested content provider took too long to initialize.
 *
 * @hide
 */
public final class AndroidTimeoutException extends AndroidRuntimeException {

    public AndroidTimeoutException(@NonNull String message) {
        super(message);
    }
}
+7 −0
Original line number Diff line number Diff line
@@ -269,6 +269,8 @@ public final class Parcel {
    private static final int EX_UNSUPPORTED_OPERATION = -7;
    private static final int EX_SERVICE_SPECIFIC = -8;
    private static final int EX_PARCELABLE = -9;
    private static final int EX_TIMEOUT = -10;

    /** @hide */
    public static final int EX_HAS_NOTED_APPOPS_REPLY_HEADER = -127; // special; see below
    private static final int EX_HAS_STRICTMODE_REPLY_HEADER = -128;  // special; see below
@@ -2156,6 +2158,7 @@ public final class Parcel {
     * <li>{@link SecurityException}
     * <li>{@link UnsupportedOperationException}
     * <li>{@link NetworkOnMainThreadException}
     * <li>{@link AndroidTimeoutException}
     * </ul>
     *
     * @param e The Exception to be written.
@@ -2225,6 +2228,8 @@ public final class Parcel {
            code = EX_UNSUPPORTED_OPERATION;
        } else if (e instanceof ServiceSpecificException) {
            code = EX_SERVICE_SPECIFIC;
        } else if (e instanceof AndroidTimeoutException) {
            code = EX_TIMEOUT;
        }
        return code;
    }
@@ -2403,6 +2408,8 @@ public final class Parcel {
                return new UnsupportedOperationException(msg);
            case EX_SERVICE_SPECIFIC:
                return new ServiceSpecificException(readInt(), msg);
            case EX_TIMEOUT:
                return new AndroidTimeoutException(msg);
            default:
                return null;
        }
+6 −0
Original line number Diff line number Diff line
@@ -1511,6 +1511,12 @@
            android:process=":SlowProvider">
        </provider>

        <provider
            android:name="android.content.TimingOutProvider"
            android:authorities="android.content.TimingOutProvider"
            android:process=":TimingOutProvider">
        </provider>

        <!-- Application components used for os tests -->

        <service android:name="android.os.MessengerService"
+15 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import android.graphics.Color;
import android.graphics.ImageDecoder;
import android.graphics.Paint;
import android.net.Uri;
import android.os.AndroidTimeoutException;
import android.os.MemoryFile;
import android.os.ParcelFileDescriptor;
import android.os.SystemClock;
@@ -225,6 +226,20 @@ public class ContentResolverTest {
        assertThat(end).isLessThan(start + 5000);
    }

    @Test
    public void testCall_timingOutProvider() {
        try {
            // This provider is running in a different process and is configured to time out
            // on start. We acquire it as "unstable" to avoid getting killed by the timeout in the
            // content provider process.
            mResolver.acquireUnstableContentProviderClient(
                    Uri.parse("content://android.content.TimingOutProvider"));
            fail("AndroidTimeoutException expected");
        } catch (AndroidTimeoutException t) {
            assertThat(t).hasMessageThat().contains("android.content.TimingOutProvider");
        }
    }

    @Test
    public void testGetType_unknownProvider() {
        // This provider does not exist.
Loading