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

Commit 66cffd5a authored by Jason Monk's avatar Jason Monk
Browse files

Run slice callbacks on thread they come in on

Instead post a runnable that will trigger an ANR+crash if the app
doesn't respond in time.

Test: atest cts/tests/tests/slice
Bug: 74251457
Change-Id: Ieea7a8d8cb08d3bf0735b9f7b385f286839dacd8
parent 0b4626aa
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -7276,7 +7276,6 @@ package android.app.slice {
  public abstract class SliceProvider extends android.content.ContentProvider {
    ctor public SliceProvider();
    method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]);
    method public final java.lang.String getBindingPackage();
    method public final java.lang.String getType(android.net.Uri);
    method public final android.net.Uri insert(android.net.Uri, android.content.ContentValues);
    method public android.app.slice.Slice onBindSlice(android.net.Uri, java.util.List<android.app.slice.SliceSpec>);
+32 −73
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@
package android.app.slice;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.ContentProvider;
@@ -35,7 +34,6 @@ import android.os.Binder;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.Handler;
import android.os.Looper;
import android.os.Process;
import android.os.StrictMode;
import android.os.StrictMode.ThreadPolicy;
@@ -46,7 +44,6 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * A SliceProvider allows an app to provide content to be displayed in system spaces. This content
@@ -162,18 +159,10 @@ public abstract class SliceProvider extends ContentProvider {

    private static final boolean DEBUG = false;

    private String mBindingPkg;
    private SliceManager mSliceManager;
    private static final long SLICE_BIND_ANR = 2000;

    /**
     * Return the package name of the caller that initiated the binding request
     * currently happening. The returned package will have been
     * verified to belong to the calling UID. Returns {@code null} if not
     * currently performing an {@link #onBindSlice(Uri, List)}.
     */
    public final @Nullable String getBindingPackage() {
        return mBindingPkg;
    }
    private String mCallback;
    private SliceManager mSliceManager;

    @Override
    public void attachInfo(Context context, ProviderInfo info) {
@@ -182,12 +171,12 @@ public abstract class SliceProvider extends ContentProvider {
    }

    /**
     * Implemented to create a slice. Will be called on the main thread.
     * Implemented to create a slice.
     * <p>
     * onBindSlice should return as quickly as possible so that the UI tied
     * to this slice can be responsive. No network or other IO will be allowed
     * during onBindSlice. Any loading that needs to be done should happen
     * off the main thread with a call to {@link ContentResolver#notifyChange(Uri, ContentObserver)}
     * in the background with a call to {@link ContentResolver#notifyChange(Uri, ContentObserver)}
     * when the app is ready to provide the complete data in onBindSlice.
     * <p>
     * The slice returned should have a spec that is compatible with one of
@@ -375,55 +364,32 @@ public abstract class SliceProvider extends ContentProvider {
    }

    private Collection<Uri> handleGetDescendants(Uri uri) {
        if (Looper.myLooper() == Looper.getMainLooper()) {
            return onGetSliceDescendants(uri);
        } else {
            CountDownLatch latch = new CountDownLatch(1);
            Collection<Uri>[] output = new Collection[1];
            Handler.getMain().post(() -> {
                output[0] = onGetSliceDescendants(uri);
                latch.countDown();
            });
        mCallback = "onGetSliceDescendants";
        Handler.getMain().postDelayed(mAnr, SLICE_BIND_ANR);
        try {
                latch.await();
                return output[0];
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return onGetSliceDescendants(uri);
        } finally {
            Handler.getMain().removeCallbacks(mAnr);
        }
    }

    private void handlePinSlice(Uri sliceUri) {
        if (Looper.myLooper() == Looper.getMainLooper()) {
            onSlicePinned(sliceUri);
        } else {
            CountDownLatch latch = new CountDownLatch(1);
            Handler.getMain().post(() -> {
                onSlicePinned(sliceUri);
                latch.countDown();
            });
        mCallback = "onSlicePinned";
        Handler.getMain().postDelayed(mAnr, SLICE_BIND_ANR);
        try {
                latch.await();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            onSlicePinned(sliceUri);
        } finally {
            Handler.getMain().removeCallbacks(mAnr);
        }
    }

    private void handleUnpinSlice(Uri sliceUri) {
        if (Looper.myLooper() == Looper.getMainLooper()) {
            onSliceUnpinned(sliceUri);
        } else {
            CountDownLatch latch = new CountDownLatch(1);
            Handler.getMain().post(() -> {
                onSliceUnpinned(sliceUri);
                latch.countDown();
            });
        mCallback = "onSliceUnpinned";
        Handler.getMain().postDelayed(mAnr, SLICE_BIND_ANR);
        try {
                latch.await();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            onSliceUnpinned(sliceUri);
        } finally {
            Handler.getMain().removeCallbacks(mAnr);
        }
    }

@@ -441,21 +407,12 @@ public abstract class SliceProvider extends ContentProvider {
                return createPermissionSlice(getContext(), sliceUri, pkg);
            }
        }
        if (Looper.myLooper() == Looper.getMainLooper()) {
            return onBindSliceStrict(sliceUri, supportedSpecs, pkg);
        } else {
            CountDownLatch latch = new CountDownLatch(1);
            Slice[] output = new Slice[1];
            Handler.getMain().post(() -> {
                output[0] = onBindSliceStrict(sliceUri, supportedSpecs, pkg);
                latch.countDown();
            });
        mCallback = "onBindSlice";
        Handler.getMain().postDelayed(mAnr, SLICE_BIND_ANR);
        try {
                latch.await();
                return output[0];
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return onBindSliceStrict(sliceUri, supportedSpecs);
        } finally {
            Handler.getMain().removeCallbacks(mAnr);
        }
    }

@@ -507,19 +464,21 @@ public abstract class SliceProvider extends ContentProvider {
        }
    }

    private Slice onBindSliceStrict(Uri sliceUri, List<SliceSpec> supportedSpecs,
            String callingPackage) {
    private Slice onBindSliceStrict(Uri sliceUri, List<SliceSpec> supportedSpecs) {
        ThreadPolicy oldPolicy = StrictMode.getThreadPolicy();
        try {
            StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                    .detectAll()
                    .penaltyDeath()
                    .build());
            mBindingPkg = callingPackage;
            return onBindSlice(sliceUri, supportedSpecs);
        } finally {
            mBindingPkg = null;
            StrictMode.setThreadPolicy(oldPolicy);
        }
    }

    private final Runnable mAnr = () -> {
        Process.sendSignal(Process.myPid(), Process.SIGNAL_QUIT);
        Log.wtf(TAG, "Timed out while handling slice callback " + mCallback);
    };
}