Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix ConcurrentModification Exception on asWritableMap on GATT connected peripherals. #1264

Closed
wants to merge 0 commits into from

Conversation

lucaswitch
Copy link
Contributor

Fixes Concurrency problems on parsing back Peripherals objects.
Aims to fix the occurrence of problem as reported on issue #1229

Copy link
Contributor

@vhakulinen vhakulinen Sep 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for a drive by comment, but why are you deleting the lock file for the example?

@@ -220,13 +221,12 @@ public WritableMap asWritableMap(BluetoothGatt gatt) {
WritableArray characteristicsArray = Arguments.createArray();

if (connected && gatt != null) {
for (Iterator<BluetoothGattService> it = gatt.getServices().iterator(); it.hasNext();) {
for (Iterator<BluetoothGattService> it = new CopyOnWriteArrayList<>(gatt.getServices()).iterator(); it.hasNext();) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm doubtful that this will actually fix the problem, but merely hide it.

Copy link
Contributor Author

@lucaswitch lucaswitch Sep 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At least will solve for iterator .next() presenting sudden crash, not hiding it Services and caracteristics are being changed by the time asWritable method is called. I dont see any problem with that since asWritable role is just parsing as a rn bridge object for events and callbacks. Also copy on write will ensure last known characteristics and services for that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you suggest a better approach on that?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would really be interested in the actual reason why the ConcurrentModificationException is thrown.
Since we (i.e. this code) isn't modifying the iterator (unless we call the next call), it must mean that the returned ArrayList is not a fresh copy, but a reference that gets modified by someone else while we're iterating on it.

I tried (briefly) to find the source code for BluetoothGatt but could only manage to find a source that was incorrect (based on the file length and the reported line number on the stack trace in #1229).

If figuring that out is out of scope for this fix (which is completely understandable), I would rather just take a complete copy of the returned array (instead of trying to be fancy with CopyOnWriteArrayList).

Copy link
Contributor Author

@lucaswitch lucaswitch Sep 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would really be interested in the actual reason why the ConcurrentModificationException is thrown. Since we (i.e. this code) isn't modifying the iterator (unless we call the next call), it must mean that the returned ArrayList is not a fresh copy, but a reference that gets modified by someone else while we're iterating on it.

I tried (briefly) to find the source code for BluetoothGatt but could only manage to find a source that was incorrect (based on the file length and the reported line number on the stack trace in #1229).

If figuring that out is out of scope for this fix (which is completely understandable), I would rather just take a complete copy of the returned array (instead of trying to be fancy with CopyOnWriteArrayList).

My guess is:

1) Somehow the number of services and characteristics can change during runtime and alongside of asWritableMap is being called.(hard to know probably not)

2) The order of callbacks on js bridge can make this happen. Something like discoverServices and getConnected/getDisconnected(or some other callbacks that use peripherals) being called at the same time.

So this quickfix makes the method concurrent proof.
Still i'll try to reproduce that on my Android 14 when i have spare time with the available api to trying reproducing it.

About the implementation: i agree, do you wanna make that change or i can just abort this pull request and create another one with straight copy of services and characteristics list?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have the bandwidth to work on this (nor do I have any permissions to merge anything).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants