fix: Android headless JS timeout (#33044)

Summary:
Fixes https://github.com/facebook/react-native/issues/33043 and thereby https://github.com/invertase/react-native-firebase/issues/3955.

The issue arised because when there currently is no available React context, `HeadlessJsTaskService` will create a new one in background and start the task using `onReactContextInitialized` of `ReactInstanceManager.addReactInstanceEventListener`.
7ef14af81f/ReactAndroid/src/main/java/com/facebook/react/HeadlessJsTaskService.java (L94-L113)
The `TimingModule` however is initialized asynchronously, meaning the headless JS is started before its initialization. That's an issue because the `TimingModule` is only run when there is JS code executing (meaning if the application is running or there is a headless task running) - this is checked by registering a `HeadlessJsTaskEventListener` on the `HeadlessJsTaskContext` in `TimingModule.initialize()`.
7ef14af81f/ReactAndroid/src/main/java/com/facebook/react/modules/core/TimingModule.java (L69-L75)
However this event listener is never invoked because the task was started before `TimingModule.initialize()` is called -> `TimingModule.onHeadlessJsTaskStart(...)` is not called and the timer never resumes.

In order to fix this we can just invoke `HeadlessJsTaskEventListener.onHeadlessJsTaskStart(...)` for all currently running tasks when a new listener is added to `HeadlessJsTaskContext`. This call then needs to be `synchronized` as otherwise there's a race condition with `HeadlessJsTaskContext.finishTask(...)` where `onHeadlessJsTaskFinish(...)` could be called before `onHeadlessJsTaskStart(...)`. See the diff for the exact changes.

## Changelog

<!-- Help reviewers and the release process by writing your own changelog entry. For an example, see:
https://github.com/facebook/react-native/wiki/Changelog
-->

[Android] [Fix] - Fixed `TimingModule` related functions for headless JS tasks, eg. `setTimeout`

Pull Request resolved: https://github.com/facebook/react-native/pull/33044

Test Plan: I did a local build with the changes and tested the provided example code from https://github.com/facebook/react-native/issues/33043 there.

Reviewed By: sshic

Differential Revision: D34006573

Pulled By: dmitryrykun

fbshipit-source-id: d6a821bbd6476ba278c1d8895edb4a0ba16d889e
This commit is contained in:
Marces Engel 2022-04-11 06:58:37 -07:00 коммит произвёл Facebook GitHub Bot
Родитель 65abc361bf
Коммит dac56ce077
1 изменённых файлов: 8 добавлений и 2 удалений

Просмотреть файл

@ -61,9 +61,15 @@ public class HeadlessJsTaskContext {
mReactContext = new WeakReference<ReactContext>(reactContext);
}
/** Register a task lifecycle event listener. */
public void addTaskEventListener(HeadlessJsTaskEventListener listener) {
/**
* Register a task lifecycle event listener. Synchronized in order to prevent race conditions with
* finishTask, as the listener will be invoked for already running tasks.
*/
public synchronized void addTaskEventListener(HeadlessJsTaskEventListener listener) {
mHeadlessJsTaskEventListeners.add(listener);
for (Integer activeTaskId : mActiveTasks) {
listener.onHeadlessJsTaskStart(activeTaskId);
}
}
/** Unregister a task lifecycle event listener. */