Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix iOS accessibility bridge leak #14155

Closed
wants to merge 18 commits into from
Closed

Fix iOS accessibility bridge leak #14155

wants to merge 18 commits into from

Conversation

xujim
Copy link

@xujim xujim commented Dec 6, 2019

see issue: flutter/flutter#45599
When accessibility element got focus, it will be kept by __UIAccessibilityFocusedElements.
Consequently, accessibility bridge will fail to dealloc the kept semantics objects when FlutterEngine need to reset its FlutterViewController( in the function: FlutterEngine::setViewController) and reset the platform view's accesssiblity bridge( int the function: PlatformViewIOS::SetOwnerViewController).
To fix it, we use focusedAccessibilityElements( a vector) to keep those transiently focused elements, and reset its bridge to the new one. As long as __UIAccessibilityFocusedElements release them, those semantics objects will be dealloced accordingly.

tvolkert and others added 4 commits December 2, 2019 13:28
* dart-lang/sdk@3f32196 Make LateInitialziationError abstract and uninstantiable
* dart-lang/sdk@f9cedb6 [vm/ffi] Fix source information in generated AST nodes
* dart-lang/sdk@8023acc [vm/ffi] Fix source information in generated AST nodes - part 2
* dart-lang/sdk@1392d61 [infra] Modify 2.7.0 make_version hack so that it also works on other branches
* 3e6d6bc add pointer data santizing in flutter web engine
@auto-assign auto-assign bot requested a review from liyuqian December 6, 2019 09:31
@googlebot
Copy link

Thanks for your pull request. It looks like this may be your first contribution to a Google open source project (if not, look below for help). Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

📝 Please visit https://cla.developers.google.com/ to sign.

Once you've signed (or fixed any issues), please reply here with @googlebot I signed it! and we'll verify it.


What to do if you already signed the CLA

Individual signers
Corporate signers

ℹ️ Googlers: Go here for more info.

1 similar comment
@googlebot
Copy link

Thanks for your pull request. It looks like this may be your first contribution to a Google open source project (if not, look below for help). Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

📝 Please visit https://cla.developers.google.com/ to sign.

Once you've signed (or fixed any issues), please reply here with @googlebot I signed it! and we'll verify it.


What to do if you already signed the CLA

Individual signers
Corporate signers

ℹ️ Googlers: Go here for more info.

@googlebot
Copy link

CLAs look good, thanks!

ℹ️ Googlers: Go here for more info.

1 similar comment
@googlebot
Copy link

CLAs look good, thanks!

ℹ️ Googlers: Go here for more info.

@googlebot googlebot added cla: yes and removed cla: no labels Dec 6, 2019
@xujim
Copy link
Author

xujim commented Dec 6, 2019

To test it, use my example in flutter/flutter#45599, and turn on the voice over. Click push flutter page, and open second route repeatedly. Without this fix, it will crash due to leaked semantics object has no bridge, which has been reset by SetOwnerViewController

@liyuqian
Copy link
Contributor

liyuqian commented Dec 8, 2019

Thank you @xujim for reporting the issue and finding a fix! It would be nice if you can also transform your test in flutter/flutter#45599 into a test either in the flutter/engine or flutter/flutter repo, so we won't accidentally break it again in the future.

CC @goderbauer @cbracken for accessibility review, @xster for add-to-app, and @chinmaygarde for iOS and engine unit tests.

@goderbauer
Copy link
Member

/cc @darrenaustin, who was recently investigating a similar problem.

@xujim
Copy link
Author

xujim commented Dec 10, 2019

@liyuqian see my code: https://github.com/xujim/testaccessibility.git
The automation tests are included. However, unfortunately, the automation test failed to trigger the bug, may due to the thread difference.
Anyway, manually test can reproduce it.
Before test it, make sure you have turned the VoiceOver on.
If it is ok, I will add the test to somewhere of Flutter repository( please show me the appropriate dir)

* 57afd86 Remove specificity on Android and iOS
* 253851e Move Fuchsia unit test runners into engine repo
@liyuqian
Copy link
Contributor

Thank you @xujim for the effort of making https://github.com/xujim/testaccessibility.git ! Making a nice test is often more tricky and time consuming than the fix itself so we really appreciate your contributions here.

It seems Flutter doesn't currently have any real-device iOS integration tests with accessibility. The closest test I can find is android_semantics_integration_test. In order to test flutter/flutter#45599 automatically, we probably have to write some test for devicelab that automatically turns the VoiceOver on for a real iOS device.

CC one of our test guru @dnfield who is going to give a talk in accessibility in Flutter Interact tomorrow. Dan: do you have any thought on the best way to write a test for this?

@xster xster changed the title fix bug: https://github.com/flutter/flutter/issues/45599 Fix iOS accessibility bridge leak Dec 12, 2019
@xster
Copy link
Member

xster commented Dec 12, 2019

Also cc @gaaclarke on review and/or testing thoughts

Copy link
Member

@gaaclarke gaaclarke left a comment

Choose a reason for hiding this comment

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

I don't recommend this fix. Introducing a global c++ data structure to to store objective-c objects is perilous. The correct fix is in the dealloc of the AccessibilityBridge. You need to either issue a command that gets __UIAccessibilityFocusedElements to forget about the object, or your need to nil out the bridge parameter of outstanding SemanticObjects.

@dnfield
Copy link
Contributor

dnfield commented Dec 12, 2019

How do we end up with multiple focused accessibility elements?

@xujim
Copy link
Author

xujim commented Dec 13, 2019

@gaaclarke , yes, the ideal fix is let the __UIAccessibilityFocusedElements forget the focused element, However seems there is no such API to do it. I have tried a lot of method, but none of them works. For example: UIAccessibilityPostNotification(Layout/Screenchange). Besides, I don't know how to nil out the semantics object in the bridge if it is string referenced by __UIAccessibilityFocusedElements. If I call release directly, it will go to crash, because __UIAccessibilityFocusedElements then access a wild pointer.
So, I submitted this ugly fix, it violates the readonly relationship between bridge and semantics objects.
Could you show me the method to get the __UIAccessibilityFocusedElements lost the focus? Thanks in advance.

@xujim xujim requested a review from gaaclarke December 16, 2019 12:13
@darrenaustin
Copy link
Contributor

This appears to be dealing with a similar issue that PR #13857 was trying to fix. Not sure if it is the same thing, but in that case the problem was that when the a11y bridge shut down it correctly released everything it was referencing. However, for some reason iOS was still holding on to the a11y focused semantic object.

Like @xujim I was unable to find a way to get it to release these objects with the publicly available APIs. My solution was just guard the bridge reference in the objects so that if they tried to access a dead bridge it would no longer crash. Once VoiceOver comes up again these objects would be released by iOS.

@xujim
Copy link
Author

xujim commented Dec 17, 2019

@darrenaustin , it is similar, however #13857 cannot fix the problem cleanly. At the beginning, I used the similar way, it can avoid crash, but will let the second flutter page unable to receive accessibility events.

tvolkert and others added 7 commits January 16, 2020 23:06
* google/skia@a640745 Disable QCOM_tiled_rendering while we wait for test devices
* bcb8267 Revert "Do not default to downstream affinity on iOS insertText"
Co-authored-by: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com>
…lutter#16344)

pick up a dart-sdk merge commit (no source changed) so that a new build of the engine can be hotfixed into flutter stable v1.12.13.
# Conflicts:
#	BUILD.gn
#	DEPS
#	ci/licenses_golden/licenses_flutter
#	ci/licenses_golden/licenses_skia
#	ci/licenses_golden/licenses_third_party
#	lib/web_ui/lib/src/engine.dart
#	lib/web_ui/lib/src/engine/pointer_binding.dart
#	lib/web_ui/lib/src/engine/pointer_converter.dart
#	lib/web_ui/test/engine/pointer_binding_test.dart
#	testing/fuchsia/run_tests.sh
#	testing/fuchsia/test_fars
#	testing/scenario_app/ios/Scenarios/Scenarios.xcodeproj/project.pbxproj
#	testing/scenario_app/run_ios_tests.sh
# Conflicts:
#	BUILD.gn
#	DEPS
#	ci/licenses_golden/licenses_flutter
#	ci/licenses_golden/licenses_skia
#	ci/licenses_golden/licenses_third_party
#	lib/web_ui/lib/src/engine/pointer_binding.dart
#	lib/web_ui/lib/src/engine/pointer_converter.dart
#	lib/web_ui/test/engine/pointer_binding_test.dart
#	shell/platform/darwin/ios/platform_view_ios.mm
#	testing/fuchsia/run_tests.sh
#	testing/fuchsia/test_fars
#	testing/scenario_app/ios/Scenarios/Scenarios.xcodeproj/project.pbxproj
#	tools/luci/force_luci_build.sh
@chinmaygarde
Copy link
Member

cc @cbracken

@zanderso
Copy link
Member

@cbracken advises that this PR is stale, though may have some salvageable bits. He will take a look.

@zanderso zanderso closed this Sep 10, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet