Skip to content

Commit a85f986

Browse files
jason-simmonsJsouLiang
authored andcommitted
Ensure that PlatformViewIOS does not call into Shell semantics APIs during destruction (flutter#30835)
1 parent 791e660 commit a85f986

File tree

3 files changed

+73
-32
lines changed

3 files changed

+73
-32
lines changed

shell/platform/darwin/ios/framework/Source/accessibility_bridge_test.mm

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1664,4 +1664,51 @@ - (void)testFlutterSemanticsScrollViewManagedObjectLifecycleCorrectly {
16641664
// flutterSemanticsScrollView) will cause an EXC_BAD_ACCESS.
16651665
XCTAssertFalse([flutterSemanticsScrollView isAccessibilityElement]);
16661666
}
1667+
1668+
- (void)testPlatformViewDestructorDoesNotCallSemanticsAPIs {
1669+
class TestDelegate : public flutter::MockDelegate {
1670+
public:
1671+
void OnPlatformViewSetSemanticsEnabled(bool enabled) override { set_semantics_enabled_calls++; }
1672+
int set_semantics_enabled_calls = 0;
1673+
};
1674+
1675+
TestDelegate test_delegate;
1676+
auto thread = std::make_unique<fml::Thread>("AccessibilityBridgeTest");
1677+
auto thread_task_runner = thread->GetTaskRunner();
1678+
flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
1679+
/*platform=*/thread_task_runner,
1680+
/*raster=*/thread_task_runner,
1681+
/*ui=*/thread_task_runner,
1682+
/*io=*/thread_task_runner);
1683+
1684+
fml::AutoResetWaitableEvent latch;
1685+
thread_task_runner->PostTask([&] {
1686+
auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1687+
/*delegate=*/test_delegate,
1688+
/*rendering_api=*/flutter::IOSRenderingAPI::kSoftware,
1689+
/*platform_views_controller=*/nil,
1690+
/*task_runners=*/runners);
1691+
1692+
id mockFlutterViewController = OCMClassMock([FlutterViewController class]);
1693+
auto flutterPlatformViewsController =
1694+
std::make_shared<flutter::FlutterPlatformViewsController>();
1695+
OCMStub([mockFlutterViewController platformViewsController])
1696+
.andReturn(flutterPlatformViewsController.get());
1697+
auto weakFactory =
1698+
std::make_unique<fml::WeakPtrFactory<FlutterViewController>>(mockFlutterViewController);
1699+
platform_view->SetOwnerViewController(weakFactory->GetWeakPtr());
1700+
1701+
platform_view->SetSemanticsEnabled(true);
1702+
XCTAssertNotEqual(test_delegate.set_semantics_enabled_calls, 0);
1703+
1704+
// Deleting PlatformViewIOS should not call OnPlatformViewSetSemanticsEnabled
1705+
test_delegate.set_semantics_enabled_calls = 0;
1706+
platform_view.reset();
1707+
XCTAssertEqual(test_delegate.set_semantics_enabled_calls, 0);
1708+
1709+
latch.Signal();
1710+
});
1711+
latch.Wait();
1712+
}
1713+
16671714
@end

shell/platform/darwin/ios/platform_view_ios.h

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -113,20 +113,20 @@ class PlatformViewIOS final : public PlatformView {
113113
id<NSObject> observer_;
114114
};
115115

116-
/// Smart pointer that guarantees we communicate clearing Accessibility
116+
/// Wrapper that guarantees we communicate clearing Accessibility
117117
/// information to Dart.
118-
class AccessibilityBridgePtr {
118+
class AccessibilityBridgeManager {
119119
public:
120-
explicit AccessibilityBridgePtr(const std::function<void(bool)>& set_semantics_enabled);
121-
AccessibilityBridgePtr(const std::function<void(bool)>& set_semantics_enabled,
122-
AccessibilityBridge* bridge);
123-
~AccessibilityBridgePtr();
120+
explicit AccessibilityBridgeManager(const std::function<void(bool)>& set_semantics_enabled);
121+
AccessibilityBridgeManager(const std::function<void(bool)>& set_semantics_enabled,
122+
AccessibilityBridge* bridge);
124123
explicit operator bool() const noexcept { return static_cast<bool>(accessibility_bridge_); }
125-
AccessibilityBridge* operator->() const noexcept { return accessibility_bridge_.get(); }
126-
void reset(AccessibilityBridge* bridge = nullptr);
124+
AccessibilityBridge* get() const noexcept { return accessibility_bridge_.get(); }
125+
void Set(std::unique_ptr<AccessibilityBridge> bridge);
126+
void Clear();
127127

128128
private:
129-
FML_DISALLOW_COPY_AND_ASSIGN(AccessibilityBridgePtr);
129+
FML_DISALLOW_COPY_AND_ASSIGN(AccessibilityBridgeManager);
130130
std::unique_ptr<AccessibilityBridge> accessibility_bridge_;
131131
std::function<void(bool)> set_semantics_enabled_;
132132
};
@@ -138,7 +138,7 @@ class PlatformViewIOS final : public PlatformView {
138138
std::unique_ptr<IOSSurface> ios_surface_;
139139
std::shared_ptr<IOSContext> ios_context_;
140140
const std::shared_ptr<FlutterPlatformViewsController>& platform_views_controller_;
141-
AccessibilityBridgePtr accessibility_bridge_;
141+
AccessibilityBridgeManager accessibility_bridge_;
142142
fml::scoped_nsprotocol<FlutterTextInputPlugin*> text_input_plugin_;
143143
fml::closure firstFrameCallback_;
144144
ScopedObserver dealloc_view_controller_observer_;

shell/platform/darwin/ios/platform_view_ios.mm

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@
1616

1717
namespace flutter {
1818

19-
PlatformViewIOS::AccessibilityBridgePtr::AccessibilityBridgePtr(
19+
PlatformViewIOS::AccessibilityBridgeManager::AccessibilityBridgeManager(
2020
const std::function<void(bool)>& set_semantics_enabled)
21-
: AccessibilityBridgePtr(set_semantics_enabled, nullptr) {}
21+
: AccessibilityBridgeManager(set_semantics_enabled, nullptr) {}
2222

23-
PlatformViewIOS::AccessibilityBridgePtr::AccessibilityBridgePtr(
23+
PlatformViewIOS::AccessibilityBridgeManager::AccessibilityBridgeManager(
2424
const std::function<void(bool)>& set_semantics_enabled,
2525
AccessibilityBridge* bridge)
2626
: accessibility_bridge_(bridge), set_semantics_enabled_(set_semantics_enabled) {
@@ -29,20 +29,14 @@
2929
}
3030
}
3131

32-
PlatformViewIOS::AccessibilityBridgePtr::~AccessibilityBridgePtr() {
33-
if (accessibility_bridge_) {
34-
set_semantics_enabled_(false);
35-
}
32+
void PlatformViewIOS::AccessibilityBridgeManager::Set(std::unique_ptr<AccessibilityBridge> bridge) {
33+
accessibility_bridge_ = std::move(bridge);
34+
set_semantics_enabled_(true);
3635
}
3736

38-
void PlatformViewIOS::AccessibilityBridgePtr::reset(AccessibilityBridge* bridge) {
39-
if (accessibility_bridge_) {
40-
set_semantics_enabled_(false);
41-
}
42-
accessibility_bridge_.reset(bridge);
43-
if (accessibility_bridge_) {
44-
set_semantics_enabled_(true);
45-
}
37+
void PlatformViewIOS::AccessibilityBridgeManager::Clear() {
38+
set_semantics_enabled_(false);
39+
accessibility_bridge_.reset();
4640
}
4741

4842
PlatformViewIOS::PlatformViewIOS(
@@ -83,7 +77,7 @@
8377
if (ios_surface_ || !owner_controller) {
8478
NotifyDestroyed();
8579
ios_surface_.reset();
86-
accessibility_bridge_.reset();
80+
accessibility_bridge_.Clear();
8781
}
8882
owner_controller_ = owner_controller;
8983

@@ -95,7 +89,7 @@
9589
queue:[NSOperationQueue mainQueue]
9690
usingBlock:^(NSNotification* note) {
9791
// Implicit copy of 'this' is fine.
98-
accessibility_bridge_.reset();
92+
accessibility_bridge_.Clear();
9993
owner_controller_.reset();
10094
}] retain]);
10195

@@ -119,7 +113,7 @@
119113
FML_DCHECK(ios_surface_ != nullptr);
120114

121115
if (accessibility_bridge_) {
122-
accessibility_bridge_.reset(new AccessibilityBridge(
116+
accessibility_bridge_.Set(std::make_unique<AccessibilityBridge>(
123117
owner_controller_.get(), this, [owner_controller_.get() platformViewsController]));
124118
}
125119
}
@@ -166,10 +160,10 @@
166160
return;
167161
}
168162
if (enabled && !accessibility_bridge_) {
169-
accessibility_bridge_.reset(new AccessibilityBridge(
163+
accessibility_bridge_.Set(std::make_unique<AccessibilityBridge>(
170164
owner_controller_.get(), this, [owner_controller_.get() platformViewsController]));
171165
} else if (!enabled && accessibility_bridge_) {
172-
accessibility_bridge_.reset();
166+
accessibility_bridge_.Clear();
173167
} else {
174168
PlatformView::SetSemanticsEnabled(enabled);
175169
}
@@ -185,7 +179,7 @@
185179
flutter::CustomAccessibilityActionUpdates actions) {
186180
FML_DCHECK(owner_controller_);
187181
if (accessibility_bridge_) {
188-
accessibility_bridge_->UpdateSemantics(std::move(update), std::move(actions));
182+
accessibility_bridge_.get()->UpdateSemantics(std::move(update), std::move(actions));
189183
[[NSNotificationCenter defaultCenter] postNotificationName:FlutterSemanticsUpdateNotification
190184
object:owner_controller_.get()];
191185
}
@@ -198,7 +192,7 @@
198192

199193
void PlatformViewIOS::OnPreEngineRestart() const {
200194
if (accessibility_bridge_) {
201-
accessibility_bridge_->clearState();
195+
accessibility_bridge_.get()->clearState();
202196
}
203197
if (!owner_controller_) {
204198
return;

0 commit comments

Comments
 (0)