SecurityException с grantUriPermission при совместном использовании файла с FileProvider

У меня есть два приложения. Я пытаюсь передать файл из приложения A в приложение B с помощью FileProvider. Приложение A вызывает метод insert на ContentProvider в приложении B для вставки записи. Введенные данные включают Uri в файл, который я хочу предоставить из приложения A. ContentProvider в приложении B затем попытается прочитать общий файл из приложения A. Поскольку я не использую Intent для совместного использования файла, я вызываю Context.grantUriPermission в приложении A, чтобы разрешить чтение (и время от времени писать):

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

Однако выполнение этой строки дает мне (Имена изменены для защиты невинных):

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...

В файле манифеста приложение А имеет следующее:

<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 имеет:

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

Оба приложения A и App B имеют следующее:

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

Я попытался определить разрешения в обоих приложениях. Они оба подписаны с той же отладочной подписью:

<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>

Фактический путь к файлу:

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

В этот момент я в тупике. Я не знаю, почему я не могу предоставить разрешение на файл, который я только что создал в одном приложении. Поэтому мои вопросы: почему я получаю это исключение и как я могу успешно предоставить разрешение на приложение B?

Ответ 1

Ну, через неделю и много проб и ошибок, кажется, ответ заключается в том, чтобы не указывать разрешения. Таким образом, манифест App App должен содержать:

<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>

т.е. я удалил права на чтение и запись. Мое первоначальное понимание и неспособность найти документацию, которая говорила иначе, были необходимы для ограничения доступа. Однако я обнаружил, что они действительно вмешиваются и вызывают Context.grantUriPermission. Доступ уже ограничен.

Чтобы завершить изображение и ответить на вторую часть моего вопроса, я обнаружил следующее:

Отказ прав доступа Android в виджетах RemoteViewsFactory для контента

Мне пришлось добавить:

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

поставщику содержимого в приложении B. В противном случае он также получит ошибки безопасности.

Ответ 2

Первая проблема в вашем коде экспортируется атрибутом, установленным в false. Пожалуйста, измените его на true,

<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>

Второе, что вам нужно сделать, это: Если внешнее приложение App B использует контент-провайдера в приложении A. Затем в приложении Файл манифеста указывается разрешение как

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

и в приложении B упоминание использует-разрешение как,

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

Пожалуйста, дайте мне знать, была ли ваша проблема решена или нет. Если нет, отправьте свой код целиком. Я постараюсь найти проблему. Спасибо.