From 3aae8ea5349a58a8f6d5c87a79ee2fcd8fab4427 Mon Sep 17 00:00:00 2001 From: Alexander Capehart Date: Sat, 18 Jan 2025 09:58:05 -0700 Subject: [PATCH] musikr: bubblewrap nativeinputstream Try to avoid exceptions cascading and bringing down the app. --- musikr/src/main/cpp/JVMInputStream.cpp | 30 +++++++--- .../musikr/metadata/NativeInputStream.kt | 60 +++++++++++++++---- 2 files changed, 70 insertions(+), 20 deletions(-) diff --git a/musikr/src/main/cpp/JVMInputStream.cpp b/musikr/src/main/cpp/JVMInputStream.cpp index 0ede3272d..ee579250c 100644 --- a/musikr/src/main/cpp/JVMInputStream.cpp +++ b/musikr/src/main/cpp/JVMInputStream.cpp @@ -34,11 +34,11 @@ JVMInputStream::JVMInputStream(JNIEnv *env, jobject inputStream) : env(env), inp inputStreamIsOpenMethod = env->GetMethodID(inputStreamClass, "isOpen", "()Z"); inputStreamSeekFromBeginningMethod = env->GetMethodID(inputStreamClass, - "seekFromBeginning", "(J)V"); + "seekFromBeginning", "(J)Z"); inputStreamSeekFromCurrentMethod = env->GetMethodID(inputStreamClass, - "seekFromCurrent", "(J)V"); + "seekFromCurrent", "(J)Z"); inputStreamSeekFromEndMethod = env->GetMethodID(inputStreamClass, - "seekFromEnd", "(J)V"); + "seekFromEnd", "(J)Z"); inputStreamTellMethod = env->GetMethodID(inputStreamClass, "tell", "()J"); inputStreamLengthMethod = env->GetMethodID(inputStreamClass, "length", "()J"); @@ -58,6 +58,9 @@ TagLib::FileName JVMInputStream::name() const { TagLib::ByteVector JVMInputStream::readBlock(size_t length) { auto data = (jbyteArray) env->CallObjectMethod(inputStream, inputStreamReadBlockMethod, length); + if (data == nullptr) { + throw std::runtime_error("Failed to read block, see logs"); + } jsize dataLength = env->GetArrayLength(data); auto dataBytes = env->GetByteArrayElements(data, nullptr); TagLib::ByteVector byteVector(reinterpret_cast(dataBytes), @@ -89,19 +92,24 @@ bool JVMInputStream::isOpen() const { void JVMInputStream::seek(TagLib::offset_t offset, Position p) { auto joffset = static_cast(std::llround(offset)); + jboolean result; switch (p) { case Beginning: - env->CallVoidMethod(inputStream, inputStreamSeekFromBeginningMethod, - joffset); + result = env->CallBooleanMethod(inputStream, + inputStreamSeekFromBeginningMethod, joffset); break; case Current: - env->CallVoidMethod(inputStream, inputStreamSeekFromCurrentMethod, - joffset); + result = env->CallBooleanMethod(inputStream, + inputStreamSeekFromCurrentMethod, joffset); break; case End: - env->CallVoidMethod(inputStream, inputStreamSeekFromEndMethod, joffset); + result = env->CallBooleanMethod(inputStream, + inputStreamSeekFromEndMethod, joffset); break; } + if (!result) { + throw std::runtime_error("Failed to seek, see logs"); + } } void JVMInputStream::clear() { @@ -110,11 +118,17 @@ void JVMInputStream::clear() { TagLib::offset_t JVMInputStream::tell() const { jlong jposition = env->CallLongMethod(inputStream, inputStreamTellMethod); + if (jposition == INT64_MIN) { + throw std::runtime_error("Failed to get position, see logs"); + } return static_cast(jposition); } TagLib::offset_t JVMInputStream::length() { jlong jlength = env->CallLongMethod(inputStream, inputStreamLengthMethod); + if (jlength == INT64_MIN) { + throw std::runtime_error("Failed to get length, see logs"); + } return static_cast(jlength); } diff --git a/musikr/src/main/java/org/oxycblt/musikr/metadata/NativeInputStream.kt b/musikr/src/main/java/org/oxycblt/musikr/metadata/NativeInputStream.kt index fd6c9481b..e5bb2fb69 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/metadata/NativeInputStream.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/metadata/NativeInputStream.kt @@ -18,37 +18,73 @@ package org.oxycblt.musikr.metadata +import android.util.Log import java.io.FileInputStream import java.nio.ByteBuffer internal class NativeInputStream(fis: FileInputStream) { private val channel = fis.channel - fun readBlock(length: Long): ByteArray { - val buffer = ByteBuffer.allocate(length.toInt()) - channel.read(buffer) - return buffer.array() + fun readBlock(length: Long): ByteArray? { + try { + val buffer = ByteBuffer.allocate(length.toInt()) + channel.read(buffer) + return buffer.array() + } catch (e: Exception) { + Log.d("NativeInputStream", "Error reading block", e) + return null + } } fun isOpen(): Boolean { return channel.isOpen } - fun seekFromBeginning(offset: Long) { - channel.position(offset) + fun seekFromBeginning(offset: Long): Boolean { + try { + channel.position(offset) + return true + } catch (e: Exception) { + Log.d("NativeInputStream", "Error seeking from beginning", e) + return false + } } - fun seekFromCurrent(offset: Long) { - channel.position(channel.position() + offset) + fun seekFromCurrent(offset: Long): Boolean { + try { + channel.position(channel.position() + offset) + return true + } catch (e: Exception) { + Log.d("NativeInputStream", "Error seeking from current", e) + return false + } } - fun seekFromEnd(offset: Long) { - channel.position(channel.size() + offset) + fun seekFromEnd(offset: Long): Boolean { + try { + channel.position(channel.size() + offset) + return true + } catch (e: Exception) { + Log.d("NativeInputStream", "Error seeking from end", e) + return false + } } - fun tell() = channel.position() + fun tell() = + try { + channel.position() + } catch (e: Exception) { + Log.d("NativeInputStream", "Error getting position", e) + Long.MIN_VALUE + } - fun length() = channel.size() + fun length() = + try { + channel.size() + } catch (e: Exception) { + Log.d("NativeInputStream", "Error getting length", e) + Long.MIN_VALUE + } fun close() { channel.close()