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

Commit 572cbb3

Browse files
committed
[fuchsia] fix race in DefaultSessionConnection
DefaultSessionConnection can run on two threads - the UI and raster threads. This change ensures that all variables they both touch is guarded the mutex.
1 parent f04d941 commit 572cbb3

File tree

2 files changed

+26
-29
lines changed

2 files changed

+26
-29
lines changed

shell/platform/fuchsia/flutter/default_session_connection.cc

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,8 @@ DefaultSessionConnection::DefaultSessionConnection(
178178
on_frame_presented_callback_(std::move(on_frame_presented_callback)),
179179
kMaxFramesInFlight(max_frames_in_flight),
180180
vsync_offset_(vsync_offset) {
181+
FML_CHECK(kMaxFramesInFlight > 0);
182+
181183
next_presentation_info_.set_presentation_time(0);
182184

183185
session_wrapper_.set_error_handler(
@@ -187,14 +189,16 @@ DefaultSessionConnection::DefaultSessionConnection(
187189
// fire every time a set of one or more frames is presented.
188190
session_wrapper_.set_on_frame_presented_handler(
189191
[this](fuchsia::scenic::scheduling::FramePresentedInfo info) {
192+
std::lock_guard<std::mutex> lock(mutex_);
193+
190194
// Update Scenic's limit for our remaining frames in flight allowed.
191195
size_t num_presents_handled = info.presentation_infos.size();
192-
frames_in_flight_allowed_ = info.num_presents_allowed;
193196

194197
// A frame was presented: Update our |frames_in_flight| to match the
195198
// updated unfinalized present requests.
196199
frames_in_flight_ -= num_presents_handled;
197-
TRACE_DURATION("gfx", "OnFramePresented", "frames_in_flight",
200+
201+
TRACE_DURATION("gfx", "OnFramePresented5", "frames_in_flight",
198202
frames_in_flight_, "max_frames_in_flight",
199203
kMaxFramesInFlight, "num_presents_handled",
200204
num_presents_handled);
@@ -203,19 +207,16 @@ DefaultSessionConnection::DefaultSessionConnection(
203207
last_presentation_time_ = fml::TimePoint::FromEpochDelta(
204208
fml::TimeDelta::FromNanoseconds(info.actual_presentation_time));
205209

206-
// Call the client-provided callback once we are done using |info|.
207-
on_frame_presented_callback_(std::move(info));
210+
if (fire_callback_request_pending_) {
211+
FireCallbackMaybe();
212+
}
208213

209214
if (present_session_pending_) {
210215
PresentSession();
211216
}
212217

213-
{
214-
std::lock_guard<std::mutex> lock(mutex_);
215-
if (fire_callback_request_pending_) {
216-
FireCallbackMaybe();
217-
}
218-
}
218+
// Call the client-provided callback once we are done using |info|.
219+
on_frame_presented_callback_(std::move(info));
219220
} // callback
220221
);
221222

@@ -225,10 +226,7 @@ DefaultSessionConnection::DefaultSessionConnection(
225226
session_wrapper_.RequestPresentationTimes(
226227
/*requested_prediction_span=*/0,
227228
[this](fuchsia::scenic::scheduling::FuturePresentationTimes info) {
228-
frames_in_flight_allowed_ = info.remaining_presents_in_flight_allowed;
229-
230-
// If Scenic alloted us 0 frames to begin with, we should fail here.
231-
FML_CHECK(frames_in_flight_allowed_ > 0);
229+
std::lock_guard<std::mutex> lock(mutex_);
232230

233231
next_presentation_info_ =
234232
UpdatePresentationInfo(std::move(info), next_presentation_info_);
@@ -244,12 +242,14 @@ DefaultSessionConnection::DefaultSessionConnection(
244242
DefaultSessionConnection::~DefaultSessionConnection() = default;
245243

246244
void DefaultSessionConnection::Present() {
245+
std::lock_guard<std::mutex> lock(mutex_);
246+
247247
TRACE_DURATION("gfx", "DefaultSessionConnection::Present", "frames_in_flight",
248248
frames_in_flight_, "max_frames_in_flight", kMaxFramesInFlight);
249249

250250
TRACE_FLOW_BEGIN("gfx", "DefaultSessionConnection::PresentSession",
251251
next_present_session_trace_id_);
252-
next_present_session_trace_id_++;
252+
++next_present_session_trace_id_;
253253

254254
present_requested_time_ = fml::TimePoint::Now();
255255

@@ -286,29 +286,21 @@ void DefaultSessionConnection::AwaitVsyncForSecondaryCallback(
286286
fire_callback_(times.frame_start, times.frame_target);
287287
}
288288

289+
// Precondition: |mutex_| is held
289290
void DefaultSessionConnection::PresentSession() {
290291
TRACE_DURATION("gfx", "DefaultSessionConnection::PresentSession");
291292

292-
// If we cannot call Present2() because we have no more Scenic frame budget,
293-
// then we must wait until the OnFramePresented() event fires so we can
294-
// continue our work.
295-
if (frames_in_flight_allowed_ == 0) {
296-
FML_CHECK(!initialized_ || present_session_pending_);
297-
return;
298-
}
299-
300293
present_session_pending_ = false;
301294

302295
while (processed_present_session_trace_id_ < next_present_session_trace_id_) {
303296
TRACE_FLOW_END("gfx", "DefaultSessionConnection::PresentSession",
304297
processed_present_session_trace_id_);
305-
processed_present_session_trace_id_++;
298+
++processed_present_session_trace_id_;
306299
}
307300
TRACE_FLOW_BEGIN("gfx", "Session::Present", next_present_trace_id_);
308-
next_present_trace_id_++;
301+
++next_present_trace_id_;
309302

310303
++frames_in_flight_;
311-
312304
// Flush all session ops. Paint tasks may not yet have executed but those are
313305
// fenced. The compositor can start processing ops while we finalize paint
314306
// tasks.
@@ -329,6 +321,8 @@ void DefaultSessionConnection::PresentSession() {
329321
.ToNanoseconds(),
330322
/*requested_prediction_span=*/presentation_interval.ToNanoseconds() * 10,
331323
[this](fuchsia::scenic::scheduling::FuturePresentationTimes info) {
324+
std::lock_guard<std::mutex> lock(mutex_);
325+
332326
// Clear |future_presentation_infos_| and replace it with the updated
333327
// information.
334328
std::deque<std::pair<fml::TimePoint, fml::TimePoint>>().swap(
@@ -343,15 +337,16 @@ void DefaultSessionConnection::PresentSession() {
343337
presentation_info.presentation_time()))});
344338
}
345339

346-
frames_in_flight_allowed_ = info.remaining_presents_in_flight_allowed;
347340
next_presentation_info_ =
348341
UpdatePresentationInfo(std::move(info), next_presentation_info_);
349342
});
350343
}
351344

345+
// Precondition: |mutex_| is held.
346+
//
352347
// Postcondition: Either a frame is scheduled or fire_callback_request_pending_
353348
// is set to true, meaning we will attempt to schedule a frame on the next
354-
// |OnVsync|.
349+
// |OnFramePresented|.
355350
void DefaultSessionConnection::FireCallbackMaybe() {
356351
TRACE_DURATION("flutter", "FireCallbackMaybe");
357352

@@ -368,6 +363,8 @@ void DefaultSessionConnection::FireCallbackMaybe() {
368363
}
369364
}
370365

366+
// Precondition: |mutex_| is held
367+
//
371368
// A helper function for GetTargetTimes(), since many of the fields it takes
372369
// have to be derived from other state.
373370
FlutterFrameTimes DefaultSessionConnection::GetTargetTimesHelper(
@@ -412,6 +409,7 @@ DefaultSessionConnection::UpdatePresentationInfo(
412409
return new_presentation_info;
413410
}
414411

412+
// Precondition: |mutex_| is held
415413
VsyncInfo DefaultSessionConnection::GetCurrentVsyncInfo() const {
416414
return {fml::TimePoint::FromEpochDelta(fml::TimeDelta::FromNanoseconds(
417415
next_presentation_info_.presentation_time())),

shell/platform/fuchsia/flutter/default_session_connection.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,6 @@ class DefaultSessionConnection final {
128128
const int kMaxFramesInFlight;
129129

130130
int frames_in_flight_ = 0;
131-
int frames_in_flight_allowed_ = 0;
132131
bool present_session_pending_ = false;
133132

134133
// The time from vsync that the Flutter animator should begin its frames. This

0 commit comments

Comments
 (0)