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

[iOS] Fix App crash when use WebView with iOS VoiceOver #52484

Merged
merged 9 commits into from
May 10, 2024

Conversation

tacck
Copy link
Contributor

@tacck tacck commented May 1, 2024

This PR fix the issue flutter/flutter #140528.

This fix cleans up declarations regarding retain and release.
flutterAccessibilityContainer needs to be managed in FlutterPlatformViews.mm, and problems will occur if retain or release is performed in SemanticsObject.mm.

This fix is checked by the testFlutterPlatformViewSemanticsContainer function in the SemanticsObjectTest.mm.
The result is not changed.

Pre-launch Checklist

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • I read the Tree Hygiene wiki page, which explains my responsibilities.
  • I read and followed the Flutter Style Guide and the C++, Objective-C, Java style guides.
  • I listed at least one issue that this PR fixes in the description above.
  • I added new tests to check the change I am making or feature I am adding, or the PR is test-exempt. See testing the engine for instructions on writing and running engine tests.
  • I updated/added relevant documentation (doc comments with ///).
  • I signed the CLA.
  • All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel on Discord.

@tacck tacck changed the title Fix ios voiceover webview Fix App crash when use WebView with iOS VoiceOver May 1, 2024
@tacck tacck changed the title Fix App crash when use WebView with iOS VoiceOver [iOS] Fix App crash when use WebView with iOS VoiceOver May 1, 2024
@tacck tacck marked this pull request as ready for review May 2, 2024 07:52
@chinmaygarde
Copy link
Member

cc @jmagman

Copy link
Member

@jmagman jmagman left a comment

Choose a reason for hiding this comment

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

This fix is checked by the testFlutterPlatformViewSemanticsContainer function in the SemanticsObjectTest.mm.
The result is not changed.

Are you able to get a test to fail/crash on main but succeed on this PR, that actually exercises the bad behavior? Your fix looks more correct, but in practice I can't see how it's actually changing the retains in a way that would prevent a crash.

This test, for example, passed on both main and this PR:

- (void)testFlutterPlatformViewSemanticsContainer {
  fml::WeakPtrFactory<flutter::testing::MockAccessibilityBridge> factory(
      new flutter::testing::MockAccessibilityBridge());
  fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
  __weak FlutterTouchInterceptingView* weakPlatformView;
  __weak FlutterPlatformViewSemanticsContainer* weakContainer;
  @autoreleasepool {
    FlutterTouchInterceptingView* platformView = [[FlutterTouchInterceptingView alloc] init];
    weakPlatformView = platformView;

    @autoreleasepool {
      FlutterPlatformViewSemanticsContainer* container =
      [[FlutterPlatformViewSemanticsContainer alloc] initWithBridge:bridge
                                                                uid:1
                                                       platformView:platformView];
      weakContainer = container;
      XCTAssertEqualObjects(platformView.accessibilityContainer, container);
      XCTAssertNotNil(weakPlatformView);
      XCTAssertNotNil(weakContainer);
    }
    XCTAssertNotNil(weakPlatformView);
    XCTAssertNil(weakContainer);
  }
  // Check if there's no more strong references to `platformView` after container and platformView
  // are released.
  XCTAssertNil(weakPlatformView);
  XCTAssertNil(weakContainer);
}

By the way, I'm hoping to migrate FlutterPlatformViews to ARC soon to prevent these kinds of issues 🙂

@tacck
Copy link
Contributor Author

tacck commented May 7, 2024

@jmagman
Thank you for your review.
I modified the test code based on the example you wrote.
https://github.com/flutter/engine/pull/52484/files#diff-31e401d2bb8996a130877ac6c34512d746f122368d40946914a592c1648a7f07

Are you able to get a test to fail/crash on main but succeed on this PR, that actually exercises the bad behavior? Your fix looks more correct, but in practice I can't see how it's actually changing the retains in a way that would prevent a crash.

This test verifies that the container object continues to exist even if it moves to a different scope.
This is because the platformView retains the container.
When platformView is destroyed, container will also be destroyed simultaneously.
It is the difference between main and PR.

By the way, I'm hoping to migrate FlutterPlatformViews to ARC soon to prevent these kinds of issues 🙂

That's great.
I hope it goes well 😊

@jmagman
Copy link
Member

jmagman commented May 8, 2024

This test verifies that the container object continues to exist even if it moves to a different scope. This is because the platformView retains the container. When platformView is destroyed, container will also be destroyed simultaneously. It is the difference between main and PR.

Hm, this test also passes on main though.

@tacck
Copy link
Contributor Author

tacck commented May 9, 2024

I validated my fixes and tests using the following process.
Please let me know if there are any issues.


Download tools and add PATH.
SETTING UP

git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
export PATH=${PATH}:$(pwd)/depot_tools

Download the code and prepare.
Setting up the Engine development environment

mkdir engine; cd engine;
fetch flutter
git -C src/flutter remote rename origin upstream
gclient sync

git pull again at 2024/05/09 11:00+09:00 (2024/05/09 02:00+00:00 UTC)

git -C src/flutter pull upstream main
gclient sync

Build engine.
Compiling the engine

cd src
./flutter/tools/gn --ios --unoptimized --simulator --simulator-cpu=arm64
ninja -C out/ios_debug_sim_unopt_arm64
./flutter/tools/gn --unoptimized --mac-cpu arm64
ninja -C out/host_debug_unopt_arm64

Do test.
Testing the engine

./flutter/testing/run_tests.py --type=objc --ios-variant=ios_debug_sim_unopt_arm64 --variant=host_debug_unopt_arm64

Result:

(snip)
** TEST SUCCEEDED **
(snip)

Now, I think the environment is set up.

Patch the test code and do the below again.

./flutter/tools/gn --ios --unoptimized --simulator --simulator-cpu=arm64
ninja -C out/ios_debug_sim_unopt_arm64
./flutter/tools/gn --unoptimized --mac-cpu arm64
ninja -C out/host_debug_unopt_arm64
./flutter/testing/run_tests.py --type=objc --ios-variant=ios_debug_sim_unopt_arm64 --variant=host_debug_unopt_arm64

Result:

(snip)
Test Case '-[SemanticsObjectTest testFlutterPlatformViewSemanticsContainer]' started.
/../../flutter/shell/platform/darwin/ios/framework/Source/SemanticsObjectTest.mm:1015: error: -[SemanticsObjectTest testFlutterPlatformViewSemanticsContainer] : ((weakContainer) != nil) failed
Test Case '-[SemanticsObjectTest testFlutterPlatformViewSemanticsContainer]' failed (0.058 seconds).
(snip)
** TEST FAILED **
(snip)

This means that the test code catches the checkpoint in the main branch, I think.

Patch all code and do above again.

Result:

** TEST SUCCEEDED **

This means that the product code fix the probrem, I think.

Copy link
Member

@jmagman jmagman left a comment

Choose a reason for hiding this comment

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

Apologies for wasting your time, you're totally right, I was running the test incorrectly (I was playing around with bin/et and it output to out/ci/ios_debug_unopt_sim_arm64 instead of out/ios_debug_sim_unopt 😓

FLUTTER_ENGINE[arch=x86_64]=ios_debug_sim_unopt
FLUTTER_ENGINE[arch=arm64]=ios_debug_sim_unopt_arm64
FLUTTER_ENGINE=ios_debug_sim_unopt_arm64

)

LGTM, thanks for the fix!

@jmagman jmagman requested a review from hellohuanlin May 9, 2024 19:30
@jmagman
Copy link
Member

jmagman commented May 9, 2024

+ @hellohuanlin for second review.

Copy link
Contributor

@hellohuanlin hellohuanlin left a comment

Choose a reason for hiding this comment

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

Good catch! Thanks for digging into this.

[platformView setFlutterAccessibilityContainer:self];
}
return self;
}

- (void)dealloc {
[_platformView release];
_platformView = nil;
Copy link
Contributor

@hellohuanlin hellohuanlin May 9, 2024

Choose a reason for hiding this comment

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

nit: it's not necessary to nil out the ivar (can remove the whole dealloc method here).

Copy link
Member

Choose a reason for hiding this comment

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

I'm about to remove this dealloc in #52535, I wouldn't worry about it in this PR.

Copy link
Member

Choose a reason for hiding this comment

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

Oh actually that's not true, the PR doesn't include SemanticsObject. But I'll get to that one hopefully soon 🙂

@jmagman jmagman merged commit ea83156 into flutter:main May 10, 2024
26 checks passed
jmagman added a commit to jmagman/engine that referenced this pull request May 10, 2024
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request May 10, 2024
zanderso pushed a commit to flutter/flutter that referenced this pull request May 10, 2024
…148137)

flutter/engine@c0917b1...1ccd0c3

2024-05-10 [email protected] Fixed constness
of display list storage. (flutter/engine#52705)
2024-05-10 [email protected] Revert "Various
documentation improvements (#52600)" (flutter/engine#52709)
2024-05-10 [email protected] Manual roll Dart SDK from
b7cad2edae4b to 01121c008f4d (3 revisions) (flutter/engine#52706)
2024-05-10 [email protected] [iOS] Fix App crash when use WebView with iOS
VoiceOver (flutter/engine#52484)
2024-05-09 [email protected] Various documentation improvements (#52600)
(flutter/engine#52623)
2024-05-09 [email protected] [web] scale semantic text elements to
match the desired focus ring size (flutter/engine#52586)
2024-05-09 [email protected] [Impeller] Adds
impeller display list golden tests (flutter/engine#52690)
2024-05-09 [email protected] Roll buildroot to
70a42312a688 (flutter/engine#52675)
2024-05-09 [email protected] When `et` is not attached
to a terminal, still split lines for status updates.
(flutter/engine#52681)
2024-05-09 [email protected] updated analysis
exclusion (flutter/engine#52699)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-engine-flutter-autoroll
Please CC [email protected],[email protected] on the revert to ensure that
a human
is aware of the problem.

To file a bug in Flutter:
https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
@agacemi
Copy link

agacemi commented May 26, 2024

@zanderso any idea if this fix will be released as a patch of the current release 3.22 !

@jmagman
Copy link
Member

jmagman commented May 28, 2024

This fix is in 3.23.0-10.0.pre which hasn't reached the beta channel yet. See https://github.com/flutter/flutter/blob/master/docs/releases/Hotfixes-to-the-Stable-Channel.md

@JDongKhan
Copy link

Any progress?

@tacck
Copy link
Contributor Author

tacck commented Feb 10, 2025

@JDongKhan
This PR was incorporated into 3.24.0.
https://docs.flutter.dev/release/release-notes/release-notes-3.24.0

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants