Skip to content

🐞[Android] NullPointerException: Attempt to read from field 'java.lang.String io.flutter.embedding.engine.loader.FlutterApplicationInfo.flutterAssetsDir' on a null object #671

@absar

Description

@absar
  • I have read the README
  • I have done the setup for Android
  • I have done the setup for iOS
  • I have ran the sample app and it does not work there

Version

Technology Version
Workmanager version 0.9.0+3
Workmanager Android 0.9.0+2
Xcode version
Swift version
iOS deployment target

Describe the error
On Android when a WorkManager background job and the main app Activity start at the same time (e.g. process killed from recents, then both triggered simultaneously), the app crashes however the background job completes. Most probably BackgroundWorker companion FlutterLoader causes NullPointerException crash when app and WorkManager job start simultaneously:

java.lang.NullPointerException: Attempt to read from field 'java.lang.String io.flutter.embedding.engine.loader.FlutterApplicationInfo.flutterAssetsDir' on a null object reference in method
'java.lang.String io.flutter.embedding.engine.loader.FlutterLoader.findAppBundlePath()'
at FlutterActivityAndFragmentDelegate.addEntrypointOptions
at FlutterActivityAndFragmentDelegate.setUpFlutterEngine

Followed by warnings then work completion:

W/FlutterJNI: FlutterJNI.loadLibrary called more than once
W/FlutterJNI: FlutterJNI.init called more than once
I/WM-WorkerWrapper: Worker result SUCCESS for Work [ id=8b5a5aa4-4b14-4f99-b964-a1713ba64d42, tags={ dev.fluttercommunity.workmanager.BackgroundWorker } ]
D/WM-Processor: Processor 8b5a5aa4-4b14-4f99-b964-a1713ba64d42 executed; reschedule = false
D/WM-GreedyScheduler: Cancelling work ID 8b5a5aa4-4b14-4f99-b964-a1713ba64d42
D/WM-SystemJobScheduler: Scheduling work ID 8b5a5aa4-4b14-4f99-b964-a1713ba64d42Job ID 184

Probably this is whats happening: BackgroundWorker.companion holds private val flutterLoader = FlutterLoader(). The FlutterLoader() no-arg constructor internally calls FlutterInjector.instance(), which creates and locks the injector singleton as a side effect and produces a second FlutterLoader instance separate from FlutterInjector.instance().flutterLoader(). The worker initializes its own companion loader, but FlutterEngine(applicationContext) and the main app's FlutterActivityAndFragmentDelegate both use the injector's loader. In a race between the job and the app launch, the injector's loader can reach findAppBundlePath() before startInitialization() has been called on it, producing the NPE. Because ListenableWorker.startWork() runs on the main thread, the ordering of these two initializations is non-deterministic at process start.

Affected scenarios: App killed → WorkManager job fires → user opens app simultaneously or vice versa; any scenario where process starts fresh with a pending job and UI together.

Platform: Android only. Unfortunately, this issue is very difficult to reproduce because accurately timing the background job execution with app startup is nearly impossible. However, I have observed it multiple times on an emulator. The pattern was that the emulator had not been used for several days then started the emulator, and when I launched the app from Android Studio, the app appeared briefly for about a second, then immediately disappeared. Right after that, the background job executed logs for the same appended below. It is affecting multiple users on different devices in production.

Complete logs on Emulator:

D/FlutterJNI: Beginning load of flutter...
D/FlutterJNI: flutter (null) was loaded normally!
E/AndroidRuntime: FATAL EXCEPTION: main
E/AndroidRuntime: Process: com.abc.redacted, PID: 11233
E/AndroidRuntime: java.lang.NullPointerException: Attempt to read from field 'java.lang.String io.flutter.embedding.engine.loader.FlutterApplicationInfo.flutterAssetsDir' on a null object reference in method 'java.lang.String io.flutter.embedding.engine.loader.FlutterLoader.findAppBundlePath()'
E/AndroidRuntime: 	at io.flutter.embedding.engine.loader.FlutterLoader.findAppBundlePath(FlutterLoader.java:615)
E/AndroidRuntime: 	at io.flutter.embedding.android.FlutterActivityAndFragmentDelegate.addEntrypointOptions(FlutterActivityAndFragmentDelegate.java:244)
E/AndroidRuntime: 	at io.flutter.embedding.android.FlutterActivityAndFragmentDelegate.setUpFlutterEngine(FlutterActivityAndFragmentDelegate.java:340)
E/AndroidRuntime: 	at io.flutter.embedding.android.FlutterActivityAndFragmentDelegate.onAttach(FlutterActivityAndFragmentDelegate.java:197)
E/AndroidRuntime: 	at io.flutter.embedding.android.FlutterFragment.onAttach(FlutterFragment.java:1060)
E/AndroidRuntime: 	at androidx.fragment.app.Fragment.performAttach(Fragment.java:3075)
E/AndroidRuntime: 	at androidx.fragment.app.FragmentStateManager.attach(FragmentStateManager.java:510)
E/AndroidRuntime: 	at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:279)
E/AndroidRuntime: 	at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2214)
E/AndroidRuntime: 	at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:2109)
E/AndroidRuntime: 	at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:2052)
E/AndroidRuntime: 	at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3327)
E/AndroidRuntime: 	at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:3237)
E/AndroidRuntime: 	at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:263)
E/AndroidRuntime: 	at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:350)
E/AndroidRuntime: 	at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1696)
E/AndroidRuntime: 	at android.app.Activity.performStart(Activity.java:9198)
E/AndroidRuntime: 	at android.app.ActivityThread.handleStartActivity(ActivityThread.java:4305)
E/AndroidRuntime: 	at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:214)
E/AndroidRuntime: 	at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:194)
E/AndroidRuntime: 	at android.app.servertransaction.TransactionExecutor.executeLifecycleItem(TransactionExecutor.java:166)
E/AndroidRuntime: 	at android.app.servertransaction.TransactionExecutor.executeTransactionItems(TransactionExecutor.java:101)
E/AndroidRuntime: 	at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:80)
E/AndroidRuntime: 	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2823)
E/AndroidRuntime: 	at android.os.Handler.dispatchMessage(Handler.java:110)
E/AndroidRuntime: 	at android.os.Looper.loopOnce(Looper.java:248)
E/AndroidRuntime: 	at android.os.Looper.loop(Looper.java:338)
E/AndroidRuntime: 	at android.app.ActivityThread.main(ActivityThread.java:9067)
E/AndroidRuntime: 	at java.lang.reflect.Method.invoke(Native Method)
E/AndroidRuntime: 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:593)
E/AndroidRuntime: 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:932)
D/FlutterJNI: Beginning load of flutter...
D/FlutterJNI: flutter (null) was loaded normally!
I/flutter : [IMPORTANT:flutter/shell/platform/android/android_context_gl_impeller.cc(104)] Using the Impeller rendering backend (OpenGLES).
W/FlutterJNI: FlutterJNI.loadLibrary called more than once
D/FlutterJNI: Beginning load of flutter...
D/FlutterJNI: flutter (null) was loaded normally!
W/FlutterJNI: FlutterJNI.prefetchDefaultFontManager called more than once
W/FlutterJNI: FlutterJNI.init called more than once
Syncing files to device sdk gphone64 x86 64...
I/DynamiteModule: Considering local module com.google.android.gms.cronet_dynamite:0 and remote module com.google.android.gms.cronet_dynamite:4311
I/DynamiteModule: Selected remote version of com.google.android.gms.cronet_dynamite, version >= 4311
V/DynamiteModule: Dynamite loader version >= 2, using loadModule2NoCrashUtils
W/om.abc.redacted: ClassLoaderContext classpath element checksum mismatch. expected=162677756, found=1402994959 (DLC[];PCL[base.apk*162677756]{PCL[/system/framework/org.apache.http.legacy.jar*4247870504]#PCL[/system/framework/com.android.location.provider.jar*1570284764]#PCL[/system/framework/com.android.media.remotedisplay.jar*487574312]#PCL[/system_ext/framework/androidx.window.extensions.jar*1030441313]#PCL[/system_ext/framework/androidx.window.sidecar.jar*3860983653]} | DLC[];PCL[/data/app/~~kIPQ58LhNa75MlW_2Pqrpw==/com.abc.redacted-aDuszTJdKUXcioUv_ZYoNQ==/base.apk*1402994959]{PCL[/system_ext/framework/androidx.window.extensions.jar*1030441313]#PCL[/system_ext/framework/androidx.window.sidecar.jar*3860983653]})
I/om.abc.redacted: AssetManager2(0x7590db640cf8) locale list changing from [] to [en-US]
I/WM-WorkerWrapper: Worker result SUCCESS for Work [ id=8b5a5aa4-4b14-4f99-b964-a1713ba64d42, tags={ dev.fluttercommunity.workmanager.BackgroundWorker } ]
D/WM-Processor: Processor 8b5a5aa4-4b14-4f99-b964-a1713ba64d42 executed; reschedule = false
D/WM-GreedyScheduler: Cancelling work ID 8b5a5aa4-4b14-4f99-b964-a1713ba64d42
D/WM-SystemJobScheduler: Scheduling work ID 8b5a5aa4-4b14-4f99-b964-a1713ba64d42Job ID 184

Logs from live devices on Flutter 3.41.9

Fatal Exception: java.lang.NullPointerException: Attempt to read from field 'java.lang.String bb.b.b' on a null object reference in method 'void wa.c.a(io.flutter.embedding.engine.b$b)'
       at io.flutter.embedding.engine.loader.FlutterLoader.findAppBundlePath(FlutterLoader.java:615)
       at io.flutter.embedding.android.FlutterActivityAndFragmentDelegate.addEntrypointOptions(FlutterActivityAndFragmentDelegate.java:244)
       at io.flutter.embedding.android.FlutterActivityAndFragmentDelegate.setUpFlutterEngine(FlutterActivityAndFragmentDelegate.java:340)
       at io.flutter.embedding.android.FlutterActivityAndFragmentDelegate.onAttach(FlutterActivityAndFragmentDelegate.java:197)
       at io.flutter.embedding.android.FlutterFragment.onAttach(FlutterFragment.java:1058)
       at androidx.fragment.app.Fragment.performAttach(Fragment.java:3075)
       at androidx.fragment.app.FragmentStateManager.attach(FragmentStateManager.java:510)
       at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:279)
       at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2214)
       at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:2109)
       at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:2052)
       at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3327)
       at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:3237)
       at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:263)
       at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:350)
       at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1455)
       at android.app.Activity.performStart(Activity.java:8195)
       at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3805)
       at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:221)
       at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:201)
       at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:173)
       at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2325)
       at android.os.Handler.dispatchMessage(Handler.java:106)
       at android.os.Looper.loopOnce(Looper.java:210)
       at android.os.Looper.loop(Looper.java:299)
       at android.app.ActivityThread.main(ActivityThread.java:8280)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:576)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1073)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions