From 0319570049e184ed54ab89fc393bdd10c257e3b2 Mon Sep 17 00:00:00 2001 From: Erik Date: Mon, 5 Oct 2026 17:40:31 -0700 Subject: [PATCH] Fix native VehicleDecoder leak in DashKitDataSource Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_017nzxRV1bnDuyu5Ma2AgR7q --- .../dashpilot/datasource/DashKitDataSource.kt | 3 ++- .../softwiredtech/dashpilot/vehicle/CanFrameDecoder.kt | 8 +++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/datasource/DashKitDataSource.kt b/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/datasource/DashKitDataSource.kt index 262de43e..078fa0b8 100644 --- a/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/datasource/DashKitDataSource.kt +++ b/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/datasource/DashKitDataSource.kt @@ -37,6 +37,7 @@ class DashKitDataSource( override fun disconnect() { manager.removeGattListener(this) + decoder.destroy() } override fun onServicesReady(gatt: BluetoothGatt) { @@ -66,7 +67,7 @@ class DashKitDataSource( private fun parseAndEmit(payload: ByteArray) { if (payload.isEmpty()) return for (frame in parseCanPacket(payload)) { - currentState = decoder.decodeFrame(frame.bus, frame.address, frame.data) + currentState = decoder.decodeFrame(frame.bus, frame.address, frame.data) ?: return } _incoming.tryEmit(currentState) } diff --git a/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/vehicle/CanFrameDecoder.kt b/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/vehicle/CanFrameDecoder.kt index cd80e453..fb4dadf4 100644 --- a/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/vehicle/CanFrameDecoder.kt +++ b/dashpilot-android/app/src/main/java/com/softwiredtech/dashpilot/vehicle/CanFrameDecoder.kt @@ -9,17 +9,19 @@ class CanFrameDecoder( private val bridge: VehicleBridge, profile: VehicleProfile ) { - val decoderHandle: Long = bridge.nativeCreateVehicleDecoder( + var decoderHandle: Long = bridge.nativeCreateVehicleDecoder( profile.dbcContents, profile.busIndices, profile.type ) - fun decodeFrame(bus: Int, address: Int, data: ByteArray): CarState { + @Synchronized fun decodeFrame(bus: Int, address: Int, data: ByteArray): CarState? { + if (decoderHandle == 0L) return null val values = bridge.nativeDecodeCanFrame(decoderHandle, bus, address, data) return arrayToCarState(values) } - fun destroy() { + @Synchronized fun destroy() { bridge.nativeDestroyVehicleDecoder(decoderHandle) + decoderHandle = 0 } companion object {