Repository navigation
Make sure _handleAppFrame is only registered once per frame - #30346
Conversation
|
cc @xster |
| @@ -557,7 +562,7 @@ class MultiFrameImageStreamCompleter extends ImageStreamCompleter { | |||
| } | |||
| final Duration delay = _frameDuration - (timestamp - _shownTimestamp); | |||
| _timer = Timer(delay * timeDilation, () { | |||
There was a problem hiding this comment.
Would it make sense guarding the timer with this check too, so that you don't even register the timer if it's already been registered?
Could you possibly achieve this same effect by just doing something like _timer ??=?
There was a problem hiding this comment.
I don't see how guarding just against double timer registration fixes the described issue (e.g in the addListener,removeListener,addListener scenario).
I'm not sure I see a scenario where we will have double timer registration with the current guard given that removeListener cancels the timer after removing all listeners.
Can you describe the scenario you're thinking about in which there will be double timer registration?
There was a problem hiding this comment.
I may be misreading something here, but it looks like this timer can get created multiple times without getting cancelled, which could be leading to multiple registration.
There was a problem hiding this comment.
I'm probably missing what you see, can you please describe the sequence of events that leads to multiple timer registration?
There was a problem hiding this comment.
It looks like the constructor of this class calls _handleAppFrame when the codec is ready (
Image widget ends up making a new image stream which ends up creating a timer and then adding a listener which creates a second timer before the first has finished.
There was a problem hiding this comment.
Good catch!
The scenario you describe can actually result in the first frame being skipped(as _nextFrame can be set to the second codec frame before the next flutter frame is executed).
Fixed it by only starting to decode after both the codec is ready and a frame listener is added.
In practice I'd imagine that this was very unlikely to happen as the first frame listener was likely to be added synchronously right after creating the stream completer at which point _codec is still null (as the async call had no chance to complete) thus the second _decodeNextFrameAndSchedule will not be invoked (it's guarded by a check that _codec is not null).
Anyway with this fixed I don't see a scenario where the timer is registered multiple times simultaneously.
goderbauer
left a comment
There was a problem hiding this comment.
LGTM
Thanks for debugging and fixing!
| _framesEmitted = 0, | ||
| _timer = null { | ||
| _timer = null, | ||
| _frameCallbackScheduled = false { |
There was a problem hiding this comment.
nit: It reads a little cleaner to me if you would just initialize the member with false in line 539 instead of doing it here.
bab89ea to
bec0589
Compare
Description
There were 2 possible scenarios in which
_handleAppFrameis added more than once as a frame callback. When this happens it is possible that the second invocation will try to access_nextFrame.imagewhen_nextFrameis null and crash. The 2 scenarios are:Scenario 1
MultiFrameImageStreamCompleter#removeListeneris called followed by ``MultiFrameImageStreamCompleter#addListenerthat is invoking_decodeNextFrameAndSchedule` which is adding `_handleAppFrame` again as a next frame callback.Scenario 2
removeListener and addListener are called multiple times in succession, every call to addListener can result in another registration of
_handleAppFrameto the next Flutter frame callbacks list.This patch fixes the issue by guarding against a second registration of _handleAppFrame.
Related Issues
fixes #30340
Tests
I added the following tests:
Checklist
Before you create this PR confirm that it meets all requirements listed below by checking the relevant checkboxes (
[x]). This will ensure a smooth and quick review process.///).flutter analyze --flutter-repo) does not report any problems on my PR.Breaking Change
Does your PR require Flutter developers to manually update their apps to accommodate your change?