Closed NickGerleman closed 1 year ago
@dozoisch your report is somewhat unclear, could you help us understand a bit more which scenario crashes vs unresolved?
Basically, can you copy paste this section and fill accordingly? 👇
S22 android 13 + RN 0.68.6 + Grammarly = Crash S22 android 13 + RN 0.69.8 + Grammarly = (didn't test, but can test it) S10 android 12 (but with Grammarly enabled) + RN 0.68.6 = Lag S10 android 12 (but with Grammarly enabled) + RN 0.69.8 = Lag + reproduced crash this morning
Given how other folks are reporting that for 0.68 it's fixed, I wonder if as @NickGerleman is suggesting, that there's something else going on in your code that might be affecting it. (or maybe there's only an issue with 0.69?)
Yesterday I was indeed in a view with an inverted flatlist, but I did the same thing in a different view where it's just a multiline input.
Here is the video of it:
https://user-images.githubusercontent.com/4422516/215815546-a7e401dd-c405-4a9e-8a0e-3d08ef488e66.mov
You will see two things. First, around 2:00 it starts lagging like crazy. I then unfocus the field and go write in a different field to show it's not the device that's lagging, and then when i refocus the field it crashes almost instantly.
Here is the S22 device information:
Samsung recently published an update that eliminated all of our ANRs. So this issue might be moot.
@phatmann can you provide a link?
Some of our users reported receiving an update from Samsung and after that they had no more ANRs. This is probably the update they received: https://security.samsungmobile.com/securityUpdate.smsb
That stripping AbsoluteSizeSpan resolved some hangs in the wild seems like a sign that reducing the number of formatting spans rendered to EditText can reduce the impact of the issue. AbsoluteSizeSpan was the one rendered everywhere, but there are more spans where we could possibly omit.
SetSpanOperation()
describes a step, in mapping of JS-side text props to a rendered Spannable. This Spannable is used and measured outside of the EditText, but we already mutate a new span before committing to the EditText to make changes only the EditText will see. The previous change works by removing spans at this stage, where their applied value is equivalent to a style attribute we set globally on the EditText (outside the Spannable).
Looking through the all MetricImpactingSpans created as part of a SetSpanOperation, we emit on:
Some of these are already likely optimal. E.g. italic covering a subset of text will always require a span. But application of something like font-family especially is more likely to apply to the entire Spannable, and could benefit from the same trick of removing spans where an EditText level attribute may deliver the same result. We need to be careful though to validate the output remains the same.
I was able to reproduce the behavior noted externally, that spans "multiply" during edits. I think this is likely the cause for the long-layouts, and Spannables too large to persist.
This behavior did not reproduce when using GBoard on the same device, including manually changing from the Samsung spellchecker to GBoard spellchecker, so that it would show its own annotations and emit SuggestionSpans.
The below example, is an uncontrolled component, where the initial render is done by React, and RN never mutates the TextInput again afterward. It has non-uniform text-size and text coloring, so React Initially renders it with 2 spans for text size, and two spans for font color.
Even appending to the end of the EditText, where we should not need to make splits, we see the previous spans duplicated many times over as raw AbsoluteSizeSpan
and ForegroundColorSpan
(I think calling clone()
on the React variant does this). Notably, ForegroundColorSpan
is not metric impacting, but presumably lead to larger Spannables. All of the cloned spans are present after the start of the last character, with zero-length, and flags 0x045022
which includes SPAN_EXCLUSIVE_INCLUSIVE
.
Version (has Jan 6 2023 Security Patches):
Here's a stacktrace of users using S20, A71 5G, Note 20 Ultra 5G all running Android 13 that lags/crashes, controlled multiline input after updating to 0.68.6
:
let me know if you guys want device info for the rest of the devices, stacktrace is the same on all devices.
ps. this input is under an inverted FlatList (with the scaleY: -1
patch applied). The lag is happening only on this screen/input. On my S22 and on some other users that are using S22 it works fine.
edit: according to play console vitals stacktraces this is the same issue as: https://github.com/facebook/react-native/issues/35936#issuecomment-1410291851
UPDATE: we have now released a patch release containing the first mitigation for all the supported versions of React Native plus 0.68 (since it's still used by a significant number of users):
Please upgrade to those versions and report back here if it helps! We are still planning to do further investigation, but don't expect any new releases concerning this topic for at least a couple weeks (unless something unexpected happens).
@kelset just to comfirm that the ANR fix is in the 0.71.2 release as I don't see the commit in the release notes as is in 0.70.7 ans the others
Thanks @kelset! It's worth mentioning that, unlike the other versions, v0.71.2 doesn't mention this fix in its release notes (at least not that I can see).
@enahum @swrobel sorry, for some reason I missed it when doing the changelog 🤦♂️ the commit is indeed in the 0.71 branch: https://github.com/facebook/react-native/commit/4650ef36e3d63df6e6a31f00fcf323c53daff2d6 and is released in 0.71.2. I've updated the release notes and changelog
UPDATE: Yes, found out the setState call is the issue in my case. After I commented out the onChangeText
method I did not get the lag or ANR.
We upgraded our RN app to v0.68.6. Unfortunately the lag and ANR still happens. I have tested on my current device Samsung A52 which is running on android 13 (Debug mode). Grammerly is enabled. My TextInput
is simply inside a ScrollView
(KeyboardAwareScrollView). No FlatList involved.
This is how the current TextInput is written, It is an uncontrolled input with a default value. I am suspecting that setting an object on each keystroke might be the problem even though it was working fine prior to Android 13.
<TextInput
autoComplete="off"
defaultValue={this.state.note_questions[q.id] || ''}
onChangeText={message => {
this.setState({
note_questions: {
...this.state.note_questions,
[q.id]: message,
},
note_errors: {},
});
}} />
*** Side note => last time I tried to minimise the render issue by converting my state
to ref
. I got a very positive result and there was no lag / ANR happening.
The patch has fixed ANRs for us, but now we are experiencing the following crash (at a lower rate than ANR, however):
android.os.TransactionTooLargeException: data parcel size 394596 bytes
at android.os.BinderProxy.transactNative(BinderProxy.java)
at android.os.BinderProxy.transact(BinderProxy.java:653)
at android.view.autofill.IAutoFillManager$Stub$Proxy.updateSession(IAutoFillManager.java:615)
at android.view.autofill.AutofillManager.updateSessionLocked(AutofillManager.java:2181)
at android.view.autofill.AutofillManager.notifyViewEnteredLocked(AutofillManager.java:1302)
at android.view.autofill.AutofillManager.notifyViewEntered(AutofillManager.java:1250)
at android.view.autofill.AutofillManager.notifyViewEntered(AutofillManager.java:1165)
at android.view.View.notifyEnterOrExitForAutoFillIfNeeded(View.java:8593)
at android.view.View.performClick(View.java:7889)
at android.widget.TextView.performClick(TextView.java:16201)
at android.view.View.performClickInternal(View.java:7858)
at android.view.View.-$$Nest$mperformClickInternal
at android.view.View$PerformClick.run(View.java:30863)
at android.os.Handler.handleCallback(Handler.java:942)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at android.app.ActivityThread.main(ActivityThread.java:8741)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)
java.lang.RuntimeException: android.os.TransactionTooLargeException: data parcel size 394596 bytes
at android.view.autofill.AutofillManager.updateSessionLocked(AutofillManager.java:2184)
at android.view.autofill.AutofillManager.notifyViewEnteredLocked(AutofillManager.java:1302)
at android.view.autofill.AutofillManager.notifyViewEntered(AutofillManager.java:1250)
at android.view.autofill.AutofillManager.notifyViewEntered(AutofillManager.java:1165)
at android.view.View.notifyEnterOrExitForAutoFillIfNeeded(View.java:8593)
at android.view.View.performClick(View.java:7889)
at android.widget.TextView.performClick(TextView.java:16201)
at android.view.View.performClickInternal(View.java:7858)
at android.view.View.-$$Nest$mperformClickInternal
at android.view.View$PerformClick.run(View.java:30863)
at android.os.Handler.handleCallback(Handler.java:942)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at android.app.ActivityThread.main(ActivityThread.java:8741)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)
Can confirm... No more ANRs, but this popped up (not as frequent yet)
android.os.TransactionTooLargeException: data parcel size 395088 bytes
at android.os.BinderProxy.transactNative(BinderProxy.java)
at android.os.BinderProxy.transact(BinderProxy.java:653)
at android.view.autofill.IAutoFillManager$Stub$Proxy.updateSession(IAutoFillManager.java:615)
at android.view.autofill.AutofillManager.updateSessionLocked(AutofillManager.java:2181)
at android.view.autofill.AutofillManager.notifyValueChanged(AutofillManager.java:1583)
at android.widget.TextView.notifyListeningManagersAfterTextChanged(TextView.java:11935)
at android.widget.TextView.sendAfterTextChanged(TextView.java:11915)
at android.widget.TextView$ChangeWatcher.afterTextChanged(TextView.java:15283)
at android.text.SpannableStringBuilder.sendAfterTextChanged(SpannableStringBuilder.java:1291)
at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:591)
at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:521)
at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:39)
at android.view.inputmethod.BaseInputConnection.replaceText(BaseInputConnection.java:945)
at android.view.inputmethod.BaseInputConnection.commitText(BaseInputConnection.java:219)
at com.android.internal.inputmethod.EditableInputConnection.commitText(EditableInputConnection.java:201)
at com.android.internal.inputmethod.RemoteInputConnectionImpl.lambda$commitText$16$com-android-internal-inputmethod-RemoteInputConnectionImpl(RemoteInputConnectionImpl.java:569)
at com.android.internal.inputmethod.RemoteInputConnectionImpl$$ExternalSyntheticLambda34.run
at android.os.Handler.handleCallback(Handler.java:942)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at android.app.ActivityThread.main(ActivityThread.java:8741)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)
java.lang.RuntimeException: android.os.TransactionTooLargeException: data parcel size 395088 bytes
at android.view.autofill.AutofillManager.updateSessionLocked(AutofillManager.java:2184)
at android.view.autofill.AutofillManager.notifyValueChanged(AutofillManager.java:1583)
at android.widget.TextView.notifyListeningManagersAfterTextChanged(TextView.java:11935)
at android.widget.TextView.sendAfterTextChanged(TextView.java:11915)
at android.widget.TextView$ChangeWatcher.afterTextChanged(TextView.java:15283)
at android.text.SpannableStringBuilder.sendAfterTextChanged(SpannableStringBuilder.java:1291)
at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:591)
at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:521)
at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:39)
at android.view.inputmethod.BaseInputConnection.replaceText(BaseInputConnection.java:945)
at android.view.inputmethod.BaseInputConnection.commitText(BaseInputConnection.java:219)
at com.android.internal.inputmethod.EditableInputConnection.commitText(EditableInputConnection.java:201)
at com.android.internal.inputmethod.RemoteInputConnectionImpl.lambda$commitText$16$com-android-internal-inputmethod-RemoteInputConnectionImpl(RemoteInputConnectionImpl.java:569)
at com.android.internal.inputmethod.RemoteInputConnectionImpl$$ExternalSyntheticLambda34.run
at android.os.Handler.handleCallback(Handler.java:942)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at android.app.ActivityThread.main(ActivityThread.java:8741)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)
I think it is relatively likely the crash and hang have the same underlying cause.
If the system is infinitely multiplying spans, the Spannable may become very large, which could cause the crash we are seeing. Previously we hung because we had many metric effecting spans, which also decrease performance, instead of just taking size.
So in the cases of crashes, I suspect we would have previously hung, but now that we don't, we now see a later issue handling the many spans in the text.
I am working on a more comprehensive change which targets reducing span usage in more cases, to mitigate the platform infinitely multiplying them. This should make the hang and crash less likely still (especially in cases where text style is fully uniform).
UPDATE: Yes, found out the setState call is the issue in my case. After I commented out the
onChangeText
method I did not get the lag or ANR.We upgraded our RN app to v0.68.6. Unfortunately the lag and ANR still happens. I have tested on my current device Samsung A52 which is running on android 13 (Debug mode). Grammerly is enabled. My
TextInput
is simply inside aScrollView
(KeyboardAwareScrollView). No FlatList involved.This is how the current TextInput is written, It is an uncontrolled input with a default value. I am suspecting that setting an object on each keystroke might be the problem even though it was working fine prior to Android 13.
<TextInput autoComplete="off" defaultValue={this.state.note_questions[q.id] || ''} onChangeText={message => { this.setState({ note_questions: { ...this.state.note_questions, [q.id]: message, }, note_errors: {}, }); }} />
*** Side note => last time I tried to minimise the render issue by converting my
state
toref
. I got a very positive result and there was no lag / ANR happening.
This is it! working like a charm
Edit: We can't do this without building RN from source...
Edit: Never mind, we can use the diff at https://github.com/facebook/react-native/pull/35967/files
Hey I don't expect an update of RN 0.66.5, but could you please point us to the diff with the fix?
We can always apply the fix via patch-package
manually in the meantime.
Thank you!
@fabiendem you have to build from source, patch-package won’t work
Argh yeah makes sense @efstathiosntonas, thank you, it will pull RN from the pre-built artifacts. We would need to do https://reactnative.dev/contributing/how-to-build-from-source to apply the patches...
I still get ANRs using RN 0.70.7. For folks who claimed the patch fixes the problem, I wonder if there was anything else that needed to be changed other than adding the patch by bumping up the RN version?
I am confused, is it considered officially fixed in those patches or not yet?
Did we get confirmation that those patchs do indeed lead to new crashes rather than ANRs? Or was it just project-related for those who mentioned it?
@pierroo in my case less ANR but more crashes, 0.68.6 controlled input
Yea, ANR is less, but now it does a straight crash instead of hanging. One of our users turned off autosuggest (in device keyboard settings), then turned it back on, and somehow, can't reproduce it anymore. I wonder if that helps.
still happening in 0.68.6, the device that was crashing was a xiaomi with grammarly keyboard, so this shouldn't be titled on samsung devices only.
Definitely not only samsung and definitely still happening. Is this still being looked at?
Still Hang/Lag on samsung when typing too long text with Samsung keyboard and as well as Gboard in samsung S22
TextInput is uncontrolled input
Also Tried with Controlled Input same results
React native version - 0.70.7
Upgraded to 0.68.6, Still noticing unresponsiveness on samsung when typing long text with Samsung keyboard and as well as Gboard in samsung
Upgraded to 0.69.8 and unfortunately the issue still arises, as a matter of fact a beta tester mentioned it's even worse and it lagged so bad they had to turn off their phone entirely :/
folks, we feel your pain and Nick is still investigating more substantial approaches, but let me remind you that without clear, minimal repro it's hard to make progress.
Posting comments along the lines of "me too" only generates noise. This issue had clear explanations and well defined steps, and allowed the engineers working on this to figure out a mitigation - if you are affected by problems so substantial, it should be doable for you to recreate the problem in a way that can be tested independently.
Hello @kelset @NickGerleman, the community is grateful for your efforts in getting this issue resolved. I don't intend to put any form of pressure through this comment. However, if you can share any updates, it would be appreciated very much.
Sorry, gave a recent update in https://github.com/facebook/react-native/issues/35590#issuecomment-1459038182 without updating this thread.
TLDR: The larger change to minimize the number of spans emitted by React Native is currently being validated and is targeting next week to hit the main branch. This does not erase the issue effecting the native platform, but mitigates the issue in as many cases as possible on the React Native side. So only scenarios that would cause a hang in the stock platform also effect React Native. That should:
It's not only Samsung keyboards or Samsung smartphones. I use a Xiaomi Redmi K20 phone with Swiftkey and have problems with the mattermost mobile app (https://github.com/mattermost/mattermost-mobile/issues/7098) caused by this issue.
@NickGerleman thank you for your ongoing efforts in addressing this issue. I wanted to inquire if you have any estimated time of release now that you have opened the PRs?
Hey @NickGerleman, thanks for your efforts, I build the app with these PR, This time it seems to fix the issue, also it will be really helpful, If you can tell us expected time line of the release with this fix.
Apologies for all of the spam here. We made a configuration change to how we push in-progress changes to open-source, and it seems to get quite spammy if the changes include GitHub links 😅.
The series of changes has been merged to the main branch. We will backport the set of changes to earlier versions of React Native, after a little bit of bake time to ensure the set of changes does not cause any unexpected issues.
Hey everybody 👋
Quick update: the fixes from @NickGerleman are now in the 0.72 RC.1 release. We'd love if you tried that version and could confirm the fix works as expected. Once we are more confident with the changes, we will also include them in the patch releases of supported minor versions (0.71, 0.70, 0.69).
Hey @fortmarek, I have patched the fix on 0.71.5 on my end and build it from source, I can confirm, it fixes the issue. Also confirmed by our clients, its now working fine, Thanks @NickGerleman and every one for your efforts
Hey everyone - a quick update on this: we've just released:
Both contain @NickGerleman's multi-commit fix to address this problem - early signs in 0.72 RC1 suggested that they indeed address the problem, so we hope that by upgrading to these new versions you'll see improvements! Upgrade to those and let us know!
We are planning to also backport these fixes back to 68 and 69 - but the harsh reality is that the further back we go in the codebase, the more complicated this process of backporting gets (I literally attempted to bring back these fixes to 69 three separate times without much success 😭). We'll keep working on this and make it land in those older versions, but it will probably take a bit longer.
Hello!
So far so good, early signs show that react-native 0.70.9 partially fixed the bug for us.
We found some of our users still have hangs (ANR?) while writing in TextInput: Android 13 and Google Pixel 6a.
After some more updates, we found that this issue https://github.com/keybase/client/issues/25396 fix more TextInput hangs. (with this patch: https://phab.comm.dev/D6193)
We had a FlatList
inverted
, and it was enough to cause problems with Android 13 and TextInputs on the same screen. At least, this patch fixed hangs to some of our users, but 0.70.9 didn't.
For now, react-native 0.70.9 and the above patch fix all our problems, but we are waiting for more feedbacks from our users.
Thank you very much for all your work to all the team!
EDIT: The reply below referenced this is a known issue: https://github.com/facebook/react-native/issues/35983#issuecomment-1406020651
For anyone that didn't knew that issue, it was night and day on our app. Worth a try.
@mhammerc Your issue is related to the different issue, in which user's facing hang with inverted list, I solved it with this https://github.com/facebook/react-native/issues/35983#issuecomment-1406020651
iOS TextInput S.O.S: https://github.com/facebook/react-native/issues/36872
Hey everyone - a quick update on this: the 0.69.10 release is out, bringing the fixes back to the last minor in the release window: https://github.com/facebook/react-native/releases/tag/v0.69.10
We're also backporting it to 68, will start working on that asap.
Hey everyone - as promised, we've backported the fixes to 0.68 too: https://github.com/facebook/react-native/releases/tag/v0.68.7
Please bear in mind that this 0.68 patch release was done as an exceptional measure to help address this very impactful problem. We do not expect to do more patches for this minor, as it is out of the release support window. Please upgrade to newer versions asap.
Given the general silence since this new round of patches, we are assuming that it means that the problem is indeed addressed - massive props to @NickGerleman for his work in working on this!
We'll leave the issue open a few more days to see how things evolve just in case, after which we'll close.
After upgrading to 0.71.7 started to get the content oversize error. 93% from Android 13 devices, seems it happened when large amount of text being entered, put the app to background, and crash when coming back from background.
Caused by android.os.TransactionTooLargeException
data parcel size 1031804 bytes
android.os.BinderProxy.transactNative (BinderProxy.java)
android.os.BinderProxy.transact (BinderProxy.java:643)
android.app.IActivityClientController$Stub$Proxy.activityStopped (IActivityClientController.java:1248)
android.app.ActivityClient.activityStopped (ActivityClient.java:85)
android.app.servertransaction.PendingTransactionActions$StopInfo.run (PendingTransactionActions.java:143)
android.os.Handler.handleCallback (Handler.java:942)
android.os.Handler.dispatchMessage (Handler.java:99)
android.os.Looper.loopOnce (Looper.java:210)
android.os.Looper.loop (Looper.java:299)
android.app.ActivityThread.main (ActivityThread.java:8116)
java.lang.reflect.Method.invoke (Method.java)
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:559)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:950)
@tarouboy
when large amount of text being entered, put the app to background, and crash when coming back from background.
since this seems to be a separate behaviour/problem, can I ask you to open a new issue with this report (plus a repro) so that we can track it separately? this issue already has 90+ comments and GH starts to struggle after a certain point 😅
I'm going to close this as no new reports specific about the TextInput issue combo that we wanted to address (TextInput, Grammarly, Samsung) have been produced - so we can consider it addressed. If you can create a new repro that does not involve an inverted FlatList (since that's an existing problem we are aware of, and has been reported many times), please open a new issue.
Sorry for the ping, Can someone please confirm this solution also works well with the controlled inputs in react native? and we can use the value
prop? Previously we changed our controlled inputs to uncontrolled inputs because of the issue. Thanks a lot!
We are using RN 0.71.8 together with expo 48.0 and the issue is still happens to all of our Samsung users for some reason, any ideas?
NEW UPDATE: we have now released patch releases containing the second wave of fix for:
- https://github.com/facebook/react-native/releases/tag/v0.69.10
- https://github.com/facebook/react-native/releases/tag/v0.70.9
- https://github.com/facebook/react-native/releases/tag/v0.71.7
- https://github.com/facebook/react-native/releases/tag/v0.68.7
UPDATE: we have now released a patch release containing the first mitigation for all the supported versions of React Native plus 0.68 (since it's still used by a significant number of users):
- https://github.com/facebook/react-native/releases/tag/v0.68.6
- https://github.com/facebook/react-native/releases/tag/v0.69.8
- https://github.com/facebook/react-native/releases/tag/v0.70.7
- https://github.com/facebook/react-native/releases/tag/v0.71.2
Please upgrade to those versions and report back here if it helps! We are still planning to do further investigation, but don't expect any new releases concerning this topic for at least a couple weeks (unless something unexpected happens).
There have been repeated and persistent signals of ANRs (hangs) when typing into a multiline TextInput on Samsung phones. This is most reported by using the out-of-the-box keyboard provided by Samsung One UI 5. We have been able to locally reproduce the hangs on two separate Galaxy S22 devices. Most devices will not be as fast as the ones we have tested on.
Impact
The issue presents as repeated hangs or ANRs when typing into a TextInput which has a large amount of text. It is specific to the Samsung soft keyboard, and does not reproduce when using other keyboards like GBoard on the same device. There are a different set of TextInputs where we have confirmed impact depending on whether Fabric is enabled or disabled.
Fabric enabled
Both controlled and uncontrolled TextInputs are impacted.
Fabric disabled
Controlled TextInputs and uncontrolled TextInputs which set an initial value via child are impacted.
Root causing
Root causing the issue focused on:
- Locally profiling the hang under different scenarios
- Examining which span differences create the hang
- Reproducing the issue outside of React Native
Profiling
We saw similar results to the trace already shared in #35590. A Java sampling profiler shows the process
com.samsung.android.honeyboard
has a very long running frame, delivering input.This triggers code on the main thread, in the app process, where we see a hang happen while committing a text change from the IME to the underlying Spannable backing the EditText. The hang happens in an event handler which has subscribed to changes to the underlying text. The long-running work seems to be laying out the text.
Because the hang happens in response to an edit to the underlying Spannable, investigation focused on the Spannable content differences in scenarios which created ANRs vs not.
Spannable differences between hang/no hang
We examined typing into the below example, which may hang on Fabric but not Paper:
<TextInput multiline={true} />
Grammarly annotations were present as
SuggestionSpan
spans on both platforms. On Fabric but not paper there was the presence ofAbsoluteSizeSpan
spans, which set the font size within the text. This is akin to setting<span style=”font-size: 12px”}>Text</span>
within a browser.When we stubbed out platform code in React Native which set an
AbsoluteSizeSpan
, that example along with another previously hanging example would no longer hang. The hang was possible to trigger in an uncontrolled TextInput with a short string like “Text Here” as a child, so we attempted to repro the logical extreme, where we add a single span setting font size to the TextInput.Reproducing outside of React Native
We discovered that adding even a single inclusive span (specifically setting font size) is enough to create hangs. This can reproduced by:
- Adding an
EditText
with aninputType
oftextMultiLine
.- Adding an inclusive span setting font size: E.g.
str.setSpan(new AbsoluteSizeSpan(55), 0, string.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE)
- Pasting a large amount of text then starting to type.
We were able to create a repro for this on top of a template Android application. The issue only happens when using the Samsung keyboard.
reproducervideo.mp4 ~Grammarly annotations are not shown locally when changing the appId and namespace of the repro to
com.facebook.katana
(the ID of the Facebook app). This implies the Facebook app may be being special-cased, contributing to the lack of internal signal on the issue.~ This only happened on 1/2 devices, so it's possible there might be some setting or association that wasn't fresh.Remediation
While the underlying issue seems to be outside of React Native, the issue still has a real-world effect on our users. We are starting the process to mitigate the issue by working to notify Samsung. This issue has already shown signs of impacting the Android app ecosystem outside of React Native and the ability to set spans with formatting like font size is a fundamentally important part of the platform.
We hope this issue will be addressed in a future update from Samsung, but this does not address the already-present impact of the issue. A potential mitigation which we are exploring is whether React Native could avoid adding AbsoluteSizeSpan (or formatting spans in general) in more common cases.
There have been previously discovered workarounds for the issue, such as setting
keyboardType
tovisible-password
. We recommend against preemptively using these workarounds, due to impact on UX and accessibility.
Sumsung Galaxy A71 , Sumsung Galaxy A32, Sumsung Galaxy A53 phone the following crash occurs , hope to give me solution,thanks Fatal Exception: java.lang.IndexOutOfBoundsException: offset(1) should be less than line limit(0) at android.text.TextLine.measure(TextLine.java:389) at android.text.Layout.getHorizontal(Layout.java:1254) at android.text.Layout.getHorizontal(Layout.java:1230) at android.text.Layout.getPrimaryHorizontal(Layout.java:1200) at android.widget.TextView.bringPointIntoView(TextView.java:11046) at android.widget.TextView.updateAfterEdit(TextView.java:11983) at android.widget.Editor.finishBatchEdit(Editor.java:2086) at android.widget.Editor.endBatchEdit(Editor.java:2068) at android.widget.TextView.endBatchEdit(TextView.java:9931) at android.widget.TextView.doKeyDown(TextView.java:9505) at android.widget.TextView.onKeyDown(TextView.java:9275) at android.view.KeyEvent.dispatch(KeyEvent.java:3508) at android.view.View.dispatchKeyEvent(View.java:15395) at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1978) at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1978) at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1978) at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1978) at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1978) at android.widget.ScrollView.dispatchKeyEvent(ScrollView.java:738) at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1978) at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1978) at com.facebook.react.ReactRootView.dispatchKeyEvent(ReactRootView.java:234) at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1978) at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1978) at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1978) at com.android.internal.policy.DecorView.superDispatchKeyEvent(DecorView.java:1100) at com.android.internal.policy.PhoneWindow.superDispatchKeyEvent(PhoneWindow.java:1961) at android.app.Activity.dispatchKeyEvent(Activity.java:4342) at androidx.core.app.ComponentActivity.superDispatchKeyEvent(ComponentActivity.java:122) at androidx.core.view.KeyEventDispatcher.dispatchKeyEvent(KeyEventDispatcher.java:84) at androidx.core.app.ComponentActivity.dispatchKeyEvent(ComponentActivity.java:140) at com.android.internal.policy.DecorView.dispatchKeyEvent(DecorView.java:924) at android.view.ViewRootImpl$ViewPostImeInputStage.processKeyEvent(ViewRootImpl.java:8056) at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:7864) at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:7213) at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:7270) at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:7236) at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:7434) at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:7244) at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:7491) at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:7217) at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:7270) at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:7236) at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:7244) at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:7217) at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:10788) at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:10676) at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:10632) at android.view.ViewRootImpl$ViewRootHandler.handleMessageImpl(ViewRootImpl.java:6822) at android.view.ViewRootImpl$ViewRootHandler.handleMessage(ViewRootImpl.java:6697) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loopOnce(Looper.java:226) at android.os.Looper.loop(Looper.java:313) at android.app.ActivityThread.main(ActivityThread.java:8757) at java.lang.reflect.Method.invoke(Method.java) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)
NEW UPDATE: we have now released patch releases containing the second wave of fix for:
UPDATE: we have now released a patch release containing the first mitigation for all the supported versions of React Native plus 0.68 (since it's still used by a significant number of users):
Please upgrade to those versions and report back here if it helps! We are still planning to do further investigation, but don't expect any new releases concerning this topic for at least a couple weeks (unless something unexpected happens).
There have been repeated and persistent signals of ANRs (hangs) when typing into a multiline TextInput on Samsung phones. This is most reported by using the out-of-the-box keyboard provided by Samsung One UI 5. We have been able to locally reproduce the hangs on two separate Galaxy S22 devices. Most devices will not be as fast as the ones we have tested on.
Impact
The issue presents as repeated hangs or ANRs when typing into a TextInput which has a large amount of text. It is specific to the Samsung soft keyboard, and does not reproduce when using other keyboards like GBoard on the same device. There are a different set of TextInputs where we have confirmed impact depending on whether Fabric is enabled or disabled.
Fabric enabled
Both controlled and uncontrolled TextInputs are impacted.
Fabric disabled
Controlled TextInputs and uncontrolled TextInputs which set an initial value via child are impacted.
Root causing
Root causing the issue focused on:
Profiling
We saw similar results to the trace already shared in #35590. A Java sampling profiler shows the process
com.samsung.android.honeyboard
has a very long running frame, delivering input.This triggers code on the main thread, in the app process, where we see a hang happen while committing a text change from the IME to the underlying Spannable backing the EditText. The hang happens in an event handler which has subscribed to changes to the underlying text. The long-running work seems to be laying out the text.
Because the hang happens in response to an edit to the underlying Spannable, investigation focused on the Spannable content differences in scenarios which created ANRs vs not.
Spannable differences between hang/no hang
We examined typing into the below example, which may hang on Fabric but not Paper:
Grammarly annotations were present as
SuggestionSpan
spans on both platforms. On Fabric but not paper there was the presence ofAbsoluteSizeSpan
spans, which set the font size within the text. This is akin to setting<span style=”font-size: 12px”}>Text</span>
within a browser.When we stubbed out platform code in React Native which set an
AbsoluteSizeSpan
, that example along with another previously hanging example would no longer hang. The hang was possible to trigger in an uncontrolled TextInput with a short string like “Text Here” as a child, so we attempted to repro the logical extreme, where we add a single span setting font size to the TextInput.Reproducing outside of React Native
We discovered that adding even a single inclusive span (specifically setting font size) is enough to create hangs. This can reproduced by:
EditText
with aninputType
oftextMultiLine
.str.setSpan(new AbsoluteSizeSpan(55), 0, string.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE)
We were able to create a repro for this on top of a template Android application. The issue only happens when using the Samsung keyboard.
https://user-images.githubusercontent.com/835219/214149647-7dd093de-29d0-4a62-b898-579316ee1365.mp4
Grammarly annotations are not shown locally when changing the appId and namespace of the repro toThis only happened on 1/2 devices, so it's possible there might be some setting or association that wasn't fresh.com.facebook.katana
(the ID of the Facebook app). This implies the Facebook app may be being special-cased, contributing to the lack of internal signal on the issue.Remediation
While the underlying issue seems to be outside of React Native, the issue still has a real-world effect on our users. We are starting the process to mitigate the issue by working to notify Samsung. This issue has already shown signs of impacting the Android app ecosystem outside of React Native and the ability to set spans with formatting like font size is a fundamentally important part of the platform.
We hope this issue will be addressed in a future update from Samsung, but this does not address the already-present impact of the issue. A potential mitigation which we are exploring is whether React Native could avoid adding AbsoluteSizeSpan (or formatting spans in general) in more common cases.
There have been previously discovered workarounds for the issue, such as setting
keyboardType
tovisible-password
. We recommend against preemptively using these workarounds, due to impact on UX and accessibility.