Пользовательское действие выбора: SecurityException UID n не имеет разрешения на содержимое: // uri

Я создаю приложение Chooser, которое заменяет родное диалоговое окно Android Share. Он работает нормально, за исключением случаев, когда я пытаюсь поделиться изображением из Chrome с помощью длинного нажатия на изображение> поделиться изображением.

Я обнаружил, что Google+ не перехватывает исключение (вылетает), поэтому я могу посмотреть на него через Logcat:

  • Выполните поиск изображений в Google.
  • Выберите изображение (это должно показать предварительный просмотр)
  • Нажмите и удерживайте изображение
  • Выберите «Поделиться изображением»
  • Моя активность выбора всплывает
  • Выберите Google+
  • Google+ вылетает с этой ошибкой:

java.lang.SecurityException: UID 10130 не имеет разрешения на контент://com.android.chrome.FileProvider/images/screenshot/15307295588677864462883877407218.jpg [пользователь 0]

Мой код (упрощенный):

@Override
public void onCreate() {
    handleIntent();
}

private void handleIntent() {

    // Get intent and payload
    mIntent = getIntent();
    mPayloadIntent = (Intent) mIntent.getParcelableExtra(Intent.EXTRA_INTENT);

    // Nullify some things for queryIntentActivities (or no results will be found)
    mPayloadIntent.setComponent(null);
    mPayloadIntent.setPackage(null);

    // Retrieve a list of targets we can send mPayloadIntent to..
    List<ResolveInfo> targets = context.getPackageManager().queryIntentActivities(mPayloadIntent, 0);
    // etc...

}

private void onClickTarget(ResolveInfo target) {

    // Prepare..
    ComponentName compName = new ComponentName(
                target.activityInfo.applicationInfo.packageName,
                target.activityInfo.name);

    // Build a 'new' shareIntent
    Intent shareIntent = new Intent(mPayloadIntent);
    shareIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT | Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
    shareIntent.setComponent(compName);

    // Start the targeted activity with the shareIntent
    startActivity(shareIntent);
    finish();

}

AndroidManifest.xml:

<activity
    android:name=".ActShareReplace"
    android:label="Sharedr"
    android:theme="@style/AppTheme.TransparentActivity"
    >
    <intent-filter>
        <action android:name="android.intent.action.CHOOSER" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

Если я посмотрю документацию для Intent.ACTION_CHOOSER, там написано :

Если вам нужно предоставить разрешения URI через средство выбора, вы должны указать разрешения, которые будут предоставлены в намерении ACTION_CHOOSER в дополнение к EXTRA_INTENT внутри. Это означает использование setClipData(ClipData) для указания предоставляемых URI, а также FLAG_GRANT_READ_URI_PERMISSION и/или FLAG_GRANT_WRITE_URI_PERMISSION в зависимости от ситуации.

Я не совсем уверен, что это то, что должно делать мое приложение, или это ответственность приложения, которое вызвало действие выбора, но я бы предположил, что это последнее. Мое приложение не может устанавливать разрешения URI для получаемых намерений, не так ли?

В любом случае, если я проверю дополнительные элементы и флаги на mIntent и mPayloadIntent, я получаю:

mIntent имеет только дополнения, без флагов (насколько я могу судить):

android.intent.extra.CHOSEN_COMPONENT_INTENT_SENDER IntentSender{4fa3901: android.os.BinderProxy@3aec3a6} (android.content.IntentSender)

android.intent.extra.INTENT Intent { act=android.intent.action.SEND type=image/jpeg flg=0x80001 clip={image/jpeg U:content://com.android.chrome.FileProvider/images/screenshot/ 15307316967108618905323381238187.jpg} (есть дополнения) } (android.content.Intent)

android.intent.extra.TITLE Поделиться через (java.lang.String)

mPayloadIntent:

android.intent.extra.STREAM content://com.android.chrome.FileProvider/images/screenshot/1530731945132897653908815339041.jpg (android.net.Uri$HierarchicalUri)

  • FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
  • FLAG_ACTIVITY_NEW_DOCUMENT
  • FLAG_GRANT_READ_URI_PERMISSION

Итак, mPayloadIntent имеет FLAG_GRANT_READ_URI_PERMISSION, а mIntent нет. По документам должно.

Я читал, что мое приложение могло использовать разрешение URI, поэтому Я пытался кэшировать файл самостоятельно, но как только я пытаюсь получить доступ к URI через ContentResolver, я получаю, как вы уже догадались, ошибку разрешения.

Затем я понял, что мне, вероятно, не нужно кэшировать файл как родной Chooser Activity, похоже, тоже этого не делает. Вот где я сейчас. Возвращается на круги своя.

Это ошибка Хрома? Ошибка андроида? Или я что-то не так делаю?

Я бы с радостью обвинил Chrome и отправил отчет об ошибке, но кто-то, кто работает над подобным проектом (и столкнулся с той же проблемой), сказал мне, что у WhatsApp есть аналогичная проблема. Он также делится изображениями через контент: // uri.

Для полноты я тестирую это на Pixel 2016 с Android 8.1. Я понятия не имею, что использует другой парень (который столкнулся с той же проблемой с WA).


person REJH    schedule 04.07.2018    source источник


Ответы (1)


Это ошибка Хрома? Ошибка андроида? Или я что-то не так делаю?

Я предполагаю, что это ошибка на стороне клиента, исходящая от людей, создающих ACTION_CHOOSER Intent объекты напрямую, а не через Intent.createChooser(). Intent.createChooser() похоже, что он берет флаги из того, что вы назвали mPayloadIntent, и добавляет их к mIntent.

Вы должны быть в состоянии проверить это самостоятельно. Создайте приложение-записку, которое создает ACTION_SEND Intent с EXTRA_STREAM, указывающим на некоторый фрагмент контента (например, обслуживаемый FileProvider). Затем попробуйте вызвать средство выбора тремя способами:

  1. Оберните Intent через Intent.createChooser()

  2. Оберните Intent через ACTION_CHOOSER Intent, где вы следуете тому, что говорят документы, и поместите флаги на оба объекта Intent

  3. Оберните Intent через ACTION_CHOOSER Intent, где вы пропустите флажки на ACTION_CHOOSER Intent

Если я прав, #1 и #2 будут работать, а #3 выйдет из строя с тем же основным режимом отказа, который вы видите.

Если моя теория до сих пор верна, попробуйте снова запустить три приложения, но на этот раз используйте средство выбора системы. Я предполагаю, что средство выбора системы получает некоторые особые преимущества от того, что является частью основной ОС, и все три будут работать. В противном случае разработчики Chrome и WhatsApp столкнулись бы с этой проблемой при тестировании и исправили бы ее.

И, если вся эта теория верна... вы немного облажались. Я предполагаю, что больше людей используют Intent.createChooser(), чем используют ACTION_CHOOSER напрямую, поскольку Intent.createChooser() проще. И некоторые люди, использующие ACTION_CHOOSER, могут на самом деле следовать документации...

хахахахахахахаха... вздох ...хахахахахахахахахаха!

...и для них ты в порядке. Кроме того, у некоторых людей, использующих ACTION_CHOOSER, может быть Uri в EXTRA_STREAM, которое удобочитаемо всем (что не очень хорошая идея, но здесь это работает в вашу пользу). Только для клиентов с ошибками, которые создают ACTION_CHOOSER вручную, не могут правильно установить флаги Intent, но делают должным образом защищают свое содержимое, вы не сможете правильно обработать Intent.

person CommonsWare    schedule 04.07.2018
comment
Спасибо, я попробую. Может быть, я могу заглянуть в исходный код Chrome (это ОС), посмотреть, как они объединяют это намерение. Я нашел их (пользовательскую/расширенную) реализацию FileProvider. - person REJH; 05.07.2018
comment
Бах. Похоже, что №1, №2 и №3 имеют одинаковую проблему. Принимающее приложение аварийно завершает работу (или обнаруживает ошибку и просто выходит из строя). Кроме того, похоже, что Intent.createChooser() не добавляет флаги разрешений URI к намерению или намерению полезной нагрузки, поэтому я попытался добавить их, но не сигару. - person REJH; 05.07.2018
comment
Подробнее читайте в исходном коде Android ChooserActivity я обнаружил, что он использует метод startActivityAsCaller() для вызова намерения. Он объявлен в android. /app/Activity.java и не является частью общедоступного API. Это для действий решателя и выбора, которые действуют как посредники. Я думаю, что я трахаюсь :((( - person REJH; 05.07.2018