Failed to find provider info for com.example.serialprovider.provider.SampleProvider

I’ve been trying to get data from another app’s custom ContentProvider class but I keep getting this error: Failed to find provider info for com.example.serialprovider.provider.SampleProvider..

I searched a lot for similar issues online but still didn’t know what’s wrong, I checked the manifest multiple times, and I even took a copy of the authorities attribute to use it in the receiver app but still, the receiver app can’t find the provider.

Here’s the declaration in the manifest:

<provider
    android:name=".provider.SampleProvider"
    android:authorities="com.example.serialprovider.provider.SampleProvider"
    android:enabled="true"
    android:exported="true" />

and here’s the implementation of onCreate and query methods in the Provider class (I’m using RoomDatabase):

public class SampleProvider extends ContentProvider {
    
    public SampleProvider() {
    }

    private static final String AUTHORITY = "com.example.serialprovider.provider.SampleProvider";
    private static final String TABLE_NAME = "devicepin";

    private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);

    static {
        sURIMatcher.addURI(AUTHORITY, TABLE_NAME, 1);
    }

    @Override
    public boolean onCreate() {
        return true;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        if (sURIMatcher.match(uri) == 1) {
            final Context context = getContext();
            AppDao dao = DatabaseClient.getInstance(context).getAppDatabase().appDao();
            final Cursor cursor = dao.get();
            cursor.setNotificationUri(getContext().getContentResolver(), uri);
            cursor.close();
            return cursor;
        } else {
            throw new IllegalArgumentException("Unknown URI: " + uri);
        }
    }
}

and here’s how I try to get the cursor in the other app “receiver”:

private void getPin(){
    new Thread(() -> {
        ContentResolver resolver = getContentResolver();
        try{
            Cursor cursor = resolver.query(Uri.parse("content://com.example.serialprovider.provider.SampleProvider/devciepin"), null, null, null, null);
            cursor.close();
        }
        catch (Exception e){
            e.printStackTrace();
        }
    }).start();
}

cursor is always null, when I surround it with try and catch blocks, the “failed to find provider info” is what I get as an exception.

Answer

Turns out the code is alright, but there’s some new restrictions that were introduced in Android 11 (API 30) when accessing the ContentProvider from another app.

Quoting the Documentation on Android 11 behavior changes:

If your app shares a content URI with another app, the intent must grant URI access permissions by setting at least one of the following intent flags: FLAG_GRANT_READ_URI_PERMISSION and FLAG_GRANT_WRITE_URI_PERMISSION. That way, if the other app targets Android 11, it can still access the content URI. Your app must include the intent flags even when the content URI is associated with a content provider that your app doesn’t own.

If your app owns the content provider that’s associated with the content URI, verify that the content provider isn’t exported. We already recommend this security best practice.