Skip to content

Commit 8bc2ef3

Browse files
committed
fix(android): Ensure all requests release transport
1 parent b4df77d commit 8bc2ef3

File tree

2 files changed

+74
-84
lines changed

2 files changed

+74
-84
lines changed

react-native-mcu-manager/android/src/main/java/uk/co/playerdata/reactnativemcumanager/DeviceUpgrade.kt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package uk.co.playerdata.reactnativemcumanager
22

3-
import android.bluetooth.BluetoothDevice
43
import android.content.Context
54
import android.net.Uri
65
import android.util.Log
@@ -35,7 +34,7 @@ val UpgradeFileTypes = mapOf(
3534
)
3635

3736
class DeviceUpgrade(
38-
device: BluetoothDevice,
37+
private val transport: McuMgrBleTransport,
3938
private val context: Context,
4039
private val updateFileUri: Uri,
4140
private val updateOptions: UpdateOptions,
@@ -44,7 +43,6 @@ class DeviceUpgrade(
4443
) : FirmwareUpgradeCallback<FirmwareUpgradeManager.State> {
4544
private val TAG = "DeviceUpdate"
4645
private var lastNotification = -1
47-
private var transport = McuMgrBleTransport(context, device)
4846
private var dfuManager = FirmwareUpgradeManager(transport, this)
4947
private var unsafePromise: Promise? = null
5048
private var promiseComplete = false

react-native-mcu-manager/android/src/main/java/uk/co/playerdata/reactnativemcumanager/ReactNativeMcuManagerModule.kt

Lines changed: 73 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -44,82 +44,84 @@ class ReactNativeMcuManagerModule() : Module() {
4444
private val context
4545
get() = requireNotNull(appContext.reactContext) { "React Application Context is null" }
4646

47-
private fun getBluetoothDevice(macAddress: String?): BluetoothDevice {
47+
private fun getTransport(macAddress: String): McuMgrBleTransport {
4848
val bluetoothManager = context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
49-
val adapter = bluetoothManager?.adapter ?: throw Exception("No bluetooth adapter")
49+
val adapter = bluetoothManager.adapter ?: throw Exception("No bluetooth adapter")
50+
val device = adapter.getRemoteDevice(macAddress)
5051

51-
return adapter.getRemoteDevice(macAddress)
52+
return McuMgrBleTransport(context, device)
5253
}
5354

54-
override fun definition() = ModuleDefinition {
55-
Name(MODULE_NAME)
55+
private fun withTransport(macAddress: String, block: (transport: McuMgrBleTransport) -> Unit) {
56+
val transport = getTransport(macAddress)
5657

57-
AsyncFunction("bootloaderInfo") { macAddress: String?, promise: Promise ->
58-
val device: BluetoothDevice = getBluetoothDevice(macAddress)
58+
transport.connect(transport.bluetoothDevice).timeout(60000).await()
5959

60-
val transport = McuMgrBleTransport(context, device)
61-
transport.connect(device).timeout(60000).await()
60+
try {
61+
block.invoke(transport)
62+
} finally {
63+
transport.release()
64+
}
65+
}
6266

63-
val manager = DefaultManager(transport)
64-
val info = BootloaderInfo()
67+
override fun definition() = ModuleDefinition {
68+
Name(MODULE_NAME)
6569

66-
try {
67-
val nameResult = manager.bootloaderInfo(DefaultManager.BOOTLOADER_INFO_QUERY_BOOTLOADER)
68-
info.bootloader = nameResult.bootloader
69-
} catch(ex: McuMgrErrorException) {
70-
transport.release()
70+
AsyncFunction("bootloaderInfo") { macAddress: String, promise: Promise ->
71+
withTransport(macAddress) { transport ->
72+
val manager = DefaultManager(transport)
73+
val info = BootloaderInfo()
74+
75+
try {
76+
val nameResult = manager.bootloaderInfo(DefaultManager.BOOTLOADER_INFO_QUERY_BOOTLOADER)
77+
info.bootloader = nameResult.bootloader
78+
} catch (ex: McuMgrErrorException) {
79+
// For consistency with iOS, if the error code is 8 (MGMT_ERR_ENOTSUP), return null
80+
if (ex.code == McuMgrErrorCode.NOT_SUPPORTED) {
81+
promise.resolve(info)
82+
return@withTransport
83+
}
7184

72-
// For consistency with iOS, if the error code is 8 (MGMT_ERR_ENOTSUP), return null
73-
if (ex.code == McuMgrErrorCode.NOT_SUPPORTED) {
74-
promise.resolve(info)
75-
return@AsyncFunction
85+
throw ex;
7686
}
7787

78-
throw ex;
79-
}
80-
81-
try {
82-
if (info.bootloader == MCUBOOT) {
83-
val mcuMgrResult = manager.bootloaderInfo(DefaultManager.BOOTLOADER_INFO_MCUBOOT_QUERY_MODE)
88+
try {
89+
if (info.bootloader == MCUBOOT) {
90+
val mcuMgrResult = manager.bootloaderInfo(DefaultManager.BOOTLOADER_INFO_MCUBOOT_QUERY_MODE)
8491

85-
info.mode = mcuMgrResult.mode
86-
info.noDowngrade = mcuMgrResult.noDowngrade
87-
}
88-
} catch (ex: McuMgrErrorException) {
89-
transport.release()
92+
info.mode = mcuMgrResult.mode
93+
info.noDowngrade = mcuMgrResult.noDowngrade
94+
}
95+
} catch (ex: McuMgrErrorException) {
96+
// For consistency with iOS, if the error code is 8 (MGMT_ERR_ENOTSUP), return null
97+
if (ex.code == McuMgrErrorCode.NOT_SUPPORTED) {
98+
promise.resolve(info)
99+
return@withTransport
100+
}
90101

91-
// For consistency with iOS, if the error code is 8 (MGMT_ERR_ENOTSUP), return null
92-
if (ex.code == McuMgrErrorCode.NOT_SUPPORTED) {
93-
promise.resolve(info)
94-
return@AsyncFunction
102+
throw ex;
95103
}
96104

97-
throw ex;
105+
promise.resolve(info)
98106
}
99-
100-
transport.release()
101-
promise.resolve(info)
102107
}
103108

104-
AsyncFunction("eraseImage") { macAddress: String?, promise: Promise ->
105-
try {
106-
val device: BluetoothDevice = getBluetoothDevice(macAddress)
107-
108-
val transport = McuMgrBleTransport(context, device)
109-
transport.connect(device).timeout(60000).await()
109+
AsyncFunction("eraseImage") { macAddress: String, promise: Promise ->
110+
withTransport(macAddress) { transport ->
111+
try {
112+
val imageManager = ImageManager(transport)
113+
imageManager.erase()
110114

111-
val imageManager = ImageManager(transport)
112-
imageManager.erase()
113-
114-
promise.resolve(null)
115-
} catch (e: McuMgrException) {
116-
promise.reject(ReactNativeMcuMgrException.fromMcuMgrException(e))
115+
promise.resolve(null)
116+
} catch (e: McuMgrException) {
117+
promise.reject(ReactNativeMcuMgrException.fromMcuMgrException(e))
118+
}
117119
}
118120
}
119121

120122
Function("createUpgrade") {
121123
id: String,
122-
macAddress: String?,
124+
macAddress: String,
123125
updateFileUriString: String?,
124126
updateOptions: UpdateOptions,
125127
progressCallback: JavaScriptFunction<Unit>,
@@ -128,24 +130,24 @@ class ReactNativeMcuManagerModule() : Module() {
128130
throw Exception("Update ID already present")
129131
}
130132

131-
val device: BluetoothDevice = getBluetoothDevice(macAddress)
133+
val transport = getTransport(macAddress)
132134
val updateFileUri = Uri.parse(updateFileUriString)
133135

134136
val upgrade = DeviceUpgrade(
135-
device,
136-
context,
137-
updateFileUri,
138-
updateOptions,
139-
{ progress ->
140-
appContext.executeOnJavaScriptThread {
141-
progressCallback(id, progress)
142-
}
143-
},
144-
{ state ->
145-
appContext.executeOnJavaScriptThread {
146-
stateCallback(id, state)
147-
}
137+
transport,
138+
context,
139+
updateFileUri,
140+
updateOptions,
141+
{ progress ->
142+
appContext.executeOnJavaScriptThread {
143+
progressCallback(id, progress)
144+
}
145+
},
146+
{ state ->
147+
appContext.executeOnJavaScriptThread {
148+
stateCallback(id, state)
148149
}
150+
}
149151
)
150152
this@ReactNativeMcuManagerModule.upgrades[id] = upgrade
151153
}
@@ -185,26 +187,16 @@ class ReactNativeMcuManagerModule() : Module() {
185187
}
186188

187189
AsyncFunction("resetDevice") { macAddress: String, promise: Promise ->
188-
val device: BluetoothDevice = getBluetoothDevice(macAddress)
189-
190-
val transport = McuMgrBleTransport(context, device)
191-
transport.connect(device).timeout(60000).await()
192-
193-
val manager = DefaultManager(transport)
190+
withTransport(macAddress) { transport ->
191+
val manager = DefaultManager(transport)
194192

195-
val callback = object: McuMgrCallback<McuMgrOsResponse> {
196-
override fun onResponse(response: McuMgrOsResponse) {
197-
transport.release()
193+
try {
194+
manager.reset()
198195
promise.resolve()
199-
}
200-
201-
override fun onError(error: McuMgrException) {
202-
transport.release()
196+
} catch (error: McuMgrException) {
203197
promise.reject(CodedException("RESET_DEVICE_FAILED", "Failed to reset device", error))
204198
}
205199
}
206-
207-
manager.reset(callback)
208200
}
209201
}
210202
}

0 commit comments

Comments
 (0)