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(Android,Fabric,bridgeless): crash on RN hot reload in dev mode when redbox in presentation #2289

Merged
merged 3 commits into from
Aug 9, 2024

Conversation

kkafar
Copy link
Member

@kkafar kkafar commented Aug 7, 2024

Description

There was a crash on Android + Fabric + bridgeless:

  1. trigger a redbox by triggering some JS error (e.g. call a method that does not exist),
  2. fast refresh react-native,
  3. see the crash in onHostResume.

The application crashed because we had a check for not null activity in reactContext.
However after such reload ReactContext is recreated with null activity!!!.

In such case, when we don't have access to the activity, we're currently unable to create the dummy layout,
so the best we can do is not fail. The fix for jumping layout won't work, however.

This PR also adds synchornization on synchornied block in maybeInitDummyLayoutWithHeaderMethod, which should prevent
a possible data race, where both threads could try to create dummy layout simmultaneously.

Changes

  • Do not fail in onHostResume when there is no activity present in the provided context,
  • only log a warning in the described case,
  • synchronize layout initialisation, so that there is no data race <- I'm not sure it was real due to JVM atomicity guarantees, however this time I prefer the "better safe than sorry" approach,
  • mark isLayoutInitialized variable as Volatile, to ensure that updates from one thread are visible on the other thread.

Test code and steps to reproduce

Desribed above ^ in the "Description" section.

Checklist

  • Ensured that CI passes

@kkafar kkafar requested a review from WoLewicki August 7, 2024 16:11
if (!reactContext.hasCurrentActivity()) {
return false
}

// We need to use activity here, as react context does not have theme attributes required by
// AppBarLayout attached leading to crash.
val contextWithTheme =
requireNotNull(reactContext.currentActivity) { "[RNScreens] Attempt to use context detached from activity" }
requireNotNull(reactContext.currentActivity) { "[RNScreens] Attempt to use context detached from activity. This could happen only due to race-condition." }
Copy link
Member

Choose a reason for hiding this comment

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

Why aren't you using reactContextRef everywhere?

Copy link
Member Author

@kkafar kkafar Aug 8, 2024

Choose a reason for hiding this comment

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

@WoLewicki this method takes reactContext: ReactApplicationContext as a parameter, there is no point of using the reactContextRef field here. It makes more sense for me to take this as parameter, because:

  1. this method requires nonnull react context to do anything,
  2. moving context validation out of the method allows to throw better error messages which are tailored to specific code path & context, see e.g. onHostResume method;
  3. during package initialisation I do have direct access to reactContext (of non-nullable type), thus can pass it directly / omit checks in the method itself.

Copy link
Member Author

@kkafar kkafar Aug 8, 2024

Choose a reason for hiding this comment

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

I do not see any advantages of using reactContextRef directly. I do need to sanitise the reference anyway in almost all cases, because I do want to throw / log an message everytime reactContextRef.get() == null & it is unexpected.

@kkafar kkafar merged commit 4c22ef1 into main Aug 9, 2024
4 checks passed
@kkafar kkafar deleted the @kkafar/fabric-bridgefull-reload branch August 9, 2024 07:06
ja1ns pushed a commit to WiseOwlTech/react-native-screens that referenced this pull request Oct 9, 2024
…en redbox in presentation (software-mansion#2289)

## Description

There was a crash on Android + Fabric + bridgeless:

1. trigger a redbox by triggering some JS error (e.g. call a method that
does not exist),
2. fast refresh react-native,
3. see the crash in `onHostResume`.

The application crashed because we had a check for not null activity in
reactContext.
However after such reload ReactContext is recreated with null
activity!!!.

In such case, when we don't have access to the activity, we're currently
unable to create the dummy layout,
so the best we can do is not fail. The fix for jumping layout won't
work, however.

This PR also adds synchornization on `synchornied` block in
`maybeInitDummyLayoutWithHeaderMethod`, which should prevent
a possible data race, where both threads could try to create dummy
layout simmultaneously.

## Changes

* Do not fail in `onHostResume` when there is no activity present in the
provided context,
* only log a warning in the described case,
* synchronize layout initialisation, so that there is no data race <-
I'm not sure it was real due to JVM atomicity guarantees, however this
time I prefer the "better safe than sorry" approach,
* mark `isLayoutInitialized` variable as `Volatile`, to ensure that
updates from one thread are visible on the other thread.


## Test code and steps to reproduce

Desribed above ^ in the "Description" section.

## Checklist

- [ ] Ensured that CI passes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants