2

My Android app I'm building is having difficulty reading any file from inside my app's directories, including internal storage (using filesDir).

Because it's internal storage, I shouldn't need any read/write permissions added to my manifest, but just to troubleshoot, I've added:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

Additionally, I'm targeting devices from Marshmallow up, so I have successfully implemented Runtime permissions as well (in a different activity)... so permissions of any type should not be an issue.

Here's my Kotlin code, which upon the Activity being started, is supposed to start playing an MP3 file. (The fileName is passed by the previous activity)

class RecordingManager : AppCompatActivity() {

    var audioPlayer: MediaPlayer? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_recording_manager)

        actionBar?.title = getString(R.string.recording_manager_actionbar_title)
        supportActionBar?.title = getString(R.string.recording_manager_actionbar_title)
        actionBar?.setDisplayHomeAsUpEnabled(true)
        supportActionBar?.setDisplayHomeAsUpEnabled(true)

        val typedValue = TypedValue()
        theme.resolveAttribute(R.attr.colorPrimary, typedValue, true)
        val color = typedValue.data

        supportActionBar?.setBackgroundDrawable(ColorDrawable(color))
        val recordingsDir = File(filesDir, "recordings")
        val fileName = intent.getStringExtra("fileName")
        txtTitle.text = fileName

        val audioFile = File(recordingsDir, fileName!!)
        audioFile.setReadable(true)
        audioFile.setWritable(true)



        var mediaPlayer: MediaPlayer? = MediaPlayer.create(this, Uri.parse(audioFile.absolutePath))
        mediaPlayer?.start() // no need to call prepare(); create() does that for you

    }

Reading the Logcat, I can clearly see that the MP3 file exists, however, MediaPlayer is unable to read it:

2019-08-05 14:03:21.360 993-20629/? E/ClearFileSource: Failed to open file '/data/user/0/dev.oliverm.materialvoicerecorder/files/recordings/recording2019-08-0323:35:55.97500.mp3'. (Permission denied)
2019-08-05 14:03:21.360 993-20629/? E/GenericSource: Failed to create data source!
2019-08-05 14:03:21.357 993-993/? W/generic: type=1400 audit(0.0:566): avc: denied { read } for name="0" dev="sda45" ino=524291 scontext=u:r:mediaserver:s0 tcontext=u:object_r:system_data_file:s0 tclass=lnk_file permissive=0
2019-08-05 14:03:21.360 20593-20610/dev.oliverm.materialvoicerecorder E/MediaPlayerNative: error (1, -2147483648)
2019-08-05 14:03:21.361 20593-20593/dev.oliverm.materialvoicerecorder D/MediaPlayer: create failed:

This line right here: W/generic: type=1400 audit(0.0:566): avc: denied { read } for name="0" dev="sda45" ino=524291 leads me to believe it's an SELinux issue.

I've tested this using multiple emulators & devices. I've used my own Pixel phone to test it, and I've used multiple emulators (M, N, O, P, Q beta) to no avail.

I have no idea why SELinux is not permitting my app to read files from inside my internal app's directory. Any help is greatly appreciated.

Oliver-H-Miller
  • 451
  • 1
  • 7
  • 19
  • For debugging purposes, you can instantiate a MediaPlayer, `var mediaPlayer = MediaPlayer()` and then surround `mediaPlayer.setContent(audioFile)` with a try catch and look at the actual exception being thrown. https://developer.android.com/reference/android/media/MediaPlayer.html#setDataSource(java.io.FileDescriptor) – user2836202 Aug 05 '19 at 20:41
  • @user2836202 mediaPlayer.setContent(file) is not a method, did you mean mediaPlayer.setDataSource(file)? – Oliver-H-Miller Aug 05 '19 at 22:01
  • what device you test with? – sanemars Aug 06 '19 at 03:40
  • @Oliver_H_Miller, that's what I meant. Sorry about that. I linked it and typed the wrong thing. Using that method should allow you to catch the error instead of having the library swallow and log it. – user2836202 Aug 06 '19 at 15:39
  • @user2836202 I tried surrounding the `mediaPlayer` code with a try/catch, still same `Permission denied` error :( – Oliver-H-Miller Aug 06 '19 at 22:32

2 Answers2

2
Uri.parse(audioFile.absolutePath)

audioFile.absolutePath is not a URI, its a path. URIs would start with a scheme (file:). Paths start from a directory. So you're parsing a non URI as a URI, ending with an exception. Use Uri.fromFile(audioFile) instead

Gabe Sechan
  • 90,003
  • 9
  • 87
  • 127
  • Thanks for your answer. I've tried what you said, using this: `var mediaPlayer: MediaPlayer? = MediaPlayer.create(this, Uri.fromFile(audioFile))`, however, I still get the same error from the LogCat as before :( – Oliver-H-Miller Aug 06 '19 at 19:11
0

Update

I finally was able to do some more work, and the code that works for me is below:

        audioPlayer = MediaPlayer()
        audioPlayer?.setDataSource("file://"+audioFile.absoluteFile)
        audioPlayer?.prepare()
        audioPlayer?.start()

My best guess why this was happening is that audioPlayer was created outside of the onCreate, and wasn't being set to MediaPlayer(). Now that I've explicitly set audioPlayer to MediaPlayer(), it appears to be working for now.

This conversation may also be helpful for others, it helps troubleshoot playing local files with MediaPlayer

If anyone has a better explanation, please feel free to leave your answer below, and I will mark it as correct.

Oliver-H-Miller
  • 451
  • 1
  • 7
  • 19