Skip to content

Commit e58cf4f

Browse files
committed
fix null pointer
1 parent bc2712e commit e58cf4f

5 files changed

Lines changed: 118 additions & 38 deletions

File tree

app/src/main/java/com/bitchat/android/mesh/BluetoothConnectionManager.kt

Lines changed: 84 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -128,11 +128,13 @@ class BluetoothConnectionManager(
128128

129129
try {
130130
isActive = true
131-
setupGattServer()
132131

133132
// Start power manager and services
134133
connectionScope.launch {
135134
powerManager.start()
135+
136+
// Setup GATT server after power manager is ready
137+
setupGattServer()
136138
delay(500) // Ensure GATT server is ready
137139

138140
startAdvertising()
@@ -146,13 +148,14 @@ class BluetoothConnectionManager(
146148

147149
startPeriodicCleanup()
148150

149-
Log.i(TAG, "Power-optimized Bluetooth services started successfully (CLIENT ONLY)")
151+
Log.i(TAG, "Power-optimized Bluetooth services started successfully")
150152
}
151153

152154
return true
153155

154156
} catch (e: Exception) {
155157
Log.e(TAG, "Failed to start Bluetooth services: ${e.message}")
158+
isActive = false
156159
return false
157160
}
158161
}
@@ -355,6 +358,12 @@ class BluetoothConnectionManager(
355358

356359
val serverCallback = object : BluetoothGattServerCallback() {
357360
override fun onConnectionStateChange(device: BluetoothDevice, status: Int, newState: Int) {
361+
// Guard against callbacks after service shutdown
362+
if (!isActive) {
363+
Log.d(TAG, "Server: Ignoring connection state change after shutdown")
364+
return
365+
}
366+
358367
when (newState) {
359368
BluetoothProfile.STATE_CONNECTED -> {
360369
Log.d(TAG, "Server: Device connected ${device.address}")
@@ -371,6 +380,20 @@ class BluetoothConnectionManager(
371380
}
372381
}
373382

383+
override fun onServiceAdded(status: Int, service: BluetoothGattService) {
384+
// Guard against callbacks after service shutdown
385+
if (!isActive) {
386+
Log.d(TAG, "Server: Ignoring service added callback after shutdown")
387+
return
388+
}
389+
390+
if (status == BluetoothGatt.GATT_SUCCESS) {
391+
Log.d(TAG, "Server: Service added successfully: ${service.uuid}")
392+
} else {
393+
Log.e(TAG, "Server: Failed to add service: ${service.uuid}, status: $status")
394+
}
395+
}
396+
374397
override fun onCharacteristicWriteRequest(
375398
device: BluetoothDevice,
376399
requestId: Int,
@@ -380,6 +403,12 @@ class BluetoothConnectionManager(
380403
offset: Int,
381404
value: ByteArray
382405
) {
406+
// Guard against callbacks after service shutdown
407+
if (!isActive) {
408+
Log.d(TAG, "Server: Ignoring characteristic write after shutdown")
409+
return
410+
}
411+
383412
if (characteristic.uuid == CHARACTERISTIC_UUID) {
384413
val packet = BitchatPacket.fromBinaryData(value)
385414
if (packet != null) {
@@ -402,13 +431,21 @@ class BluetoothConnectionManager(
402431
offset: Int,
403432
value: ByteArray
404433
) {
434+
// Guard against callbacks after service shutdown
435+
if (!isActive) {
436+
Log.d(TAG, "Server: Ignoring descriptor write after shutdown")
437+
return
438+
}
439+
405440
if (BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE.contentEquals(value)) {
406441
Log.d(TAG, "Device ${device.address} subscribed to notifications")
407442
subscribedDevices.add(device)
408443

409444
connectionScope.launch {
410445
delay(100)
411-
delegate?.onDeviceConnected(device)
446+
if (isActive) { // Check if still active
447+
delegate?.onDeviceConnected(device)
448+
}
412449
}
413450
}
414451

@@ -418,34 +455,51 @@ class BluetoothConnectionManager(
418455
}
419456
}
420457

421-
// Clean up existing server
422-
gattServer?.close()
423-
424-
gattServer = bluetoothManager.openGattServer(context, serverCallback)
425-
426-
// Create characteristic with notification support
427-
characteristic = BluetoothGattCharacteristic(
428-
CHARACTERISTIC_UUID,
429-
BluetoothGattCharacteristic.PROPERTY_READ or
430-
BluetoothGattCharacteristic.PROPERTY_WRITE or
431-
BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE or
432-
BluetoothGattCharacteristic.PROPERTY_NOTIFY,
433-
BluetoothGattCharacteristic.PERMISSION_READ or
434-
BluetoothGattCharacteristic.PERMISSION_WRITE
435-
)
436-
437-
val descriptor = BluetoothGattDescriptor(
438-
UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"),
439-
BluetoothGattDescriptor.PERMISSION_READ or BluetoothGattDescriptor.PERMISSION_WRITE
440-
)
441-
characteristic?.addDescriptor(descriptor)
442-
443-
val service = BluetoothGattService(SERVICE_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY)
444-
service.addCharacteristic(characteristic)
445-
446-
gattServer?.addService(service)
458+
// Proper cleanup sequencing to prevent race conditions
459+
gattServer?.let { server ->
460+
Log.d(TAG, "Cleaning up existing GATT server")
461+
connectionScope.launch {
462+
// Give time for pending callbacks to complete
463+
delay(100)
464+
server.close()
465+
}
466+
}
447467

448-
Log.i(TAG, "GATT server setup complete")
468+
// Create new server after cleanup delay
469+
connectionScope.launch {
470+
delay(200) // Allow previous server to fully close
471+
472+
if (!isActive) {
473+
Log.d(TAG, "Service inactive, skipping GATT server creation")
474+
return@launch
475+
}
476+
477+
gattServer = bluetoothManager.openGattServer(context, serverCallback)
478+
479+
// Create characteristic with notification support
480+
characteristic = BluetoothGattCharacteristic(
481+
CHARACTERISTIC_UUID,
482+
BluetoothGattCharacteristic.PROPERTY_READ or
483+
BluetoothGattCharacteristic.PROPERTY_WRITE or
484+
BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE or
485+
BluetoothGattCharacteristic.PROPERTY_NOTIFY,
486+
BluetoothGattCharacteristic.PERMISSION_READ or
487+
BluetoothGattCharacteristic.PERMISSION_WRITE
488+
)
489+
490+
val descriptor = BluetoothGattDescriptor(
491+
UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"),
492+
BluetoothGattDescriptor.PERMISSION_READ or BluetoothGattDescriptor.PERMISSION_WRITE
493+
)
494+
characteristic?.addDescriptor(descriptor)
495+
496+
val service = BluetoothGattService(SERVICE_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY)
497+
service.addCharacteristic(characteristic)
498+
499+
gattServer?.addService(service)
500+
501+
Log.i(TAG, "GATT server setup complete")
502+
}
449503
}
450504

451505
@Suppress("DEPRECATION")

app/src/main/java/com/bitchat/android/mesh/BluetoothMeshService.kt

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ class BluetoothMeshService(private val context: Context) {
4747
internal val connectionManager = BluetoothConnectionManager(context, myPeerID) // Made internal for access
4848
private val packetProcessor = PacketProcessor(myPeerID)
4949

50+
// Service state management
51+
private var isActive = false
52+
5053
// Delegate for message callbacks (maintains same interface)
5154
var delegate: BluetoothMeshDelegate? = null
5255

@@ -98,7 +101,10 @@ class BluetoothMeshService(private val context: Context) {
98101

99102
// SecurityManager delegate for key exchange notifications
100103
securityManager.delegate = object : SecurityManagerDelegate {
101-
override fun onKeyExchangeCompleted(peerID: String) {
104+
override fun onKeyExchangeCompleted(peerID: String, peerPublicKeyData: ByteArray) {
105+
// Notify delegate about key exchange completion so it can register peer fingerprint
106+
delegate?.registerPeerPublicKey(peerID, peerPublicKeyData)
107+
102108
// Send announcement and cached messages after key exchange
103109
serviceScope.launch {
104110
delay(100)
@@ -276,15 +282,24 @@ class BluetoothMeshService(private val context: Context) {
276282
* Start the mesh service
277283
*/
278284
fun startServices() {
285+
// Prevent double starts
286+
if (isActive) {
287+
Log.w(TAG, "Mesh service already active, ignoring duplicate start request")
288+
return
289+
}
290+
279291
Log.i(TAG, "Starting Bluetooth mesh service with peer ID: $myPeerID")
280292

281293
if (connectionManager.startServices()) {
294+
isActive = true
282295
Log.i(TAG, "Bluetooth services started successfully")
283296

284297
// Send initial announcements after services are ready
285298
serviceScope.launch {
286299
delay(1000)
287-
sendBroadcastAnnounce()
300+
if (isActive) { // Check if still active
301+
sendBroadcastAnnounce()
302+
}
288303
}
289304
} else {
290305
Log.e(TAG, "Failed to start Bluetooth services")
@@ -295,7 +310,13 @@ class BluetoothMeshService(private val context: Context) {
295310
* Stop all mesh services
296311
*/
297312
fun stopServices() {
313+
if (!isActive) {
314+
Log.w(TAG, "Mesh service not active, ignoring stop request")
315+
return
316+
}
317+
298318
Log.i(TAG, "Stopping Bluetooth mesh service")
319+
isActive = false
299320

300321
// Send leave announcement
301322
sendLeaveAnnouncement()
@@ -547,4 +568,5 @@ interface BluetoothMeshDelegate {
547568
fun decryptChannelMessage(encryptedContent: ByteArray, channel: String): String?
548569
fun getNickname(): String?
549570
fun isFavorite(peerID: String): Boolean
571+
fun registerPeerPublicKey(peerID: String, publicKeyData: ByteArray)
550572
}

app/src/main/java/com/bitchat/android/mesh/SecurityManager.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ class SecurityManager(private val encryptionService: EncryptionService, private
113113
Log.d(TAG, "Successfully processed key exchange from $peerID")
114114

115115
// Notify delegate
116-
delegate?.onKeyExchangeCompleted(peerID)
116+
delegate?.onKeyExchangeCompleted(peerID, packet.payload)
117117

118118
return true
119119

@@ -315,5 +315,5 @@ class SecurityManager(private val encryptionService: EncryptionService, private
315315
* Delegate interface for security manager callbacks
316316
*/
317317
interface SecurityManagerDelegate {
318-
fun onKeyExchangeCompleted(peerID: String)
318+
fun onKeyExchangeCompleted(peerID: String, peerPublicKeyData: ByteArray)
319319
}

app/src/main/java/com/bitchat/android/ui/ChatViewModel.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -253,10 +253,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application), B
253253
privateChatManager.toggleFavorite(peerID)
254254
}
255255

256-
fun registerPeerPublicKey(peerID: String, publicKeyData: ByteArray) {
257-
privateChatManager.registerPeerPublicKey(peerID, publicKeyData)
258-
}
259-
260256
// MARK: - Debug and Troubleshooting
261257

262258
fun getDebugStatus(): String {
@@ -341,6 +337,10 @@ class ChatViewModel(application: Application) : AndroidViewModel(application), B
341337
return meshDelegateHandler.isFavorite(peerID)
342338
}
343339

340+
override fun registerPeerPublicKey(peerID: String, publicKeyData: ByteArray) {
341+
privateChatManager.registerPeerPublicKey(peerID, publicKeyData)
342+
}
343+
344344
// MARK: - Emergency Clear
345345

346346
fun panicClearAllData() {

app/src/main/java/com/bitchat/android/ui/MeshDelegateHandler.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,4 +154,8 @@ class MeshDelegateHandler(
154154
override fun isFavorite(peerID: String): Boolean {
155155
return privateChatManager.isFavorite(peerID)
156156
}
157+
158+
override fun registerPeerPublicKey(peerID: String, publicKeyData: ByteArray) {
159+
privateChatManager.registerPeerPublicKey(peerID, publicKeyData)
160+
}
157161
}

0 commit comments

Comments
 (0)