2

With the recent changes on Android 10 (Q), trying to play a song from the user's device on an app (that targets sdk version 29 and runs Android 10) using ExoPlayer, prints the following log on the console and fails (the song is not played):

E/libprocessgroup: Error encountered killing process cgroup uid 99420 pid 20294: Permission denied
    com.google.android.exoplayer2.upstream.FileDataSource$FileDataSourceException: java.io.FileNotFoundException: /storage/emulated/0/Music/Nirvana/[1989] - Bleach/01 - Blew.mp3: open failed: EACCES (Permission denied)
        at com.google.android.exoplayer2.upstream.FileDataSource.open(FileDataSource.java:73)
        at com.google.android.exoplayer2.upstream.DefaultDataSource.open(DefaultDataSource.java:257)
        at com.google.android.exoplayer2.upstream.StatsDataSource.open(StatsDataSource.java:83)
        at com.google.android.exoplayer2.source.ProgressiveMediaPeriod$ExtractingLoadable.load(ProgressiveMediaPeriod.java:939)
        at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:394)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:919)
     Caused by: java.io.FileNotFoundException: /storage/emulated/0/Music/Nirvana/[1989] - Bleach/01 - Blew.mp3: open failed: EACCES (Permission denied)
        at libcore.io.IoBridge.open(IoBridge.java:496)
        at java.io.RandomAccessFile.<init>(RandomAccessFile.java:289)
        at java.io.RandomAccessFile.<init>(RandomAccessFile.java:152)
        at com.google.android.exoplayer2.upstream.FileDataSource.open(FileDataSource.java:65)
        at com.google.android.exoplayer2.upstream.DefaultDataSource.open(DefaultDataSource.java:257) 
        at com.google.android.exoplayer2.upstream.StatsDataSource.open(StatsDataSource.java:83) 
        at com.google.android.exoplayer2.source.ProgressiveMediaPeriod$ExtractingLoadable.load(ProgressiveMediaPeriod.java:939) 
        at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:394) 
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) 
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) 
        at java.lang.Thread.run(Thread.java:919) 
     Caused by: android.system.ErrnoException: open failed: EACCES (Permission denied)
        at libcore.io.Linux.open(Native Method)
        at libcore.io.ForwardingOs.open(ForwardingOs.java:167)
        at libcore.io.BlockGuardOs.open(BlockGuardOs.java:252)
        at libcore.io.ForwardingOs.open(ForwardingOs.java:167)
        at android.app.ActivityThread$AndroidOs.open(ActivityThread.java:7255)
        at libcore.io.IoBridge.open(IoBridge.java:482)
        at java.io.RandomAccessFile.<init>(RandomAccessFile.java:289) 
        at java.io.RandomAccessFile.<init>(RandomAccessFile.java:152) 
        at com.google.android.exoplayer2.upstream.FileDataSource.open(FileDataSource.java:65) 
        at com.google.android.exoplayer2.upstream.DefaultDataSource.open(DefaultDataSource.java:257) 
        at com.google.android.exoplayer2.upstream.StatsDataSource.open(StatsDataSource.java:83) 
        at com.google.android.exoplayer2.source.ProgressiveMediaPeriod$ExtractingLoadable.load(ProgressiveMediaPeriod.java:939) 
        at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:394) 
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) 
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) 
        at java.lang.Thread.run(Thread.java:919) 

One way that I found on the Internet to solve that problem is to add the following attribute on the Manifest's <application> tag:

android:requestLegacyExternalStorage="true"

The problem with that solution is that it seems to be temporary and might get deprecated soon.


What is the correct way to deal with those changes under those specifications?

Augusto Carmo
  • 4,386
  • 2
  • 28
  • 61

2 Answers2

2

After further trials, I was able to play a song using ExoPlayer using the Media's Uri.

// id col = `MediaStore.Audio.Media._ID`
val id = cursor.getLong(idColIndex)
val uri = ContentUris.withAppendedId(
    MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
    id
)

...

val songSource = ExtractorMediaSource.Factory(dataSourceFactory)
    .createMediaSource(uri)

It successfully played the song without any exceptions being thrown.

Augusto Carmo
  • 4,386
  • 2
  • 28
  • 61
1

See https://stackoverflow.com/a/59037794/2373819

But looking at the Exoplayer Source Code.

https://github.com/google/ExoPlayer/blob/release-v2/library/core/src/main/java/com/google/android/exoplayer2/upstream/FileDataSource.java

Says

file = new RandomAccessFile(dataSpec.uri.getPath(), "r");

And in API 29 and above file paths are not accessible in public files.

You should raise a bug in ExoPlayer to use Java a fileDescriptor from a contentresolver instead

Andrew
  • 8,198
  • 2
  • 15
  • 35