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

Commit 4ee84df

Browse files
committed
fuchsia: Handle multiple views in platformViews path
1 parent 159071d commit 4ee84df

14 files changed

+481
-186
lines changed

flow/layers/fuchsia_layer_unittests.cc

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@
2020
#include "flutter/flow/layers/physical_shape_layer.h"
2121
#include "flutter/flow/layers/transform_layer.h"
2222
#include "flutter/flow/view_holder.h"
23-
#include "flutter/fml/platform/fuchsia/message_loop_fuchsia.h"
24-
#include "flutter/fml/task_runner.h"
2523
#include "gtest/gtest.h"
2624

2725
namespace flutter {
@@ -251,10 +249,6 @@ class MockSessionWrapper : public flutter::SessionWrapper {
251249
};
252250

253251
struct TestContext {
254-
// Message loop.
255-
fml::RefPtr<fml::MessageLoopFuchsia> loop;
256-
fml::RefPtr<fml::TaskRunner> task_runner;
257-
258252
// Session.
259253
fidl::InterfaceRequest<fuchsia::ui::scenic::SessionListener> listener_request;
260254
MockSession mock_session;
@@ -273,10 +267,6 @@ struct TestContext {
273267
std::unique_ptr<TestContext> InitTest() {
274268
std::unique_ptr<TestContext> context = std::make_unique<TestContext>();
275269

276-
// Init message loop.
277-
context->loop = fml::MakeRefCounted<fml::MessageLoopFuchsia>();
278-
context->task_runner = fml::MakeRefCounted<fml::TaskRunner>(context->loop);
279-
280270
// Init Session.
281271
fuchsia::ui::scenic::SessionPtr session_ptr;
282272
fuchsia::ui::scenic::SessionListenerPtr listener;
@@ -318,7 +308,7 @@ zx_koid_t GetChildLayerId() {
318308
class AutoDestroyChildLayerId {
319309
public:
320310
AutoDestroyChildLayerId(zx_koid_t id) : id_(id) {}
321-
~AutoDestroyChildLayerId() { ViewHolder::Destroy(id_); }
311+
~AutoDestroyChildLayerId() { ViewHolder::Destroy(id_, nullptr); }
322312

323313
private:
324314
zx_koid_t id_;
@@ -360,9 +350,10 @@ TEST_F(FuchsiaLayerTest, DISABLED_PhysicalShapeLayersAndChildSceneLayers) {
360350
const zx_koid_t kChildLayerId1 = GetChildLayerId();
361351
auto [unused_view_token1, unused_view_holder_token1] =
362352
scenic::ViewTokenPair::New();
363-
ViewHolder::Create(kChildLayerId1, test_context->task_runner,
364-
std::move(unused_view_holder_token1),
365-
/*bind_callback=*/[](scenic::ResourceId id) {});
353+
ViewHolder::Create(
354+
kChildLayerId1,
355+
/*bind_callback=*/[](scenic::ResourceId id) {},
356+
std::move(unused_view_holder_token1));
366357
// Will destroy only when we go out of scope (i.e. end of the test).
367358
AutoDestroyChildLayerId auto_destroy1(kChildLayerId1);
368359
auto child_view1 = std::make_shared<ChildSceneLayer>(
@@ -388,9 +379,10 @@ TEST_F(FuchsiaLayerTest, DISABLED_PhysicalShapeLayersAndChildSceneLayers) {
388379
const zx_koid_t kChildLayerId2 = GetChildLayerId();
389380
auto [unused_view_token2, unused_view_holder_token2] =
390381
scenic::ViewTokenPair::New();
391-
ViewHolder::Create(kChildLayerId2, test_context->task_runner,
392-
std::move(unused_view_holder_token2),
393-
/*bind_callback=*/[](scenic::ResourceId id) {});
382+
ViewHolder::Create(
383+
kChildLayerId2,
384+
/*bind_callback=*/[](scenic::ResourceId id) {},
385+
std::move(unused_view_holder_token2));
394386
// Will destroy only when we go out of scope (i.e. end of the test).
395387
AutoDestroyChildLayerId auto_destroy2(kChildLayerId2);
396388
auto child_view2 = std::make_shared<ChildSceneLayer>(
@@ -604,9 +596,10 @@ TEST_F(FuchsiaLayerTest, DISABLED_OpacityAndTransformLayer) {
604596
auto [unused_view_token1, unused_view_holder_token1] =
605597
scenic::ViewTokenPair::New();
606598

607-
ViewHolder::Create(kChildLayerId1, test_context->task_runner,
608-
std::move(unused_view_holder_token1),
609-
/*bind_callback=*/[](scenic::ResourceId id) {});
599+
ViewHolder::Create(
600+
kChildLayerId1,
601+
/*bind_callback=*/[](scenic::ResourceId id) {},
602+
std::move(unused_view_holder_token1));
610603
// Will destroy only when we go out of scope (i.e. end of the test).
611604
AutoDestroyChildLayerId auto_destroy1(kChildLayerId1);
612605
auto child_view1 = std::make_shared<ChildSceneLayer>(

flow/scene_update_context.cc

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -223,13 +223,13 @@ void SceneUpdateContext::UpdateView(int64_t view_id,
223223
}
224224

225225
void SceneUpdateContext::CreateView(int64_t view_id,
226+
ViewHolder::ViewIdCallback on_view_created,
226227
bool hit_testable,
227228
bool focusable) {
228229
FML_LOG(INFO) << "CreateView for view holder: " << view_id;
229230
zx_handle_t handle = (zx_handle_t)view_id;
230-
flutter::ViewHolder::Create(handle, nullptr,
231-
scenic::ToViewHolderToken(zx::eventpair(handle)),
232-
nullptr);
231+
flutter::ViewHolder::Create(handle, std::move(on_view_created),
232+
scenic::ToViewHolderToken(zx::eventpair(handle)));
233233
auto* view_holder = ViewHolder::FromId(view_id);
234234
FML_DCHECK(view_holder);
235235

@@ -250,8 +250,10 @@ void SceneUpdateContext::UpdateView(int64_t view_id,
250250
view_holder->set_focusable(focusable);
251251
}
252252

253-
void SceneUpdateContext::DestroyView(int64_t view_id) {
254-
ViewHolder::Destroy(view_id);
253+
void SceneUpdateContext::DestroyView(
254+
int64_t view_id,
255+
ViewHolder::ViewIdCallback on_view_destroyed) {
256+
ViewHolder::Destroy(view_id, std::move(on_view_destroyed));
255257
}
256258

257259
SceneUpdateContext::Entity::Entity(std::shared_ptr<SceneUpdateContext> context)

flow/scene_update_context.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <vector>
1717

1818
#include "flutter/flow/embedded_views.h"
19+
#include "flutter/flow/view_holder.h"
1920
#include "flutter/fml/logging.h"
2021
#include "flutter/fml/macros.h"
2122
#include "third_party/skia/include/core/SkRect.h"
@@ -167,9 +168,14 @@ class SceneUpdateContext : public flutter::ExternalViewEmbedder {
167168
return nullptr;
168169
}
169170

170-
void CreateView(int64_t view_id, bool hit_testable, bool focusable);
171+
// View manipulation.
172+
void CreateView(int64_t view_id,
173+
ViewHolder::ViewIdCallback on_view_created,
174+
bool hit_testable,
175+
bool focusable);
176+
void DestroyView(int64_t view_id,
177+
ViewHolder::ViewIdCallback on_view_destroyed);
171178
void UpdateView(int64_t view_id, bool hit_testable, bool focusable);
172-
void DestroyView(int64_t view_id);
173179
void UpdateView(int64_t view_id,
174180
const SkPoint& offset,
175181
const SkSize& size,

flow/view_holder.cc

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,8 @@ fuchsia::ui::gfx::ViewProperties ToViewProperties(float width,
5151
namespace flutter {
5252

5353
void ViewHolder::Create(zx_koid_t id,
54-
fml::RefPtr<fml::TaskRunner> ui_task_runner,
55-
fuchsia::ui::views::ViewHolderToken view_holder_token,
56-
const BindCallback& on_bind_callback) {
54+
ViewIdCallback on_view_created,
55+
fuchsia::ui::views::ViewHolderToken view_holder_token) {
5756
// This raster thread contains at least 1 ViewHolder. Initialize the
5857
// per-thread bindings.
5958
if (tls_view_holder_bindings.get() == nullptr) {
@@ -64,16 +63,20 @@ void ViewHolder::Create(zx_koid_t id,
6463
FML_DCHECK(bindings);
6564
FML_DCHECK(bindings->find(id) == bindings->end());
6665

67-
auto view_holder = std::make_unique<ViewHolder>(std::move(ui_task_runner),
68-
std::move(view_holder_token),
69-
on_bind_callback);
66+
auto view_holder = std::unique_ptr<ViewHolder>(
67+
new ViewHolder(std::move(view_holder_token), std::move(on_view_created)));
7068
bindings->emplace(id, std::move(view_holder));
7169
}
7270

73-
void ViewHolder::Destroy(zx_koid_t id) {
71+
void ViewHolder::Destroy(zx_koid_t id, ViewIdCallback on_view_destroyed) {
7472
auto* bindings = tls_view_holder_bindings.get();
7573
FML_DCHECK(bindings);
74+
auto binding = bindings->find(id);
75+
FML_DCHECK(binding != bindings->end());
7676

77+
if (binding->second->view_holder_) {
78+
on_view_destroyed(binding->second->view_holder_->id());
79+
}
7780
bindings->erase(id);
7881
}
7982

@@ -91,12 +94,10 @@ ViewHolder* ViewHolder::FromId(zx_koid_t id) {
9194
return binding->second.get();
9295
}
9396

94-
ViewHolder::ViewHolder(fml::RefPtr<fml::TaskRunner> ui_task_runner,
95-
fuchsia::ui::views::ViewHolderToken view_holder_token,
96-
const BindCallback& on_bind_callback)
97-
: ui_task_runner_(std::move(ui_task_runner)),
98-
pending_view_holder_token_(std::move(view_holder_token)),
99-
pending_bind_callback_(on_bind_callback) {
97+
ViewHolder::ViewHolder(fuchsia::ui::views::ViewHolderToken view_holder_token,
98+
ViewIdCallback on_view_created)
99+
: pending_view_holder_token_(std::move(view_holder_token)),
100+
on_view_created_(std::move(on_view_created)) {
100101
FML_DCHECK(pending_view_holder_token_.value);
101102
}
102103

@@ -114,12 +115,13 @@ void ViewHolder::UpdateScene(scenic::Session* session,
114115
opacity_node_->AddChild(*entity_node_);
115116
opacity_node_->SetLabel("flutter::ViewHolder");
116117
entity_node_->Attach(*view_holder_);
117-
if (ui_task_runner_ && pending_view_holder_token_.value) {
118-
ui_task_runner_->PostTask(
119-
[bind_callback = std::move(pending_bind_callback_),
120-
view_holder_id = view_holder_->id()]() {
121-
bind_callback(view_holder_id);
122-
});
118+
119+
// Inform the rest of Flutter about the view being created.
120+
// As long as we do this before calling `Present` on the session,
121+
// View-related messages sent to the UI thread will never be processed
122+
// before this internal message is delivered to the UI thread.
123+
if (on_view_created_) {
124+
on_view_created_(view_holder_->id());
123125
}
124126
}
125127
FML_DCHECK(entity_node_);

flow/view_holder.h

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,20 @@ namespace flutter {
2929
// This object is created and destroyed on the |Rasterizer|'s thread.
3030
class ViewHolder {
3131
public:
32-
using BindCallback = std::function<void(scenic::ResourceId)>;
33-
32+
using ViewIdCallback = std::function<void(scenic::ResourceId)>;
33+
34+
// `Create`, `Destroy`, and `FromId` must be executed on the raster thread or
35+
// errors will occur.
36+
//
37+
// `on_bind_callback` and `on_unbind_callback` will likewise execute on the
38+
// raster thread; clients are responsible for re-threading the callback if
39+
// needed.
3440
static void Create(zx_koid_t id,
35-
fml::RefPtr<fml::TaskRunner> ui_task_runner,
36-
fuchsia::ui::views::ViewHolderToken view_holder_token,
37-
const BindCallback& on_bind_callback);
38-
static void Destroy(zx_koid_t id);
41+
ViewIdCallback on_view_created,
42+
fuchsia::ui::views::ViewHolderToken view_holder_token);
43+
static void Destroy(zx_koid_t id, ViewIdCallback on_view_destroyed);
3944
static ViewHolder* FromId(zx_koid_t id);
4045

41-
ViewHolder(fml::RefPtr<fml::TaskRunner> ui_task_runner,
42-
fuchsia::ui::views::ViewHolderToken view_holder_token,
43-
const BindCallback& on_bind_callback);
4446
~ViewHolder() = default;
4547

4648
// Sets the properties/opacity of the child view by issuing a Scenic command.
@@ -68,18 +70,20 @@ class ViewHolder {
6870
void set_focusable(bool value) { focusable_ = value; }
6971

7072
private:
71-
fml::RefPtr<fml::TaskRunner> ui_task_runner_;
73+
ViewHolder(fuchsia::ui::views::ViewHolderToken view_holder_token,
74+
ViewIdCallback on_view_created);
7275

7376
std::unique_ptr<scenic::EntityNode> entity_node_;
7477
std::unique_ptr<scenic::OpacityNodeHACK> opacity_node_;
7578
std::unique_ptr<scenic::ViewHolder> view_holder_;
7679

7780
fuchsia::ui::views::ViewHolderToken pending_view_holder_token_;
78-
BindCallback pending_bind_callback_;
7981

8082
bool hit_testable_ = true;
8183
bool focusable_ = true;
8284

85+
ViewIdCallback on_view_created_;
86+
8387
fuchsia::ui::gfx::ViewProperties pending_properties_;
8488
bool has_pending_properties_ = false;
8589

lib/ui/compositing/scene_host.cc

Lines changed: 44 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -19,24 +19,26 @@ namespace {
1919

2020
struct SceneHostBindingKey {
2121
std::string isolate_service_id;
22-
zx_koid_t koid;
22+
scenic::ResourceId resource_id;
2323

24-
SceneHostBindingKey(const zx_koid_t koid,
25-
const std::string isolate_service_id) {
26-
this->koid = koid;
24+
SceneHostBindingKey(const std::string isolate_service_id,
25+
scenic::ResourceId resource_id) {
2726
this->isolate_service_id = isolate_service_id;
27+
this->resource_id = resource_id;
2828
}
2929

3030
bool operator==(const SceneHostBindingKey& other) const {
31-
return isolate_service_id == other.isolate_service_id && koid == other.koid;
31+
return isolate_service_id == other.isolate_service_id &&
32+
resource_id == other.resource_id;
3233
}
3334
};
3435

3536
struct SceneHostBindingKeyHasher {
3637
std::size_t operator()(const SceneHostBindingKey& key) const {
37-
std::size_t koid_hash = std::hash<zx_koid_t>()(key.koid);
3838
std::size_t isolate_hash = std::hash<std::string>()(key.isolate_service_id);
39-
return koid_hash ^ isolate_hash;
39+
std::size_t resource_id_hash =
40+
std::hash<scenic::ResourceId>()(key.resource_id);
41+
return isolate_hash ^ resource_id_hash;
4042
}
4143
};
4244

@@ -54,7 +56,7 @@ void SceneHost_constructor(Dart_NativeArguments args) {
5456
flutter::SceneHost* GetSceneHost(scenic::ResourceId id,
5557
std::string isolate_service_id) {
5658
auto binding =
57-
scene_host_bindings.find(SceneHostBindingKey(id, isolate_service_id));
59+
scene_host_bindings.find(SceneHostBindingKey(isolate_service_id, id));
5860
if (binding == scene_host_bindings.end()) {
5961
return nullptr;
6062
} else {
@@ -165,7 +167,8 @@ SceneHost::SceneHost(fml::RefPtr<zircon::dart::Handle> viewHolderToken,
165167
Dart_Handle viewStateChangedCallback)
166168
: raster_task_runner_(
167169
UIDartState::Current()->GetTaskRunners().GetRasterTaskRunner()),
168-
koid_(GetKoid(viewHolderToken->handle())) {
170+
koid_(GetKoid(viewHolderToken->handle())),
171+
weak_factory_(this) {
169172
auto dart_state = UIDartState::Current();
170173
isolate_service_id_ = Dart_IsolateServiceId(Dart_CurrentIsolate());
171174

@@ -180,34 +183,47 @@ SceneHost::SceneHost(fml::RefPtr<zircon::dart::Handle> viewHolderToken,
180183
view_state_changed_callback_.Set(dart_state, viewStateChangedCallback);
181184
}
182185

183-
// This callback will be posted as a task when the |scenic::ViewHolder|
184-
// resource is created and given an id by the raster thread.
185-
auto bind_callback = [scene_host = this,
186-
isolate_service_id =
187-
isolate_service_id_](scenic::ResourceId id) {
188-
const auto key = SceneHostBindingKey(id, isolate_service_id);
189-
scene_host_bindings.emplace(std::make_pair(key, scene_host));
186+
// This callback is invoked on the raster thread when the |scenic::ViewHolder|
187+
// resource is created and given an id.
188+
auto bind_callback = [weak = weak_factory_.GetWeakPtr(),
189+
ui_task_runner =
190+
dart_state->GetTaskRunners().GetUITaskRunner()](
191+
scenic::ResourceId id) {
192+
ui_task_runner->PostTask([weak, id]() {
193+
if (!weak) {
194+
FML_LOG(WARNING) << "ViewHolder bound to SceneHost after SceneHost was "
195+
"destroyed; ignoring.";
196+
return;
197+
}
198+
199+
FML_DCHECK(weak->resource_id_ == 0);
200+
weak->resource_id_ = id;
201+
202+
const auto key =
203+
SceneHostBindingKey(weak->isolate_service_id_, weak->resource_id_);
204+
scene_host_bindings.emplace(std::make_pair(key, weak.get()));
205+
});
190206
};
191207

192208
// Pass the raw handle to the raster thread; destroying a
193209
// |zircon::dart::Handle| on that thread can cause a race condition.
194-
raster_task_runner_->PostTask(
195-
[id = koid_,
196-
ui_task_runner =
197-
UIDartState::Current()->GetTaskRunners().GetUITaskRunner(),
198-
raw_handle = viewHolderToken->ReleaseHandle(), bind_callback]() {
199-
flutter::ViewHolder::Create(
200-
id, std::move(ui_task_runner),
201-
scenic::ToViewHolderToken(zx::eventpair(raw_handle)),
202-
std::move(bind_callback));
203-
});
210+
raster_task_runner_->PostTask([koid = koid_,
211+
raw_handle = viewHolderToken->ReleaseHandle(),
212+
bind_callback = std::move(bind_callback)]() {
213+
flutter::ViewHolder::Create(
214+
koid, std::move(bind_callback),
215+
scenic::ToViewHolderToken(zx::eventpair(raw_handle)));
216+
});
204217
}
205218

206219
SceneHost::~SceneHost() {
207-
scene_host_bindings.erase(SceneHostBindingKey(koid_, isolate_service_id_));
220+
if (resource_id_ != 0) {
221+
scene_host_bindings.erase(
222+
SceneHostBindingKey(isolate_service_id_, resource_id_));
223+
}
208224

209225
raster_task_runner_->PostTask(
210-
[id = koid_]() { flutter::ViewHolder::Destroy(id); });
226+
[koid = koid_]() { flutter::ViewHolder::Destroy(koid, nullptr); });
211227
}
212228

213229
void SceneHost::dispose() {

0 commit comments

Comments
 (0)