android: stricter IO usage

This commit is contained in:
Thibault Deckers 2021-08-02 14:14:29 +09:00
parent 888c5e567f
commit 9b90c7ba84
7 changed files with 76 additions and 54 deletions

View file

@ -31,6 +31,18 @@ class MainActivity : FlutterActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
Log.i(LOG_TAG, "onCreate intent=$intent")
// StrictMode.setThreadPolicy(
// StrictMode.ThreadPolicy.Builder()
// .detectAll()
// .penaltyLog()
// .build()
// )
// StrictMode.setVmPolicy(
// StrictMode.VmPolicy.Builder()
// .detectAll()
// .penaltyLog()
// .build()
// )
super.onCreate(savedInstanceState)
val messenger = flutterEngine!!.dartExecutor.binaryMessenger

View file

@ -36,7 +36,7 @@ import java.util.*
class DebugHandler(private val context: Context) : MethodCallHandler {
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
when (call.method) {
"getContextDirs" -> result.success(getContextDirs())
"getContextDirs" -> GlobalScope.launch(Dispatchers.IO) { safe(call, result, ::getContextDirs) }
"getEnv" -> result.success(System.getenv())
"getBitmapFactoryInfo" -> GlobalScope.launch(Dispatchers.IO) { safe(call, result, ::getBitmapFactoryInfo) }
"getContentResolverMetadata" -> GlobalScope.launch(Dispatchers.IO) { safe(call, result, ::getContentResolverMetadata) }
@ -48,24 +48,28 @@ class DebugHandler(private val context: Context) : MethodCallHandler {
}
}
private fun getContextDirs() = hashMapOf(
"cacheDir" to context.cacheDir,
"filesDir" to context.filesDir,
"obbDir" to context.obbDir,
"externalCacheDir" to context.externalCacheDir,
).apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
putAll(
hashMapOf(
"codeCacheDir" to context.codeCacheDir,
"noBackupFilesDir" to context.noBackupFilesDir,
private fun getContextDirs(@Suppress("UNUSED_PARAMETER") call: MethodCall, result: MethodChannel.Result) {
val dirs = hashMapOf(
"cacheDir" to context.cacheDir,
"filesDir" to context.filesDir,
"obbDir" to context.obbDir,
"externalCacheDir" to context.externalCacheDir,
).apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
putAll(
hashMapOf(
"codeCacheDir" to context.codeCacheDir,
"noBackupFilesDir" to context.noBackupFilesDir,
)
)
)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
put("dataDir", context.dataDir)
}
}.mapValues { it.value?.path }
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
put("dataDir", context.dataDir)
}
}.mapValues { it.value?.path }
result.success(dirs)
}
private fun getBitmapFactoryInfo(call: MethodCall, result: MethodChannel.Result) {
val uri = call.argument<String>("uri")?.let { Uri.parse(it) }

View file

@ -9,11 +9,14 @@ import deckers.thibault.aves.utils.LogUtils
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
class GlobalSearchHandler(private val context: Activity) : MethodCallHandler {
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
when (call.method) {
"registerCallback" -> safe(call, result, ::registerCallback)
"registerCallback" -> GlobalScope.launch(Dispatchers.IO) { safe(call, result, ::registerCallback) }
else -> result.notImplemented()
}
}
@ -25,7 +28,6 @@ class GlobalSearchHandler(private val context: Activity) : MethodCallHandler {
return
}
Log.i(LOG_TAG, "register global search callback")
context.getSharedPreferences(SearchSuggestionsProvider.SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE)
.edit()
.putLong(SearchSuggestionsProvider.CALLBACK_HANDLE_KEY, callbackHandle)

View file

@ -23,13 +23,13 @@ import java.util.*
class StorageHandler(private val context: Context) : MethodCallHandler {
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
when (call.method) {
"getStorageVolumes" -> safe(call, result, ::getStorageVolumes)
"getFreeSpace" -> safe(call, result, ::getFreeSpace)
"getGrantedDirectories" -> safe(call, result, ::getGrantedDirectories)
"getInaccessibleDirectories" -> safe(call, result, ::getInaccessibleDirectories)
"getRestrictedDirectories" -> safe(call, result, ::getRestrictedDirectories)
"getStorageVolumes" -> GlobalScope.launch(Dispatchers.IO) { safe(call, result, ::getStorageVolumes) }
"getFreeSpace" -> GlobalScope.launch(Dispatchers.IO) { safe(call, result, ::getFreeSpace) }
"getGrantedDirectories" -> GlobalScope.launch(Dispatchers.IO) { safe(call, result, ::getGrantedDirectories) }
"getInaccessibleDirectories" -> GlobalScope.launch(Dispatchers.IO) { safe(call, result, ::getInaccessibleDirectories) }
"getRestrictedDirectories" -> GlobalScope.launch(Dispatchers.IO) { safe(call, result, ::getRestrictedDirectories) }
"revokeDirectoryAccess" -> safe(call, result, ::revokeDirectoryAccess)
"deleteEmptyDirectories" -> safe(call, result, ::deleteEmptyDirectories)
"deleteEmptyDirectories" -> GlobalScope.launch(Dispatchers.IO) { safe(call, result, ::deleteEmptyDirectories) }
"scanFile" -> GlobalScope.launch(Dispatchers.IO) { safe(call, result, ::scanFile) }
else -> result.notImplemented()
}
@ -38,7 +38,7 @@ class StorageHandler(private val context: Context) : MethodCallHandler {
private fun getStorageVolumes(@Suppress("UNUSED_PARAMETER") call: MethodCall, result: MethodChannel.Result) {
val volumes = ArrayList<Map<String, Any>>()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val sm = context.getSystemService(StorageManager::class.java)
val sm = context.getSystemService(Context.STORAGE_SERVICE) as? StorageManager
if (sm != null) {
for (volumePath in getVolumePaths(context)) {
try {

View file

@ -39,7 +39,7 @@ class StorageAccessStreamHandler(private val activity: Activity, arguments: Any?
handler = Handler(Looper.getMainLooper())
when (op) {
"requestVolumeAccess" -> requestVolumeAccess()
"requestVolumeAccess" -> GlobalScope.launch(Dispatchers.IO) { requestVolumeAccess() }
"createFile" -> GlobalScope.launch(Dispatchers.IO) { createFile() }
"openFile" -> GlobalScope.launch(Dispatchers.IO) { openFile() }
"selectDirectory" -> GlobalScope.launch(Dispatchers.IO) { selectDirectory() }
@ -83,18 +83,20 @@ class StorageAccessStreamHandler(private val activity: Activity, arguments: Any?
putExtra(Intent.EXTRA_TITLE, name)
}
MainActivity.pendingResultHandlers[MainActivity.CREATE_FILE_REQUEST] = PendingResultHandler(null, { uri ->
try {
activity.contentResolver.openOutputStream(uri)?.use { output ->
output as FileOutputStream
// truncate is necessary when overwriting a longer file
output.channel.truncate(0)
output.write(bytes)
GlobalScope.launch(Dispatchers.IO) {
try {
activity.contentResolver.openOutputStream(uri)?.use { output ->
output as FileOutputStream
// truncate is necessary when overwriting a longer file
output.channel.truncate(0)
output.write(bytes)
}
success(true)
} catch (e: Exception) {
error("createFile-write", "failed to write file at uri=$uri", e.message)
}
success(true)
} catch (e: Exception) {
error("createFile-write", "failed to write file at uri=$uri", e.message)
endOfStream()
}
endOfStream()
}, {
success(null)
endOfStream()
@ -115,13 +117,15 @@ class StorageAccessStreamHandler(private val activity: Activity, arguments: Any?
type = mimeType
}
MainActivity.pendingResultHandlers[MainActivity.OPEN_FILE_REQUEST] = PendingResultHandler(null, { uri ->
activity.contentResolver.openInputStream(uri)?.use { input ->
val buffer = ByteArray(BUFFER_SIZE)
var len: Int
while (input.read(buffer).also { len = it } != -1) {
success(buffer.copyOf(len))
GlobalScope.launch(Dispatchers.IO) {
activity.contentResolver.openInputStream(uri)?.use { input ->
val buffer = ByteArray(BUFFER_SIZE)
var len: Int
while (input.read(buffer).also { len = it } != -1) {
success(buffer.copyOf(len))
}
endOfStream()
}
endOfStream()
}
}, {
success(ByteArray(0))

View file

@ -25,7 +25,7 @@ object PermissionManager {
var intent: Intent? = null
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val sm = activity.getSystemService(StorageManager::class.java)
val sm = activity.getSystemService(Context.STORAGE_SERVICE) as? StorageManager
intent = sm?.getStorageVolume(File(path))?.createOpenDocumentTreeIntent()
}

View file

@ -187,14 +187,13 @@ object StorageUtils {
// /storage/10F9-3F13/Pictures/ -> 10F9-3F13
private fun getVolumeUuidForTreeUri(context: Context, anyPath: String): String? {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
context.getSystemService(StorageManager::class.java)?.let { sm ->
sm.getStorageVolume(File(anyPath))?.let { volume ->
if (volume.isPrimary) {
return "primary"
}
volume.uuid?.let { uuid ->
return uuid.uppercase(Locale.ROOT)
}
val sm = context.getSystemService(Context.STORAGE_SERVICE) as? StorageManager
sm?.getStorageVolume(File(anyPath))?.let { volume ->
if (volume.isPrimary) {
return "primary"
}
volume.uuid?.let { uuid ->
return uuid.uppercase(Locale.ROOT)
}
}
}
@ -222,7 +221,8 @@ object StorageUtils {
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
context.getSystemService(StorageManager::class.java)?.let { sm ->
val sm = context.getSystemService(Context.STORAGE_SERVICE) as? StorageManager
if (sm != null) {
for (volumePath in getVolumePaths(context)) {
try {
val volume = sm.getStorageVolume(File(volumePath))