Essentials icon indicating copy to clipboard operation
Essentials copied to clipboard

[Bug] Share.RequestAsync causes java.lang.SecurityException: Permission Denial

Open redcurry opened this issue 4 years ago • 15 comments

Description

Using Share.RequestAsync with ShareFileRequest prints out an exception on the Debug console (actual URI has been replaced with <redacted>):

06-21 16:57:58.952 E/DatabaseUtils( 8291): Writing exception to parcel
06-21 16:57:58.952 E/DatabaseUtils( 8291): java.lang.SecurityException: Permission Denial: reading xamarin.essentials.fileProvider uri content://<redacted> from pid=8356, uid=1000 requires the provider be exported, or grantUriPermission()
06-21 16:57:58.952 E/DatabaseUtils( 8291): 	at android.content.ContentProvider.enforceReadPermissionInner(ContentProvider.java:729)
06-21 16:57:58.952 E/DatabaseUtils( 8291): 	at android.content.ContentProvider$Transport.enforceReadPermission(ContentProvider.java:602)
06-21 16:57:58.952 E/DatabaseUtils( 8291): 	at android.content.ContentProvider$Transport.query(ContentProvider.java:231)
06-21 16:57:58.952 E/DatabaseUtils( 8291): 	at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:104)
06-21 16:57:58.952 E/DatabaseUtils( 8291): 	at android.os.Binder.execTransactInternal(Binder.java:1021)
06-21 16:57:58.952 E/DatabaseUtils( 8291): 	at android.os.Binder.execTransact(Binder.java:994)

Despite the exception printed, the app works as expected.

Steps to Reproduce

  1. Create a file in Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData).
  2. Call await Share.RequestAsync(new ShareFileRequest(new ShareFile(path)));

Expected Behavior

Shows the platform-dependent share UI to share the file. No exception printed on the console.

Actual Behavior

Prints an exception to the console. The share UI is shown as expected.

Basic Information

  • Version with issue: 1.5.3.2
  • Last known good version: Unknown
  • IDE: Visual Studio Community 2019
  • Platform Target Frameworks:
    • iOS: None
    • Android: 10.0 (API 29)
    • UWP: None
  • Android Support Library Version:
  • Nuget Packages: Acr.UserDialogs, AiForms.SettingsView, CsvHelper, DryIoc.dll, MetadataExtractor, MvvmLightLibsStd10, NLog, Resizetizer.NT, SkiaSharp.Views.Forms, sqlite-net-pcl
  • Affected Devices: Google Pixel 2

redcurry avatar Jun 21 '20 21:06 redcurry

@redcurry I'm guessing that is caused by the change on Android 10 permissions. If you target Android9.0 this error occurs?

pictos avatar Jun 21 '20 22:06 pictos

Are you missing a perrmision granted? String packageName = resolveInfo.activityInfo.packageName; context.grantUriPermission(some permissions);

broteam168 avatar Jun 22 '20 02:06 broteam168

@pictos I targeted Android 9.0 and the exception did not happen.

@broteam168 The documentation page did not talk about any specific permissions, so I did not set any.

redcurry avatar Jun 22 '20 03:06 redcurry

@redcurry, I have been in trouble with Android 10 permission API as well, from my research I found that this API was changed a little bit, to provide more privacy to the end-user. One of then is the Storage permission, It looks like you need to ask permission to access each folder that you need. To be honest I didn't look for more details on that.

For now, if you can I suggest you keep the target version to Android 9.0

pictos avatar Jun 22 '20 03:06 pictos

@pictos Let me correct myself in something. I've always been targeting Android 9.0. What I changed was the emulated device. I got the exception on an Android 10.0 device, but not on an Android 9.0 device.

Thanks for the documentation link. I'll look into it.

redcurry avatar Jun 22 '20 04:06 redcurry

Just a note, I had this problem when I forgot to add the Xamarin.Essentials NuGet package to the Android project. Then the necessary .xml file for the FileProvider wasn't integrated into the Android app. Solved my problem.

vividos avatar Apr 13 '21 06:04 vividos

I have updated documentation based on all of the changes in Android 10.

Sounds like we are good?

jamesmontemagno avatar Apr 14 '21 05:04 jamesmontemagno

I have updated documentation based on all of the changes in Android 10.

James, not sure which page was updated but I can't find any "permissions" info on the Xamarin.Essentials: Share document page.

I've just tried the following code:-

string sDirPath = FileSystem.CacheDirectory;
string sFilePath = Path.Combine(sDirPath, sFilename);
File.WriteAllBytes(sFilePath, data);

// share the zip file
_ = Share.RequestAsync(new ShareFileRequest
{
	File = new ShareFile(sFilePath),
	Title = "Share Zipped Records"
});

... and I still get ...

[DatabaseUtils] java.lang.SecurityException: Permission Denial: reading xamarin.essentials.fileProvider uri content://xxxxxx.fileProvider/external_cache/2203693cc04e0be7f4f024d5f9499e13/c04154eb620d4dd3b9d4d5c404f4eb80/xxxxxxx.zip from pid=844, uid=1000 requires the provider be exported, or grantUriPermission()
[DatabaseUtils] 	at android.content.ContentProvider.enforceReadPermissionInner(ContentProvider.java:841)
[DatabaseUtils] 	at android.content.ContentProvider.semEnforceReadPermission(ContentProvider.java:758)
[DatabaseUtils] 	at android.content.ContentProvider$Transport.enforceReadPermission(ContentProvider.java:684)
[DatabaseUtils] 	at android.content.ContentProvider$Transport.query(ContentProvider.java:239)
[DatabaseUtils] 	at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:106)
[DatabaseUtils] 	at android.os.Binder.execTransactInternal(Binder.java:1190)
[DatabaseUtils] 	at android.os.Binder.execTransact(Binder.java:1159)

mpfj avatar Sep 07 '21 15:09 mpfj

@mpfj did you add the Xamarin.Essentials NuGet package to the Android project?

jamesmontemagno avatar Sep 08 '21 00:09 jamesmontemagno

@jamesmontemagno yes ...

image

mpfj avatar Sep 08 '21 08:09 mpfj

Hmmmm what we will want to see is if the file provider is being added into your file build https://github.com/xamarin/Essentials/blob/main/Xamarin.Essentials/Resources/xml/xamarin_essentials_fileprovider_file_paths.xml

Maybe try to add this manually to your Android app in Resources/xml/ with the same name and see if that fixes it.

And also if the file provider is being swizzled in https://github.com/xamarin/Essentials/blob/main/Xamarin.Essentials/Types/FileProvider.android.cs

Here it is not exported, but it is granting UI permission

What you want to do is going into your Android project folder on disk and go to obj/100 or obj/110, whatever you target.

Look inside of your AndroidManifest.xml in that folder and you will want to see:

    <provider android:authorities="com.xamarin.essentials.fileProvider" android:exported="false" android:grantUriPermissions="true" android:name="xamarin.essentials.fileProvider">
      <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/xamarin_essentials_fileprovider_file_paths" />
    </provider>

jamesmontemagno avatar Sep 08 '21 17:09 jamesmontemagno

Maybe try to add this manually to your Android app in Resources/xml/ with the same name and see if that fixes it.

(1) Added this but it made no difference.

Look inside of your AndroidManifest.xml in that folder and you will want to see:

    <provider android:authorities="com.xamarin.essentials.fileProvider" android:exported="false" android:grantUriPermissions="true" android:name="xamarin.essentials.fileProvider">
      <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/xamarin_essentials_fileprovider_file_paths" />
    </provider>

(2) This is already present in the manifest file, so not that either :(

mpfj avatar Sep 08 '21 21:09 mpfj

This also happened to me. Building with target Android version 11.0 (API 30) and running in a device with Android 11.

I figured out that happens when contentUris.Count == 1 in PlatformRequestAsync. Somehow Intent.ActionSendMultiple with intent.PutParcelableArrayListExtra works while Intent.ActionSend with intent.PutExtra(Intent.ExtraStream, contentUris[0]) doesn't.

I can create a PR to make it always handle it as SendMultiple but I'm not sure if it is the correct way to fix it.

lucasbrahm avatar Jul 18 '22 00:07 lucasbrahm

Tested on Android 8, 9, 10, 11, 12 (Samsung and Huawei Devices)

AndroidManifest.xml

<provider android:authorities="${applicationId}.provider" android:exported="false" android:grantUriPermissions="true" android:name="androidx.core.content.FileProvider">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/sharing_paths" />
</provider>

sharing_paths.xml

<path>
...
 <external-path name="Android/data/${applicationId}/ABC" path="."/>
..
</path>

Example.Java

import androidx.core.content.FileProvider;
...

try {
String mediaUri = "/storage/emulated/0/android/data/****.****.****.****/files/ABC/audiofile_202208180412_7596.m4a";  //for example

 Intent intent = new Intent(Intent.ACTION_SEND);
          File file = new File(mediaUri);
          if (file.exists()) {
          intent.setType("audio/*");
          Uri uri = FileProvider.getUriForFile(this, APPLICATION_ID + ".provider", file);
          intent.setClipData(ClipData.newRawUri("", uri));
          intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
          intent.putExtra(Intent.EXTRA_STREAM, uri);
          startActivity(Intent.createChooser(intent, "Sharing to..."));
          }
          }catch (IllegalArgumentException e) {
             e.printStackTrace();
}
 ...        

FaakhirIqbal avatar Aug 18 '22 11:08 FaakhirIqbal

Can confirm that issue is still happening on android 11 with sample from the (https://learn.microsoft.com/en-us/xamarin/essentials/share?tabs=ios)

WanftMoon avatar Oct 11 '22 17:10 WanftMoon