Paltform: Android
Version: 5.0
If you open Touch gestures feature on your device, when three fingers on the screen at the same time, crash.
There is crash stack:

I test this on react-native showcase Movie Trailers by MovieLaLa Android, crash still exist.
@satya164
Hey Richard-Cao, thanks for reporting this issue!
React Native, as you've probably heard, is getting really popular and truth is we're getting a bit overwhelmed by the activity surrounding it. There are just too many issues for us to manage properly.
react-native or for more real time interactions, ask on Discord in the #react-native channel.Sorry. I've no context on this. What do you mean by the touch gestures feature? How to enable it?
@satya164 Some Android devices like XiaoMi, Huawei, Nubia and so on, have touch gestures feature.
If you open it, you can restore this crash.
I just got this on iOS as well. It seems to happen when I try to scroll my ListView quickly after it mounts...
Also got this on iOS when randomly tapping around on an app. Can't reproduce reliably ... so, sorry for there not being any more context. I don't think it was in the context of a ListView.
Found where this is happening: react/lib/ResponderTouchHistoryStore.js in the method recordMoveTouchData.
On a cold boot of my app, if the first touch on the screen is a scroll on a ListView/ScrollView, there appears to be a race condition and recordMoveTouchData is called before recordStartTouchData, therefore touchHistory.touchBank is not properly initialized.
Upon the first call,
var touchTrack = touchBank[touch.identifier];
touchTrack is undefined, causing the crash. Inserting:
if (touchTrack) {
reinitializeTouchTrack(touchTrack, touch);
} else {
touchBank[touch.identifier] = initializeTouchData(touch);
}
(like it exists in recordStartTouchData) resolves the problem. However, I doubt this is the correct solution. Again, I believe it's a race condition with the recordStartTouchData.
Opened an issue on react core here https://github.com/facebook/react/issues/6277
Ok, they bounced it back over here. Anyone familiar enough with PanResponder to look further into this?
@majak I know you recently refactored how touches work (by passing them through the event dispatcher)...would you have any clue on this issue?
TLDR; we're getting touchesMoved before a touchesStart is ever sent.
(cc @nicklockwood)
Yep, you can see here iOS gets touchesBegan, then a series of touchesMoved, yet the first event to land in JS is a topTouchMove
This is on React Native 0.20
2016-03-17 10:31:17.463 DiscoveryVR - Dev[3700:1038410] touchesBegan event = <UITouchesEvent: 0x147ef85c0> timestamp: 164352 touches: {(
<UITouch: 0x147fdc900> phase: Began tap count: 1 window: <UIWindow: 0x149037540; frame = (0 0; 375 667); autoresize = W+H; gestureRecognizers = <NSArray: 0x149060430>; layer = <UIWindowLayer: 0x14903df70>> view: <RCTView: 0x14932baf0; reactTag: 189; frame = (0 0; 341 153); alpha = 0.4; layer = <CALayer: 0x149321ad0>> location in window: {219, 587.5} previous location in window: {219, 587.5} location in view: {203, 29.5} previous location in view: {203, 29.5}
)}
2016-03-17 10:31:17.476 DiscoveryVR - Dev[3700:1038410] touchesMoved event = <UITouchesEvent: 0x147ef85c0> timestamp: 164352 touches: {(
<UITouch: 0x147fdc900> phase: Moved tap count: 1 window: <UIWindow: 0x149037540; frame = (0 0; 375 667); autoresize = W+H; gestureRecognizers = <NSArray: 0x149060430>; layer = <UIWindowLayer: 0x14903df70>> view: <RCTView: 0x14932baf0; reactTag: 189; frame = (0 0; 341 153); alpha = 0.4; layer = <CALayer: 0x149321ad0>> location in window: {219, 540.5} previous location in window: {219, 587.5} location in view: {203, -17.5} previous location in view: {203, 29.5}
)}
2016-03-17 10:31:17.492 DiscoveryVR - Dev[3700:1038410] touchesMoved event = <UITouchesEvent: 0x147ef85c0> timestamp: 164352 touches: {(
<UITouch: 0x147fdc900> phase: Moved tap count: 1 window: <UIWindow: 0x149037540; frame = (0 0; 375 667); autoresize = W+H; gestureRecognizers = <NSArray: 0x149060430>; layer = <UIWindowLayer: 0x14903df70>> view: (null) location in window: {219, 471} previous location in window: {219, 540.5} location in view: {219, 471} previous location in view: {219, 540.5}
)}
2016-03-17 10:31:17.511 DiscoveryVR - Dev[3700:1038410] touchesMoved event = <UITouchesEvent: 0x147ef85c0> timestamp: 164352 touches: {(
<UITouch: 0x147fdc900> phase: Moved tap count: 1 window: <UIWindow: 0x149037540; frame = (0 0; 375 667); autoresize = W+H; gestureRecognizers = <NSArray: 0x149060430>; layer = <UIWindowLayer: 0x14903df70>> view: (null) location in window: {219, 357.5} previous location in window: {219, 471} location in view: {219, 357.5} previous location in view: {219, 471}
)}
2016-03-17 10:31:17.526 DiscoveryVR - Dev[3700:1038410] touchesMoved event = <UITouchesEvent: 0x147ef85c0> timestamp: 164352 touches: {(
<UITouch: 0x147fdc900> phase: Moved tap count: 1 window: <UIWindow: 0x149037540; frame = (0 0; 375 667); autoresize = W+H; gestureRecognizers = <NSArray: 0x149060430>; layer = <UIWindowLayer: 0x14903df70>> view: (null) location in window: {227.5, 230} previous location in window: {219, 357.5} location in view: {227.5, 230} previous location in view: {219, 357.5}
)}
2016-03-17 10:31:17.539 [info][tid:com.facebook.React.JavaScript] 'eventTopLevelType = ', 'topTouchMove'
2016-03-17 10:31:17.544 DiscoveryVR - Dev[3700:1038410] touchesMoved event = <UITouchesEvent: 0x147ef85c0> timestamp: 164352 touches: {(
<UITouch: 0x147fdc900> phase: Moved tap count: 1 window: <UIWindow: 0x149037540; frame = (0 0; 375 667); autoresize = W+H; gestureRecognizers = <NSArray: 0x149060430>; layer = <UIWindowLayer: 0x14903df70>> view: (null) location in window: {253, 95.5} previous location in window: {227.5, 230} location in view: {253, 95.5} previous location in view: {227.5, 230}
)}
2016-03-17 10:31:17.546 [info][tid:com.facebook.React.JavaScript] 'touches = ', [ { target: 189,
pageY: 540.5,
locationX: 203,
locationY: -17.5,
identifier: 1,
pageX: 219,
timestamp: 164351752.6978334 } ]
2016-03-17 10:31:17.547 [info][tid:com.facebook.React.JavaScript] 'changedIndices = ', [ 0 ]
2016-03-17 10:31:17.548 [info][tid:com.facebook.React.JavaScript] ====================================
2016-03-17 10:31:17.550 [error][tid:com.facebook.React.JavaScript] Touch data should have been recorded on start
I've changed how touches are handled only on iOS side. If this issue is common for both iOS and Android I would expect something is wrong on js side.
@marcshilling can you repro this with a simple app containing just scrollview?
@Richard-Cao could you link to a page on this device specific touch gestures feature on Android?
@majak I'll try to throw something together. The tricky thing is it's not reproducible 100% of the time (definitely a race condition). But anyway, yeah let me see if I can get something up and running.
@majak Marc and I did a bit more research on this:
2016-03-17 12:22:28.850 DiscoveryVR - Dev[44643:4871099] OUTSIDE BLOCK: Module RCTEventEmitter, Method receiveTouches, Args (
topTouchStart,
(
{
identifier = 1;
locationX = 226;
locationY = "36.5";
pageX = 242;
pageY = "594.5";
target = 189;
timestamp = "65236062.87420401";
}
),
(
0
)
)
2016-03-17 12:22:28.873 DiscoveryVR - Dev[44643:4871447] OUTSIDE BLOCK: Module RCTEventEmitter, Method receiveTouches, Args (
topTouchMove,
(
{
identifier = 1;
locationX = 226;
locationY = "34.5";
pageX = 242;
pageY = "592.5";
target = 189;
timestamp = "65236079.616078";
}
),
(
0
)
)
2016-03-17 12:22:28.873 DiscoveryVR - Dev[44643:4871447] INSIDE BLOCK: Module RCTEventEmitter, Method receiveTouches, Args (
topTouchMove,
(
{
identifier = 1;
locationX = 226;
locationY = "34.5";
pageX = 242;
pageY = "592.5";
target = 189;
timestamp = "65236079.616078";
}
),
(
0
)
)
2016-03-17 12:22:28.874 [error][tid:com.facebook.React.JavaScript] Touch data should have been recorded on start
2016-03-17 12:22:28.879 [fatal][tid:com.facebook.React.RCTExceptionsManagerQueue] Unhandled JS Exception: Touch data should have been recorded on start
2016-03-17 12:22:28.879 DiscoveryVR - Dev[44643:4871447] INSIDE BLOCK: Module RCTEventEmitter, Method receiveTouches, Args (
topTouchStart,
(
{
identifier = 1;
locationX = 226;
locationY = "36.5";
pageX = 242;
pageY = "594.5";
target = 189;
timestamp = "65236062.87420401";
}
),
(
0
)
)
Here, we're logging calls to the bridge with the method "receiveTouches", referring to the method that receives touches in ReactNativeEventEmitter. In the log above, you notice we're logging "OUTSIDE BLOCK" and "INSIDE BLOCK" -- these logs are referring to:
OUTSIDE BLOCK: https://github.com/facebook/react-native/blob/master/React/Base/RCTBatchedBridge.m#L696
INSIDE BLOCK: https://github.com/facebook/react-native/blob/master/React/Base/RCTBatchedBridge.m#L705
As you can see in the log, the "OUTSIDE_BLOCK" stuff is executing in the proper order -- a topTouchStart followed by a topTouchMove.
INSIDE_BLOCK, however, is executing in the wrong order. You can see the topTouchStart event doesn't ACTUALLY get executed on the bridge until after the the topTouchMove.
This seems weird, but I think I may have a fundamental misunderstanding of how the JSC executor works. I was under the impression that while timing of a given JS call couldn't be guaranteed (due to the async nature of the bridge), the order could be, because as the method name implies, updates are "enqueued".
Obviously this could be fixed in JS by queuing up move calls until a touchStart is received, and we can enforce the order there. Perhaps the right fix, and presumably that would then be fixed on both platforms.
I'm curious though if anyone can explain the executor here though, and why order can't be guaranteed.
CCing @javache here as well.
Great data! I've chatted with @tadeuzagallo and we figured out there is indeed a race condition in how touches are processed.
For (perf) reasons, topTouchStart is immediately dispatched on js thread, while topTouchMove waits for js to collect it in at the beggining of a frame. This can lead into a situation in which they arrive to js in a wrong order, something like this:

I'll fix it. Thanks for digging into this, @skevy & @marcshilling!
This also makes me think this github issue actually contains two different bugs that surface with the same redbox.
This is a great explanation, and makes a lot of sense conceptually. I'm not sure I'm clear where exactly in the code this is happening...but I'll wait for the diff!
Thanks so much @majak and @tadeuzagallo.
@majak

Seeing similar crash reports in the wild on iOS as well. Thanks for looking into it!
Changes that should fix this issue were just pushed on master. Commits from 8f07b01ac81ca5962a48ed996d616a065622fb24 to 31bb85a210e8a6edba4f59df6eb36ccc5cc58d9e. The important one with deeper explanation is 1d3db4c5dc8763d16f2d051fdf04a2976c0fb154.
Since I didn't repro this issue locally I cannot guarantee it will fix it for real. Therefore it would be great if you could patch it locally and see whether it really helps.
But also turn off chrome debugging please. Looks like this stack breaks it 馃槄. I'm looking into that too.
Version 0.24.0-rc1 should already contain the fix and all necessary fixes for the fix.
To be clear, we believe the issue on iOS has been fixed. Those commits don't affect Android.
Does anyone know whether this is still an issue on Android? It seems like we at least half fixed this type of problem, but since it has been a while it does not seem clear to me whether there is still a problem on Android here..
FWIW, I just saw this in Production on Android v6.0.1 with React Native v0.25.1 (which was tagged on May 4th).
This is still reproducible on Android, RN v0.30
Fixed before v0.39.
Hi there! This issue is being closed because it has been inactive for a while. Maybe the issue has been fixed in a recent release, or perhaps it is not affecting a lot of people. Either way, we're automatically closing issues after a period of inactivity. Please do not take it personally!
If you think this issue should definitely remain open, please let us know. The following information is helpful when it comes to determining if the issue should be re-opened:
If you would like to work on a patch to fix the issue, contributions are very welcome! Read through the contribution guide, and feel free to hop into #react-native if you need help planning your contribution.
Most helpful comment
Great data! I've chatted with @tadeuzagallo and we figured out there is indeed a race condition in how touches are processed.
For (perf) reasons,
topTouchStartis immediately dispatched on js thread, whiletopTouchMovewaits for js to collect it in at the beggining of a frame. This can lead into a situation in which they arrive to js in a wrong order, something like this:I'll fix it. Thanks for digging into this, @skevy & @marcshilling!
This also makes me think this github issue actually contains two different bugs that surface with the same redbox.