Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Conversation

@cyanglaz
Copy link
Contributor

@cyanglaz cyanglaz commented Nov 3, 2020

Alternatively, we can submit frame directly if threads aren't merged.

Fix flutter/flutter#69449

122f242 need to be cherry-picked before this commit can be cherry-picked. @zanderso
This PR also had conflicts with 0d5f2e9 and I had to rebase. Cherry-picking might be a little tricky

@flutter-dashboard
Copy link

It looks like this pull request may not have tests. Please make sure to add tests before merging. If you need an exemption to this rule, contact Hixie on the #hackers channel in Chat.

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

bool FlutterPlatformViewsController::SubmitFrame(GrDirectContext* gr_context,
std::shared_ptr<IOSContext> ios_context,
std::unique_ptr<SurfaceFrame> frame) {
if (views_to_dispose_.empty() && composition_order_.empty()) {
Copy link

Choose a reason for hiding this comment

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

this won't fix the issue because composition_order_ is mutated by FlutterPlatformViewsController::PrerollCompositeEmbeddedView, PlatformViewLayer::Preroll (raster task queue), which still leaves the flutter_view_ race.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I see, the thread merger check below is probably better.

return raster_status;
}
if (external_view_embedder != nullptr) {
if (external_view_embedder != nullptr && (!raster_thread_merger_ || raster_thread_merger_->IsMerged())) {
Copy link
Member

Choose a reason for hiding this comment

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

Is raster_thread_merge_ thread-safe? raster_thread_merger_->Enable() is called from the platform thread.

Copy link
Member

Choose a reason for hiding this comment

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

Looks like there are checks for raster_thread_merger_ being null on the platform thread while it is created on the raster thread, whilst not being atomic. That looks like a problem itself.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

raster_thread_merge_ is always on raster task runner. raster_thread_merger_->IsMerged() is thread safe.

Copy link
Member

Choose a reason for hiding this comment

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

Copy link

Choose a reason for hiding this comment

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

we still need to address the flutter_view_ race, no?

Copy link
Member

Choose a reason for hiding this comment

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

I think @blasten is right about the race condition. Even with the threads merged we could end up in a SubmitFrame with a null flutter_view_ which the assert says shouldn't' happen. FWIW I ran the code with a null value for flutter_view_ by removing the assert and nothing crashed, so it looks like objc handled the null checks fine. We can just double check that null is handled fine and remove that assert maybe.

Copy link
Member

@gaaclarke gaaclarke left a comment

Choose a reason for hiding this comment

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

I talked to @cyanglaz, I think this is a good fix. I'm going to run a bit of local testing just to make sure. LGTM assuming it passes automated and some manual testing.

@gaaclarke gaaclarke mentioned this pull request Nov 3, 2020
13 tasks
@cyanglaz cyanglaz requested a review from chinmaygarde November 3, 2020 21:45
@cyanglaz cyanglaz changed the title Submit frame directly if no platform views. Do not involve external_view_embedder in submit frame process if threads are not merged. Nov 3, 2020
Comment on lines 474 to 476
// If raster_thread_merger_ is supported by the external_view_embedder,
// we make sure threads are merged before letting external_view_embedder
// to submit frame. Otherwise, fallback to `frame->Submit();`
Copy link
Member

Choose a reason for hiding this comment

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

I don't think the comment adds much to the code.

@gaaclarke
Copy link
Member

I have a 100% repro crash on a branch of the engine. When I rebased that branch onto this one, the crash doesn't happen anymore 👍

@cyanglaz
Copy link
Contributor Author

cyanglaz commented Nov 3, 2020

This is actually failing some tests that are counting number of calls for external_view_embedder->SubmitFrame.
I'm going to update those tests as well

@gaaclarke
Copy link
Member

I tried to force the reproduction of the crash by delaying [FlutterViewController viewDidLayoutSubviews] to match what I was seeing.

diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm
index 7f593583a..59c14ff3d 100644
--- a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm
+++ b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm
@@ -923,6 +923,10 @@ static flutter::PointerData::DeviceKind DeviceKindFromTouchType(UITouch* touch)
 }
 
 - (void)viewDidLayoutSubviews {
+  [self performSelector:@selector(viewDidLayoutSubviewsReal) withObject:nil afterDelay:5.0];
+}
+
+- (void)viewDidLayoutSubviewsReal {
   CGRect viewBounds = self.view.bounds;
   CGFloat scale = [UIScreen mainScreen].scale;

This didn't crash because it appears the UI thread isn't presenting trees to be rendered. It is possible this crash is practically impossible to reproduce given the aggregate system. When looking at the rasterizer / platforms view controller we can see it's technically possible and it happens in my branch but my usage is atypical.

@gaaclarke gaaclarke mentioned this pull request Nov 4, 2020
13 tasks
Copy link

@blasten blasten left a comment

Choose a reason for hiding this comment

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

LGTM. Assuming there's test for flutter_view_ = nullptr case + shell_unittest.cc changes.

@zanderso
Copy link
Member

zanderso commented Nov 5, 2020

Is the failure on the Mac iOS Engine presubmit related?

@zanderso
Copy link
Member

zanderso commented Nov 5, 2020

Fixes flutter/flutter#69449

/*device_pixel_ratio=*/2.0f);
bool result = pipeline->Produce().Complete(std::move(layer_tree));
EXPECT_TRUE(result);
std::function<bool(LayerTree&)> no_discard = [](LayerTree&) { return false; };
Copy link

Choose a reason for hiding this comment

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

nit: this could just be auto no_discard

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

ASSERT_EQ(0, external_view_embedder->GetSubmittedFrameCount());

end_frame_latch.Wait();
ASSERT_EQ(1, external_view_embedder->GetSubmittedFrameCount());
Copy link

Choose a reason for hiding this comment

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

nit: is it possible to assert that threads are merged before this assert? Same where you have the comment // Threads not merged, can that be an assert?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually, we can't assert if threads are not merged here, the threads are merged at the end of the frame. So it is actually merged here.
My comment was misleading, it should say that during the frame, the threads are not merged, they are merged at the end of the frame.
Updated the comment, PTAL

Copy link
Contributor Author

@cyanglaz cyanglaz left a comment

Choose a reason for hiding this comment

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

@gaaclarke @blasten Updated with reviews, PTAL

.WillRepeatedly(Return(&external_view_embedder));

auto surface_frame = std::make_unique<SurfaceFrame>(
nullptr, true, [](const SurfaceFrame&, SkCanvas*) { return true; });
Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

/*device_pixel_ratio=*/2.0f);
bool result = pipeline->Produce().Complete(std::move(layer_tree));
EXPECT_TRUE(result);
std::function<bool(LayerTree&)> no_discard = [](LayerTree&) { return false; };
Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

Comment on lines 232 to 234
EXPECT_CALL(external_view_embedder, BeginFrame).Times(1);
EXPECT_CALL(external_view_embedder, SubmitFrame).Times(1);
EXPECT_CALL(external_view_embedder, EndFrame).Times(1);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

ASSERT_EQ(0, external_view_embedder->GetSubmittedFrameCount());

end_frame_latch.Wait();
ASSERT_EQ(1, external_view_embedder->GetSubmittedFrameCount());
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

ASSERT_EQ(0, external_view_embedder->GetSubmittedFrameCount());

end_frame_latch.Wait();
ASSERT_EQ(1, external_view_embedder->GetSubmittedFrameCount());
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually, we can't assert if threads are not merged here, the threads are merged at the end of the frame. So it is actually merged here.
My comment was misleading, it should say that during the frame, the threads are not merged, they are merged at the end of the frame.
Updated the comment, PTAL

flutterPlatformViewsController->Reset();
}

- (void)testFlutterPlatformViewControllerSubmitFrameWithoutFlutterViewNotCrashing {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done!

@cyanglaz cyanglaz requested review from blasten and gaaclarke November 6, 2020 17:31
external_view_embedder->UpdatePostPrerollResult(
PostPrerollResult::kSuccess);
if (!raster_thread_merger_ref) {
raster_thread_merger_ref = raster_thread_merger;
Copy link

Choose a reason for hiding this comment

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

For future improvements: this would be much easier if we were to create, and supply the thread merger in the test. Right now, this dependency is hardcoded in the rasterizer, which creates patterns like this.

Copy link

@blasten blasten left a comment

Choose a reason for hiding this comment

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

LGTM

@cyanglaz cyanglaz added the waiting for tree to go green This PR is approved and tested, but waiting for the tree to be green to land. label Nov 6, 2020
@fluttergithubbot fluttergithubbot merged commit 016fbde into flutter:master Nov 6, 2020
@cyanglaz cyanglaz deleted the escape branch November 6, 2020 19:07
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Nov 6, 2020
cbracken added a commit that referenced this pull request Nov 6, 2020
)" (#22367)

This reverts commit 0d5f2e9.

Due to merge conflicts, this also reverts #22275:

Revert "Do not involve external_view_embedder in submit frame process if threads are not merged. (#22275)"

This reverts commit 016fbde.
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Nov 6, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Nov 7, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Nov 7, 2020
fluttergithubbot pushed a commit that referenced this pull request Nov 7, 2020
christopherfujino added a commit that referenced this pull request Nov 12, 2020
* Update 1.22 engine to use Dart 2.10.4
* [iOS TextInput] Avoid Unnecessary UndateEditingClient Calls (#21303)
* added unit tests to the rasterizer (#22282)
* Reland "Do not involve external_view_embedder in submit frame process if threads are not merged. #22275" (#22372)

Co-authored-by: LongCatIsLooong <[email protected]>
Co-authored-by: gaaclarke <[email protected]>
Co-authored-by: Chris Yang <[email protected]>
chaselatta pushed a commit to chaselatta/engine that referenced this pull request Nov 30, 2020
chaselatta pushed a commit to chaselatta/engine that referenced this pull request Nov 30, 2020
…tter#22348)" (flutter#22367)

This reverts commit 0d5f2e9.

Due to merge conflicts, this also reverts flutter#22275:

Revert "Do not involve external_view_embedder in submit frame process if threads are not merged. (flutter#22275)"

This reverts commit 016fbde.
chaselatta pushed a commit to chaselatta/engine that referenced this pull request Nov 30, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

cla: yes platform-ios waiting for tree to go green This PR is approved and tested, but waiting for the tree to be green to land.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

platform views on by default introduced a race condition

5 participants