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?
Try including this in your AndroidManifest. xml. On Android 6.0+ the permission must be granted by the user to the application otherwise this will throw the SecurityException. To do this go into Settings/Apps/[AppName]/Permissions and allow the Storage Permission.
To make FileProvider work follow these three steps: Define the FileProvider in your AndroidManifest file. Create an XML file that contains all paths that the FileProvider will share with other applications. Bundle a valid URI in the Intent and activate it.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With