Android: Fix Bad file descriptor in SAF/MediaStore in long term access
(cherry picked from commit 1c80b25af8c6c6f8cf6c80b96e7fdb10a18efa8a)
This commit is contained in:
committed by
Thaddeus Crews
parent
2dec60976f
commit
a570951ff4
@@ -37,6 +37,7 @@ import android.database.Cursor
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Environment
|
||||
import android.os.ParcelFileDescriptor
|
||||
import android.provider.MediaStore
|
||||
import android.util.Log
|
||||
import androidx.annotation.RequiresApi
|
||||
@@ -45,6 +46,7 @@ import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.io.FileNotFoundException
|
||||
import java.io.FileOutputStream
|
||||
import java.io.IOException
|
||||
import java.nio.channels.FileChannel
|
||||
|
||||
|
||||
@@ -53,7 +55,7 @@ import java.nio.channels.FileChannel
|
||||
* under scoped storage via the MediaStore API.
|
||||
*/
|
||||
@RequiresApi(Build.VERSION_CODES.Q)
|
||||
internal class MediaStoreData(context: Context, filePath: String, accessFlag: FileAccessFlags) :
|
||||
internal class MediaStoreData(context: Context, private val filePath: String, accessFlag: FileAccessFlags) :
|
||||
DataAccess.FileChannelDataAccess(filePath) {
|
||||
|
||||
private data class DataItem(
|
||||
@@ -248,6 +250,7 @@ internal class MediaStoreData(context: Context, filePath: String, accessFlag: Fi
|
||||
private val id: Long
|
||||
private val uri: Uri
|
||||
override val fileChannel: FileChannel
|
||||
private val parcelFileDescriptor: ParcelFileDescriptor
|
||||
|
||||
init {
|
||||
val contentResolver = context.contentResolver
|
||||
@@ -282,7 +285,7 @@ internal class MediaStoreData(context: Context, filePath: String, accessFlag: Fi
|
||||
id = dataItem.id
|
||||
uri = dataItem.uri
|
||||
|
||||
val parcelFileDescriptor = contentResolver.openFileDescriptor(uri, accessFlag.getMode())
|
||||
parcelFileDescriptor = contentResolver.openFileDescriptor(uri, accessFlag.getMode())
|
||||
?: throw IllegalStateException("Unable to access file descriptor")
|
||||
fileChannel = if (accessFlag == FileAccessFlags.READ) {
|
||||
FileInputStream(parcelFileDescriptor.fileDescriptor).channel
|
||||
@@ -294,4 +297,18 @@ internal class MediaStoreData(context: Context, filePath: String, accessFlag: Fi
|
||||
fileChannel.truncate(0)
|
||||
}
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
try {
|
||||
fileChannel.close()
|
||||
} catch (e: IOException) {
|
||||
Log.w(TAG, "Exception when closing file $filePath.", e)
|
||||
} finally {
|
||||
try {
|
||||
parcelFileDescriptor.close()
|
||||
} catch (e: IOException) {
|
||||
Log.w(TAG, "Exception when closing ParcelFileDescriptor for $filePath.", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,19 +32,21 @@ package org.godotengine.godot.io.file
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.os.ParcelFileDescriptor
|
||||
import android.provider.DocumentsContract
|
||||
import android.util.Log
|
||||
import androidx.core.net.toUri
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import java.io.FileInputStream
|
||||
import java.io.FileOutputStream
|
||||
import java.io.IOException
|
||||
import java.nio.channels.FileChannel
|
||||
|
||||
/**
|
||||
* Implementation of [DataAccess] which handles file access via a content URI obtained using the Android
|
||||
* Storage Access Framework (SAF).
|
||||
*/
|
||||
internal class SAFData(context: Context, path: String, accessFlag: FileAccessFlags) :
|
||||
internal class SAFData(context: Context, private val path: String, accessFlag: FileAccessFlags) :
|
||||
DataAccess.FileChannelDataAccess(path) {
|
||||
|
||||
companion object {
|
||||
@@ -173,9 +175,10 @@ internal class SAFData(context: Context, path: String, accessFlag: FileAccessFla
|
||||
}
|
||||
|
||||
override val fileChannel: FileChannel
|
||||
val parcelFileDescriptor: ParcelFileDescriptor
|
||||
init {
|
||||
val uri = resolvePath(context, path, accessFlag)
|
||||
val parcelFileDescriptor = context.contentResolver.openFileDescriptor(uri, accessFlag.getMode())
|
||||
parcelFileDescriptor = context.contentResolver.openFileDescriptor(uri, accessFlag.getMode())
|
||||
?: throw IllegalStateException("Unable to access file descriptor")
|
||||
fileChannel = if (accessFlag == FileAccessFlags.READ) {
|
||||
FileInputStream(parcelFileDescriptor.fileDescriptor).channel
|
||||
@@ -187,4 +190,18 @@ internal class SAFData(context: Context, path: String, accessFlag: FileAccessFla
|
||||
fileChannel.truncate(0)
|
||||
}
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
try {
|
||||
fileChannel.close()
|
||||
} catch (e: IOException) {
|
||||
Log.w(TAG, "Exception when closing file $path.", e)
|
||||
} finally {
|
||||
try {
|
||||
parcelFileDescriptor.close()
|
||||
} catch (e: IOException) {
|
||||
Log.w(TAG, "Exception when closing ParcelFileDescriptor for $path.", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user