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

Commit 9361ee5

Browse files
authored
[fuchsia] SceneHostBindings are no longer thread locals (#16262)
Prior to this change SceneHostBindinds was a ThreadLocal but the intention was for it to be IsolateLocal. Given that dart could collect this map on a non-UI thread this caused use-after-free issues. This change fixes it by making it keyed on isolate and koid this is not the ideal solution, this would exist on dart isolate group data struct. Given that Fuchsia is moving to use the embedder API, the decision to use this temporary work around was made. fixes flutter/flutter#49738
1 parent 22e31ae commit 9361ee5

File tree

2 files changed

+54
-27
lines changed

2 files changed

+54
-27
lines changed

lib/ui/compositing/scene_host.cc

Lines changed: 53 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -10,37 +10,65 @@
1010
#include <third_party/tonic/dart_binding_macros.h>
1111
#include <third_party/tonic/logging/dart_invoke.h>
1212

13+
#include "dart/runtime/include/dart_api.h"
1314
#include "flutter/flow/view_holder.h"
1415
#include "flutter/fml/thread_local.h"
1516
#include "flutter/lib/ui/ui_dart_state.h"
1617

1718
namespace {
1819

19-
using SceneHostBindings = std::unordered_map<zx_koid_t, flutter::SceneHost*>;
20+
struct SceneHostBindingKey {
21+
std::string isolate_service_id;
22+
zx_koid_t koid;
2023

21-
FML_THREAD_LOCAL fml::ThreadLocalUniquePtr<SceneHostBindings>
22-
tls_scene_host_bindings;
24+
SceneHostBindingKey(const zx_koid_t koid,
25+
const std::string isolate_service_id) {
26+
this->koid = koid;
27+
this->isolate_service_id = isolate_service_id;
28+
}
2329

24-
void SceneHost_constructor(Dart_NativeArguments args) {
25-
// This UI thread / Isolate contains at least 1 SceneHost. Initialize the
26-
// per-Isolate bindings.
27-
if (tls_scene_host_bindings.get() == nullptr) {
28-
tls_scene_host_bindings.reset(new SceneHostBindings());
30+
bool operator==(const SceneHostBindingKey& other) const {
31+
return isolate_service_id == other.isolate_service_id && koid == other.koid;
32+
}
33+
};
34+
35+
struct SceneHostBindingKeyHasher {
36+
std::size_t operator()(const SceneHostBindingKey& key) const {
37+
std::size_t koid_hash = std::hash<zx_koid_t>()(key.koid);
38+
std::size_t isolate_hash = std::hash<std::string>()(key.isolate_service_id);
39+
return koid_hash ^ isolate_hash;
2940
}
41+
};
42+
43+
using SceneHostBindings = std::unordered_map<SceneHostBindingKey,
44+
flutter::SceneHost*,
45+
SceneHostBindingKeyHasher>;
46+
47+
static SceneHostBindings scene_host_bindings;
3048

49+
void SceneHost_constructor(Dart_NativeArguments args) {
3150
tonic::DartCallConstructor(&flutter::SceneHost::Create, args);
3251
}
3352

34-
flutter::SceneHost* GetSceneHost(scenic::ResourceId id) {
35-
auto* bindings = tls_scene_host_bindings.get();
36-
FML_DCHECK(bindings);
37-
38-
auto binding = bindings->find(id);
39-
if (binding != bindings->end()) {
53+
flutter::SceneHost* GetSceneHost(scenic::ResourceId id,
54+
std::string isolate_service_id) {
55+
auto binding =
56+
scene_host_bindings.find(SceneHostBindingKey(id, isolate_service_id));
57+
if (binding == scene_host_bindings.end()) {
58+
return nullptr;
59+
} else {
4060
return binding->second;
4161
}
62+
}
4263

43-
return nullptr;
64+
flutter::SceneHost* GetSceneHostForCurrentIsolate(scenic::ResourceId id) {
65+
auto isolate = Dart_CurrentIsolate();
66+
if (!isolate) {
67+
return nullptr;
68+
} else {
69+
std::string isolate_service_id = Dart_IsolateServiceId(isolate);
70+
return GetSceneHost(id, isolate_service_id);
71+
}
4472
}
4573

4674
void InvokeDartClosure(const tonic::DartPersistentValue& closure) {
@@ -107,23 +135,23 @@ fml::RefPtr<SceneHost> SceneHost::Create(
107135
}
108136

109137
void SceneHost::OnViewConnected(scenic::ResourceId id) {
110-
auto* scene_host = GetSceneHost(id);
138+
auto* scene_host = GetSceneHostForCurrentIsolate(id);
111139

112140
if (scene_host && !scene_host->view_connected_callback_.is_empty()) {
113141
InvokeDartClosure(scene_host->view_connected_callback_);
114142
}
115143
}
116144

117145
void SceneHost::OnViewDisconnected(scenic::ResourceId id) {
118-
auto* scene_host = GetSceneHost(id);
146+
auto* scene_host = GetSceneHostForCurrentIsolate(id);
119147

120148
if (scene_host && !scene_host->view_disconnected_callback_.is_empty()) {
121149
InvokeDartClosure(scene_host->view_disconnected_callback_);
122150
}
123151
}
124152

125153
void SceneHost::OnViewStateChanged(scenic::ResourceId id, bool state) {
126-
auto* scene_host = GetSceneHost(id);
154+
auto* scene_host = GetSceneHostForCurrentIsolate(id);
127155

128156
if (scene_host && !scene_host->view_state_changed_callback_.is_empty()) {
129157
InvokeDartFunction(scene_host->view_state_changed_callback_, state);
@@ -138,6 +166,7 @@ SceneHost::SceneHost(fml::RefPtr<zircon::dart::Handle> viewHolderToken,
138166
UIDartState::Current()->GetTaskRunners().GetGPUTaskRunner()),
139167
koid_(GetKoid(viewHolderToken->handle())) {
140168
auto dart_state = UIDartState::Current();
169+
isolate_service_id_ = Dart_IsolateServiceId(Dart_CurrentIsolate());
141170

142171
// Initialize callbacks it they are non-null in Dart.
143172
if (!Dart_IsNull(viewConnectedCallback)) {
@@ -152,12 +181,11 @@ SceneHost::SceneHost(fml::RefPtr<zircon::dart::Handle> viewHolderToken,
152181

153182
// This callback will be posted as a task when the |scenic::ViewHolder|
154183
// resource is created and given an id by the GPU thread.
155-
auto bind_callback = [scene_host = this](scenic::ResourceId id) {
156-
auto* bindings = tls_scene_host_bindings.get();
157-
FML_DCHECK(bindings);
158-
FML_DCHECK(bindings->find(id) == bindings->end());
159-
160-
bindings->emplace(std::make_pair(id, scene_host));
184+
auto bind_callback = [scene_host = this,
185+
isolate_service_id =
186+
isolate_service_id_](scenic::ResourceId id) {
187+
const auto key = SceneHostBindingKey(id, isolate_service_id);
188+
scene_host_bindings.emplace(std::make_pair(key, scene_host));
161189
};
162190

163191
// Pass the raw handle to the GPU thead; destroying a |zircon::dart::Handle|
@@ -175,9 +203,7 @@ SceneHost::SceneHost(fml::RefPtr<zircon::dart::Handle> viewHolderToken,
175203
}
176204

177205
SceneHost::~SceneHost() {
178-
auto* bindings = tls_scene_host_bindings.get();
179-
FML_DCHECK(bindings);
180-
bindings->erase(koid_);
206+
scene_host_bindings.erase(SceneHostBindingKey(koid_, isolate_service_id_));
181207

182208
gpu_task_runner_->PostTask(
183209
[id = koid_]() { flutter::ViewHolder::Destroy(id); });

lib/ui/compositing/scene_host.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ class SceneHost : public RefCountedDartWrappable<SceneHost> {
5757
tonic::DartPersistentValue view_connected_callback_;
5858
tonic::DartPersistentValue view_disconnected_callback_;
5959
tonic::DartPersistentValue view_state_changed_callback_;
60+
std::string isolate_service_id_;
6061
zx_koid_t koid_ = ZX_KOID_INVALID;
6162
};
6263

0 commit comments

Comments
 (0)