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

Commit 140fc2e9 authored by Dmitri Plotnikov's avatar Dmitri Plotnikov
Browse files

Prevents an NPE when content provider is slow to start

Also, extends the client-side timeout to match that
in ActivityManagerService.

Test: atest FrameworksCoreTests:android.content.ContentResolverTest
Fixes: 148987678
Change-Id: I1daf8625bd0306cc6f6f08c3268fa191d37bda7a
parent 04c84989
Loading
Loading
Loading
Loading
+21 −2
Original line number Diff line number Diff line
@@ -700,6 +700,27 @@ public abstract class ContentResolver implements ContentInterface {
    /** @hide */
    public static final String REMOTE_CALLBACK_RESULT = "result";

    /**
     * How long we wait for an attached process to publish its content providers
     * before we decide it must be hung.
     * @hide
     */
    public static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS = 10 * 1000;

    /**
     * How long we wait for an provider to be published. Should be longer than
     * {@link #CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS}.
     * @hide
     */
    public static final int CONTENT_PROVIDER_WAIT_TIMEOUT_MILLIS =
            CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS + 10 * 1000;

    // Should be >= {@link #CONTENT_PROVIDER_WAIT_TIMEOUT_MILLIS}, because that's how
    // long ActivityManagerService is giving a content provider to get published if a new process
    // needs to be started for that.
    private static final int GET_TYPE_TIMEOUT_MILLIS =
            CONTENT_PROVIDER_WAIT_TIMEOUT_MILLIS + 5 * 1000;

    public ContentResolver(@Nullable Context context) {
        this(context, null);
    }
@@ -849,8 +870,6 @@ public abstract class ContentResolver implements ContentInterface {
        }
    }

    private static final int GET_TYPE_TIMEOUT_MILLIS = 3000;

    private static class GetTypeResultListener implements RemoteCallback.OnResultListener {
        @GuardedBy("this")
        public boolean done;
+6 −0
Original line number Diff line number Diff line
@@ -1326,6 +1326,12 @@
            android:process=":FakeProvider">
        </provider>

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

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

        <service android:name="android.os.MessengerService"
+9 −0
Original line number Diff line number Diff line
@@ -209,4 +209,13 @@ public class ContentResolverTest {
        String type = mResolver.getType(Uri.parse("content://android.content.FakeProviderRemote"));
        assertEquals("fake/remote", type);
    }


    @Test
    public void testGetType_slowProvider() {
        // This provider is running in a different process and is intentionally slow to start.
        // We are trying to confirm that it does not cause an ANR
        String type = mResolver.getType(Uri.parse("content://android.content.SlowProvider"));
        assertEquals("slow", type);
    }
}
+65 −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.content;

import android.database.Cursor;
import android.net.Uri;

/**
 * A dummy content provider for tests.  This provider runs in a different process from the test and
 * is intentionally slow.
 */
public class SlowProvider extends ContentProvider {

    private static final int ON_CREATE_LATENCY_MILLIS = 3000;

    @Override
    public boolean onCreate() {
        try {
            Thread.sleep(ON_CREATE_LATENCY_MILLIS);
        } catch (InterruptedException e) {
            // Ignore
        }
        return true;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
            String sortOrder) {
        return null;
    }

    @Override
    public String getType(Uri uri) {
        return "slow";
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        return null;
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        return 0;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        return 0;
    }
}
+11 −16
Original line number Diff line number Diff line
@@ -466,18 +466,9 @@ public class ActivityManagerService extends IActivityManager.Stub
    // How long we wait for a launched process to attach to the activity manager
    // before we decide it's never going to come up for real.
    static final int PROC_START_TIMEOUT = 10*1000;
    // How long we wait for an attached process to publish its content providers
    // before we decide it must be hung.
    static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT = 10*1000;
    // How long we wait to kill an application zygote, after the last process using
    // it has gone away.
    static final int KILL_APP_ZYGOTE_DELAY_MS = 5 * 1000;
    /**
     * How long we wait for an provider to be published. Should be longer than
     * {@link #CONTENT_PROVIDER_PUBLISH_TIMEOUT}.
     */
    static final int CONTENT_PROVIDER_WAIT_TIMEOUT = 20 * 1000;
    // How long we wait for a launched process to attach to the activity manager
    // before we decide it's never going to come up for real, when the process was
@@ -4934,7 +4925,8 @@ public class ActivityManagerService extends IActivityManager.Stub
        if (providers != null && checkAppInLaunchingProvidersLocked(app)) {
            Message msg = mHandler.obtainMessage(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG);
            msg.obj = app;
            mHandler.sendMessageDelayed(msg, CONTENT_PROVIDER_PUBLISH_TIMEOUT);
            mHandler.sendMessageDelayed(msg,
                    ContentResolver.CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS);
        }
        checkTime(startTime, "attachApplicationLocked: before bindApplication");
@@ -7198,7 +7190,8 @@ public class ActivityManagerService extends IActivityManager.Stub
        }
        // Wait for the provider to be published...
        final long timeout = SystemClock.uptimeMillis() + CONTENT_PROVIDER_WAIT_TIMEOUT;
        final long timeout =
                SystemClock.uptimeMillis() + ContentResolver.CONTENT_PROVIDER_WAIT_TIMEOUT_MILLIS;
        boolean timedOut = false;
        synchronized (cpr) {
            while (cpr.provider == null) {
@@ -7235,14 +7228,16 @@ public class ActivityManagerService extends IActivityManager.Stub
            }
        }
        if (timedOut) {
            // Note we do it afer releasing the lock.
            // Note we do it after releasing the lock.
            String callerName = "unknown";
            if (caller != null) {
                synchronized (this) {
                    final ProcessRecord record = mProcessList.getLRURecordForAppLocked(caller);
                    if (record != null) {
                        callerName = record.processName;
                    }
                }
            }
            Slog.wtf(TAG, "Timeout waiting for provider "
                    + cpi.applicationInfo.packageName + "/"