From b4532adad4e38e1237631778f7b8c917a9ccf746 Mon Sep 17 00:00:00 2001 From: Rodolfo Gomez Sirimarco Date: Mon, 16 Sep 2024 04:29:47 -0700 Subject: [PATCH] Fix Headless Crash `Tried to finish non-existent task with id` (#46497) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: Sometimes a headless task tries to finish, but it doesn’t exist, which causes an exception. No one knows how to reliably reproduce it, as it could be a race condition. However, if you attempt to remove a task that has already been removed, it shouldn’t cause an issue since you're trying to remove something that’s already gone (which is exactly what you want). Fixes: - https://github.com/facebook/react-native/issues/46496 - https://github.com/facebook/react-native/issues/33883 - https://github.com/facebook/react-native/issues/27597 - https://github.com/transistorsoft/react-native-background-fetch/issues/202 - https://github.com/transistorsoft/react-native-background-fetch/issues/369 - https://github.com/transistorsoft/react-native-background-geolocation/issues/2096 - https://github.com/jpush/jpush-react-native/issues/78 ## Stacktrace: ``` Fatal Exception: java.lang.AssertionError: Tried to finish non-existent task with id 28. at com.facebook.infer.annotation.Assertions.assertCondition(Assertions.java:88) at com.facebook.react.jstasks.HeadlessJsTaskContext.finishTask(HeadlessJsTaskContext.java:179) at com.facebook.react.jstasks.HeadlessJsTaskContext$3.run(HeadlessJsTaskContext.java:217) at android.os.Handler.handleCallback(Handler.java:958) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loopOnce(Looper.java:257) at android.os.Looper.loop(Looper.java:368) at com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run(MessageQueueThreadImpl.java:233) at java.lang.Thread.run(Thread.java:1012) ``` ## Screenshot https://github.com/user-attachments/assets/101f0f53-95c9-40ec-a59d-22d6d474b457 ## Changelog: [ANDROID] [FIXED] - Fix Headless Crash `Tried to finish non-existent task with id` Pull Request resolved: https://github.com/facebook/react-native/pull/46497 Test Plan: I created an example where I attempt to remove a task that doesn’t exist. Example: https://github.com/RodolfoGS/react-native-fix-non-existent-task ### How to reproduce using the example above: 1. `git clone git@github.com:RodolfoGS/react-native-fix-non-existent-task.git` 2. `cd react-native-fix-non-existent-task` 3. `npm install` 4. `npm run android` 5. Notice the crash ### Steps to create the example from scratch and reproduce the crash: 1. `npx react-native-community/cli@latest init AwesomeProject` 2. `cd AwesomeProject` 3. Add call to finishTask to reproduce the crash (https://github.com/RodolfoGS/react-native-fix-non-existent-task/commit/6fe3c1388a58b9ffdcca5f9c6f00a4f2fea725ea) 4. `npm run android` 5. Notice the crash Reviewed By: javache Differential Revision: D62738059 Pulled By: rshest fbshipit-source-id: 3232dc76ba8a069279c2b741d62372537a3f9140 --- .../react/jstasks/HeadlessJsTaskContext.java | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/jstasks/HeadlessJsTaskContext.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/jstasks/HeadlessJsTaskContext.java index e4350d34cd9645..00ea6098d6305e 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/jstasks/HeadlessJsTaskContext.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/jstasks/HeadlessJsTaskContext.java @@ -169,26 +169,25 @@ public void run() { /** * Finish a JS task. Doesn't actually stop the task on the JS side, only removes it from the list - * of active tasks and notifies listeners. A task can only be finished once. + * of active tasks and notifies listeners. * * @param taskId the unique id returned by {@link #startTask}. */ public synchronized void finishTask(final int taskId) { - Assertions.assertCondition( - mActiveTasks.remove(taskId), "Tried to finish non-existent task with id " + taskId + "."); - Assertions.assertCondition( - mActiveTaskConfigs.remove(taskId) != null, - "Tried to remove non-existent task config with id " + taskId + "."); + boolean removed = mActiveTasks.remove(taskId); + mActiveTaskConfigs.remove(taskId); removeTimeout(taskId); - UiThreadUtil.runOnUiThread( - new Runnable() { - @Override - public void run() { - for (HeadlessJsTaskEventListener listener : mHeadlessJsTaskEventListeners) { - listener.onHeadlessJsTaskFinish(taskId); + if (removed) { + UiThreadUtil.runOnUiThread( + new Runnable() { + @Override + public void run() { + for (HeadlessJsTaskEventListener listener : mHeadlessJsTaskEventListeners) { + listener.onHeadlessJsTaskFinish(taskId); + } } - } - }); + }); + } } private void removeTimeout(int taskId) {