Question

I have two applications. I'm trying to share a file from application A to application B using a FileProvider. Application A calls the insert method on a ContentProvider in Application B to insert a record. The data inserted includes the Uri to the file I want to share from App A. The ContentProvider in App B would then try to read the shared file from App A. Since I'm not using an Intent to share the file, I'm calling Context.grantUriPermission in App A to allow the read (and at times write):

mContext.grantUriPermission(MyPackageName, contentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

However, executing this line gives me (Names changed to protect the innocent):

java.lang.SecurityException: Uid 10066 does not have permission to uri content://au.com.example.AppA.fileprovider/MyFolder/MyFileName
at android.os.Parcel.readException(Parcel.java:1322)
at android.os.Parcel.readException(Parcel.java:1276)
at android.app.ActivityManagerProxy.grantUriPermission(ActivityManagerNative.java:2374)
at android.app.ContextImpl.grantUriPermission(ContextImpl.java:1371)
at android.content.ContextWrapper.grantUriPermission(ContextWrapper.java:400)
at etc...

App A has the following in the Manifest file:

<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="au.com.example.AppA.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true"
    android:readPermission="au.com.example.READ_CONTENT"
    android:writePermission="au.com.example.WRITE_CONTENT" >
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/filepaths" />
</provider>

filepaths.xml has:

<paths>
    <files-path
        name="MyFolder"
        path="MyFolder/" />
</paths>

Both App A and App B have the following:

<uses-permission android:name="au.com.example.READ_CONTENT" />
<uses-permission android:name="au.com.example.WRITE_CONTENT" />

I've tried defining the permissions in both apps. They are both signed with the same debug signature:

<permission
    android:name="au.com.example.READ_CONTENT"
    android:permissionGroup="MyGroup"
    android:protectionLevel="signature" >
</permission>
<permission
    android:name="au.com.example.WRITE_CONTENT"
    android:permissionGroup="MyGroup"
    android:protectionLevel="signature" >
</permission>

The actual path the file ends up in is:

/data/data/au.com.example.AppA/files/MyFolder

At this point I'm stumped. I don't know why I can't grant permission for a file I just created within the same application. So my questions are: Why am I getting this exception and how can I successfully grant permission to App B?

Was it helpful?

Solution

Well, after a week and a lot of trial and error, it seems the answer is to not specify permissions. So the App A Manifest should instead contain:

<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="au.com.example.AppA.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true" >
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/filepaths" />
</provider>

ie, I removed the read and write permissions. My initial understanding, and failing to find documentation that said otherwise, was these were necessary to restrict access. However, I've found they actually interfere and cause Context.grantUriPermission to fail. Access is limited already.

To complete the picture, and answer the second part of my question, I found the following:

Android Permission denial in Widget RemoteViewsFactory for Content

I had to add:

final long token = Binder.clearCallingIdentity();
try {
    [retrieve file here]
} finally {
    Binder.restoreCallingIdentity(token);
}

to the Content Provider in App B. Otherwise it would get security errors as well.

OTHER TIPS

The first problem in your code is exported attribute set to false. Please change it to true as,

<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="au.com.example.AppA.fileprovider"
android:exported="true"
android:readPermission="au.com.example.READ_CONTENT"
android:writePermission="au.com.example.WRITE_CONTENT" >
</provider>

The second thing you have to do is, If external application App B is using content provider in App A.Then in App A manifest file mention permission as,

<permission
android:name="au.com.example.READ_CONTENT"
 >
</permission>
<permission
android:name="au.com.example.WRITE_CONTENT"
 >
</permission>

and in App B mention uses-permission as,

<uses-permission android:name="au.com.example.READ_CONTENT" />
<uses-permission android:name="au.com.example.WRITE_CONTENT" />

Please let me know whether your problem has solved or not. If not please send your entire code. I will try to find the problem. Thank you.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top