Fix HeadlessJsTaskContext creating Handler on background thread (#44582)

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

D54496604 fixed lifecycle methods for JavaTimerManager, which now reveals another bug. Because this codepath ends up creating a `HeadlessJsTaskContext` which in turn creates a `Handler`, ReactInstance destruction doesn't complete cleanly.

```
2024-05-15 17:42:52.935 12681 27113 W fb4a.BridgelessReact: ReactHost{1}.getOrCreateDestroyTask(): React destruction failed. ReactInstance task faulted. Fault reason: Can't create handler inside thread Thread[pool-51-thread-1,5,main] that has not called Looper.prepare(). Destroy reason: FbReactInstanceHolder.destroyReactManager(): FbReactInstanceLogoutCleaner.clearReactInstanceData()
```

The fix is to not create our own Handler, but instead use the shared methods in UiThreadUtil.

Changelog: [Android][Fixed] Fixed error thrown during ReactInstance teardown

Reviewed By: cortinico

Differential Revision: D57378247

fbshipit-source-id: a31dc8e35b5418a71b83c301973f12350f2ee01b
This commit is contained in:
Pieter De Baets
2024-05-21 06:37:28 -07:00
committed by Facebook GitHub Bot
parent fd8eb4878b
commit e67d5560cf
@@ -7,7 +7,6 @@
package com.facebook.react.jstasks;
import android.os.Handler;
import android.util.SparseArray;
import com.facebook.infer.annotation.Assertions;
import com.facebook.react.bridge.ReactContext;
@@ -52,7 +51,6 @@ public class HeadlessJsTaskContext {
private final Set<HeadlessJsTaskEventListener> mHeadlessJsTaskEventListeners =
new CopyOnWriteArraySet<>();
private final AtomicInteger mLastTaskId = new AtomicInteger(0);
private final Handler mHandler = new Handler();
private final Set<Integer> mActiveTasks = new CopyOnWriteArraySet<>();
private final Map<Integer, HeadlessJsTaskConfig> mActiveTaskConfigs = new ConcurrentHashMap<>();
private final SparseArray<Runnable> mTaskTimeouts = new SparseArray<>();
@@ -194,9 +192,9 @@ public class HeadlessJsTaskContext {
}
private void removeTimeout(int taskId) {
Runnable timeout = mTaskTimeouts.get(taskId);
if (timeout != null) {
mHandler.removeCallbacks(timeout);
Runnable runnable = mTaskTimeouts.get(taskId);
if (runnable != null) {
UiThreadUtil.removeOnUiThread(runnable);
mTaskTimeouts.remove(taskId);
}
}
@@ -210,14 +208,8 @@ public class HeadlessJsTaskContext {
}
private void scheduleTaskTimeout(final int taskId, long timeout) {
Runnable runnable =
new Runnable() {
@Override
public void run() {
finishTask(taskId);
}
};
Runnable runnable = () -> finishTask(taskId);
mTaskTimeouts.append(taskId, runnable);
mHandler.postDelayed(runnable, timeout);
UiThreadUtil.runOnUiThread(runnable, timeout);
}
}