Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Permission denial: opening provider

Tags:

I've created a custom content provider, which will be accessed by a few more applications. I've included the permission TAG in my provider AndroidManifest.xml file, and in the second application, I included the uses-permissions tag, but no success. Logcat shows me:

java.lang.SecurityException: Permission Denial: opening provider com.company.contentprovider.AplicacaoContentProvider requires READ_DATABASE or WRITE_DATABASE.

I've search on similar questions, but it seems like everything is correct. Any ideas ? Thanks !!!

Here is my provider AndroidManifest.xml file:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.company.contentprovider"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk
    android:minSdkVersion="8"
    android:targetSdkVersion="17" />
<permission android:name="READ_DATABASE" android:label="@string/app_read"       android:protectionLevel="normal"></permission>
<permission android:name="WRITE_DATABASE" android:label="@string/app_write" android:protectionLevel="normal"></permission>

<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
    <activity
        android:name=".CompanyProvider"
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <provider android:name="AplicacaoContentProvider"
        android:authorities="com.company.contentprovider"
        android:exported="true"
        android:readPermission="@string/app_read"
        android:writePermission="@string/app_write"
       />
</application>

And this is my second application AndroidManifest.xml file:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.testeprovider"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk
    android:minSdkVersion="8"
    android:targetSdkVersion="16" />
<uses-permission android:name="android.permissions.READ_DATABASE"/>
<uses-permission android:name="android.permissioms.WRITE_DATABASE"/>


<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
    <activity
        android:name="com.example.testeprovider.MainActivity"
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

</application>

like image 466
Android Hunter Avatar asked Jan 16 '13 22:01

Android Hunter


3 Answers

The answer above was a litle confusing for me. But I got it now. I want to post my solution as well. Maybe for someone it's more better to understand.

First App A is the App that has the SQLite-Database and the "Custom Content Provider". App B uses with a ContentResolver the databse from App A.

This is the AndroidManifest.xml-File from App A:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.test"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk android:minSdkVersion="10" />


<permission android:name="de.test.READ_DATABASE" android:protectionLevel="normal" />
<permission android:name="de.test.WRITE_DATABASE" android:protectionLevel="normal" />

<application
    android:debuggable="true"
    ... >
    ...
    ...
    <provider
        android:name="de.test.TestContentProvider"
        android:authorities="de.test.ContentProvider"
        android:exported="true"
        android:readPermission="de.test.READ_DATABASE"
        android:writePermission="de.test.WRITE_DATABASE" />
    ...
    ...
</application>

Ok and this is the AndroidManifest.xml-File from App B. Important is the part with "uses-permission":

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.test.testercontentprovider"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk
    android:minSdkVersion="15"
    android:targetSdkVersion="17" />

<uses-permission android:name="de.test.READ_DATABASE" />
<uses-permission android:name="de.test.WRITE_DATABASE" />

<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
    <activity
        android:name="de.test.testercontentprovider.MainActivity"
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

And the Code of the ContentProvider for App A looks like this:

public class TestContentProvider extends ContentProvider {

public static final String AUTHORITY = "de.test.TestContentProvider";

public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY
        + "/" + "nameoftable");


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

@Override
public Cursor query(Uri uri, String[] projection, String selection,
        String[] selectionArgs, String sortOrder) {
    // TODO Auto-generated method stub
            return null;
}

@Override
public int update(Uri uri, ContentValues values, String selection,
        String[] selectionArgs) {
    // TODO Auto-generated method stub
    return 0;
}

@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
    // TODO Auto-generated method stub
    return 0;
}

@Override
public Uri insert(Uri uri, ContentValues values) {
    // TODO Auto-generated method stub
    return null;
}

@Override
public String getType(Uri uri) {
    // TODO Auto-generated method stub
    return null;
}
}

And the Code for the ContentResolver from App B:

public class MainActivity extends Activity {

private static final String TAG = MainActivity.class.getSimpleName();
public static final String AUTHORITY = "de.test.TestContentProvider";
public static final String TABLE_NAME = "nameoftable";

    ...

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    ContentResolver cr = getContentResolver();

    // show entries of db
    listEntries(cr);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

private void listEntries(ContentResolver cr) {
    Uri uri = Uri.parse("content://" + AUTHORITY + "/" + TABLE_NAME);
    Cursor c = cr.query(uri, null, null, null, null);

    if (c == null) {
        Log.d(TAG, "Cursor c == null.");
        return;
    }
    while (c.moveToNext()) {
        String column1 = c.getString(0);
        String column2 = c.getString(1);
        String column3 = c.getString(2);

        Log.d(TAG, "column1=" + column1 + " column2=" + column2 + " column3=" + column3);
    }
    c.close();
}
}

I hope this can help someone to understand it better.

like image 70
KingAlex1985 Avatar answered Sep 28 '22 03:09

KingAlex1985


but it seems like everything is correct

Not exactly.

<permission android:name="READ_DATABASE" android:label="@string/app_read"       android:protectionLevel="normal"></permission>
<permission android:name="WRITE_DATABASE" android:label="@string/app_write" android:protectionLevel="normal"></permission>

First, you really really really really really really should put a namespace on those permission names. Make them com.company.contentprovider.READ_DATABASE and com.company.contentprovider.WRITE_DATABASE.

<provider android:name="AplicacaoContentProvider"
    android:authorities="com.company.contentprovider"
    android:exported="true"
    android:readPermission="@string/app_read"
    android:writePermission="@string/app_write"
   />

Second, your android:readPermission and android:writePermission values need to use the android:name value from <permission>, not android:label. android:label is a display name only. So, the above snippet should be:

<provider android:name="AplicacaoContentProvider"
    android:authorities="com.company.contentprovider"
    android:exported="true"
    android:readPermission="com.company.contentprovider.READ_DATABASE"
    android:writePermission="com.company.contentprovider.WRITE_DATABASE"
   />

(though, bonus points for explicitly putting android:exported="true", which is a good idea)

<uses-permission android:name="android.permissions.READ_DATABASE"/>
<uses-permission android:name="android.permissioms.WRITE_DATABASE"/>

Third, your other manifest does not use your old android:name, nor my suggested revised android:name, nor android:label, but something else entirely, where you elected to say that these are in the android.permission namespace, and they are not. This should be:

<uses-permission android:name="com.company.contentprovider.READ_DATABASE"/>
<uses-permission android:name="com.company.contentprovider.WRITE_DATABASE"/>

(though it is possible that com.company.contentprovider.WRITE_DATABASE will be sufficient -- I don't know if android:writePermission will automatically imply android:readPermission or not)

Make those changes, and I think you will have better luck.

like image 29
CommonsWare Avatar answered Sep 28 '22 03:09

CommonsWare


I was facing the same problem, then I remember I forgot to

add export tag for provider in the Manifest

   <provider
        android:name=".UsersProvider"
        android:authorities="com.xyz.demoapplication"
        android:exported="true">
   </provider>

To access in another app you need to export true this allows other application to access Content Provider from this host application

like image 22
Atif Mukhtiar Avatar answered Sep 28 '22 05:09

Atif Mukhtiar