Skip to content

Commit 269e286

Browse files
authored
fix(FrameDispatch): All operations on Rendering event should catch exceptions (microsoft#756)
Previously, failures on the CompositionTarget.Rendering event could crash the app. With these changes, each frame callback has an exception handling wrapper. Fixes microsoft#750
1 parent 8aaa0b1 commit 269e286

File tree

4 files changed

+76
-28
lines changed

4 files changed

+76
-28
lines changed

ReactWindows/ReactNative/Animated/NativeAnimatedModule.cs

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -101,30 +101,37 @@ public override void Initialize()
101101
var nodesManager = new NativeAnimatedNodesManager(uiImpl);
102102
_animatedFrameCallback = (sender, args) =>
103103
{
104-
var renderingArgs = args as RenderingEventArgs;
105-
if (renderingArgs == null)
104+
try
106105
{
107-
return;
108-
}
106+
var renderingArgs = args as RenderingEventArgs;
107+
if (renderingArgs == null)
108+
{
109+
return;
110+
}
109111

110-
var operations = default(List<Action<NativeAnimatedNodesManager>>);
111-
lock (_operationsGate)
112-
{
113-
operations = _readyOperations;
114-
_readyOperations = null;
115-
}
112+
var operations = default(List<Action<NativeAnimatedNodesManager>>);
113+
lock (_operationsGate)
114+
{
115+
operations = _readyOperations;
116+
_readyOperations = null;
117+
}
116118

117-
if (operations != null)
118-
{
119-
foreach (var operation in operations)
119+
if (operations != null)
120120
{
121-
operation(nodesManager);
121+
foreach (var operation in operations)
122+
{
123+
operation(nodesManager);
124+
}
122125
}
123-
}
124126

125-
if (nodesManager.HasActiveAnimations)
127+
if (nodesManager.HasActiveAnimations)
128+
{
129+
nodesManager.RunUpdates(renderingArgs.RenderingTime);
130+
}
131+
}
132+
catch (Exception ex)
126133
{
127-
nodesManager.RunUpdates(renderingArgs.RenderingTime);
134+
Context.HandleException(ex);
128135
}
129136
};
130137

ReactWindows/ReactNative/Modules/Core/Timing.cs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public void OnSuspend()
6060
_suspended = true;
6161
if (_renderingHandled)
6262
{
63-
CompositionTarget.Rendering -= DoFrame;
63+
CompositionTarget.Rendering -= DoFrameSafe;
6464
_renderingHandled = false;
6565
}
6666
}
@@ -73,7 +73,7 @@ public void OnResume()
7373
_suspended = false;
7474
if (!_renderingHandled)
7575
{
76-
CompositionTarget.Rendering += DoFrame;
76+
CompositionTarget.Rendering += DoFrameSafe;
7777
_renderingHandled = true;
7878
}
7979
}
@@ -85,7 +85,7 @@ public void OnDestroy()
8585
{
8686
if (_renderingHandled)
8787
{
88-
CompositionTarget.Rendering -= DoFrame;
88+
CompositionTarget.Rendering -= DoFrameSafe;
8989
_renderingHandled = false;
9090
}
9191
}
@@ -138,6 +138,18 @@ public void deleteTimer(int timerId)
138138
}
139139
}
140140

141+
private void DoFrameSafe(object sender, object e)
142+
{
143+
try
144+
{
145+
DoFrame(sender, e);
146+
}
147+
catch (Exception ex)
148+
{
149+
Context.HandleException(ex);
150+
}
151+
}
152+
141153
private void DoFrame(object sender, object e)
142154
{
143155
if (Volatile.Read(ref _suspended))

ReactWindows/ReactNative/UIManager/Events/EventDispatcher.cs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ public void OnResume()
129129
_rctEventEmitter = _reactContext.GetJavaScriptModule<RCTEventEmitter>();
130130
}
131131

132-
CompositionTarget.Rendering += ScheduleDispatch;
132+
CompositionTarget.Rendering += ScheduleDispatcherSafe;
133133
}
134134

135135
/// <summary>
@@ -159,7 +159,7 @@ public void OnReactInstanceDispose()
159159
private void ClearCallback()
160160
{
161161
DispatcherHelpers.AssertOnDispatcher();
162-
CompositionTarget.Rendering -= ScheduleDispatch;
162+
CompositionTarget.Rendering -= ScheduleDispatcherSafe;
163163
}
164164

165165
private void MoveStagedEventsToDispatchQueue()
@@ -243,6 +243,18 @@ private long GetEventCookie(int viewTag, short eventTypeId, short coalescingKey)
243243
(((long)coalescingKey) & 0xffff) << 48;
244244
}
245245

246+
private void ScheduleDispatcherSafe(object sender, object e)
247+
{
248+
try
249+
{
250+
ScheduleDispatch(sender, e);
251+
}
252+
catch (Exception ex)
253+
{
254+
_reactContext.HandleException(ex);
255+
}
256+
}
257+
246258
private void ScheduleDispatch(object sender, object e)
247259
{
248260
DispatcherHelpers.AssertOnDispatcher();

ReactWindows/ReactNative/UIManager/UIViewOperationQueue.cs

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -371,15 +371,15 @@ public void EnqueueFindTargetForTouch(
371371
/// </summary>
372372
public void OnSuspend()
373373
{
374-
CompositionTarget.Rendering -= OnRendering;
374+
CompositionTarget.Rendering -= OnRenderingSafe;
375375
}
376376

377377
/// <summary>
378378
/// Called when the host receives the resume event.
379379
/// </summary>
380380
public void OnResume()
381381
{
382-
CompositionTarget.Rendering += OnRendering;
382+
CompositionTarget.Rendering += OnRenderingSafe;
383383
}
384384

385385
/// <summary>
@@ -453,6 +453,18 @@ private void EnqueueOperation(Action action)
453453
}
454454
}
455455

456+
private void OnRenderingSafe(object sender, object e)
457+
{
458+
try
459+
{
460+
OnRendering(sender, e);
461+
}
462+
catch (Exception ex)
463+
{
464+
_reactContext.HandleException(ex);
465+
}
466+
}
467+
456468
private void OnRendering(object sender, object e)
457469
{
458470
var renderingArgs = e as RenderingEventArgs;
@@ -466,12 +478,17 @@ private void OnRendering(object sender, object e)
466478

467479
lock (_gate)
468480
{
469-
foreach (var batch in _batches)
481+
try
482+
{
483+
foreach (var batch in _batches)
484+
{
485+
batch();
486+
}
487+
}
488+
finally
470489
{
471-
batch();
490+
_batches.Clear();
472491
}
473-
474-
_batches.Clear();
475492
}
476493
}
477494

0 commit comments

Comments
 (0)