Android framework version
net11.0-android (Preview)
Affected platform version
VS 2026 Insider [11626.173
Description
.NET 11 Android: Release crash “callback on a garbage collected delegate” with Application + ProcessLifecycleOwner + [Export] lifecycle callbacks.
• Project: single-activity, long-lived commercial .NET for Android app
• Runtime configuration:
• Crash occurs with the default new .NET runtime (UseMonoRuntime not set / false).
• Crash does not occur with UseMonoRuntime=true.
In my Application subclass:
• I implement ILifecycleObserver.
• In OnCreate I register the Application instance with ProcessLifecycleOwner:
public override void OnCreate() { base.OnCreate();
{
// ... Firebase init, etc. ...
ProcessLifecycleOwner.Get().Lifecycle.AddObserver(this);
canCallFinish = true;
appBackGrounded = false;
}
• I use Export + Lifecycle.Event attributes on two methods to detect process-level background/foreground:
[Export, Lifecycle.Event.OnStop] [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "<Pending>")] public void OnAppBackgrounded() { appBackGrounded = true; Log.Debug(logTag, $"{logTag} OnAppBackgrounded is {appBackGrounded}"); }
[Export, Lifecycle.Event.OnResume] [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "<Pending>")] public void OnAppForegrounded() { appBackGrounded = false; Log.Debug(logTag, $"{logTag} OnAppBackgrounded is {appBackGrounded}"); }
The merged AndroidManifest already contains the AndroidX Startup metadata:
<meta-data
android:name="androidx.lifecycle.ProcessLifecycleInitializer"
android:value="androidx.startup" />
So ProcessLifecycleOwner is properly initialized by AndroidX.
This Application + ProcessLifecycleOwner pattern is used so that my OBD Service can continue logging data seamlessly while the app transitions between foreground and background (e.g. user is driving, gets a phone call, app goes to background, then returns). On .NET 9 / .NET 10 this has worked correctly; log files and a video submitted to Google Play Console (for a permission review, likely FOREGROUND_SERVICE or FOREGROUND_SERVICE_CONNECTED_DEVICE) show that there are no gaps in timestamps while switching between my app and another (e.g. Gmail).
Behaviour across runtimes
- .NET 9 / .NET 10 (Mono-based pipeline)
• Same Application + ProcessLifecycleOwner + Exported lifecycle callbacks.
• No crash in Release.
• Background/foreground behaviour as intended; OBD logging continues while app is backgrounded and resumes cleanly.
- .NET 11 Preview 2, new .NET runtime (default, UseMonoRuntime not set)
• Target: net11.0-android36.1.
• If the code above is enabled (observer registration + Export/Lifecycle.Event attributes), a Release build crashes immediately on startup with:
DOTNET: Process terminated.
DOTNET: A callback was made on a garbage collected delegate of type 'callback_factory!callback_delegate__V::Invoke'.
DOTNET: Aborting process.
• If I ONLY comment out:
• ProcessLifecycleOwner.Get().Lifecycle.AddObserver(this); and
• the [Export, Lifecycle.Event.OnStop] / [Export, Lifecycle.Event.OnResume] attributes,
leaving everything else (including my OBD lib) unchanged, then:
• The same net11.0-android36.1 Release build runs successfully on both devices.
• The DOTNET “callback was made on a garbage collected delegate of type 'callback_factory!callback_delegate__V::Invoke'” error does not occur.
- .NET 11 Preview 2, Mono runtime (UseMonoRuntime=true)
• In my csproj I set:
<EnablePreviewFeatures>false</EnablePreviewFeatures>
<UseMonoRuntime>true</UseMonoRuntime>
• With these properties:
• I leave ProcessLifecycleOwner.Get().Lifecycle.AddObserver(this) and the Exported lifecycle callbacks fully enabled.
• Release builds no longer crash on startup; behaviour matches my net10 version for background logging and process lifecycle.
• The build output again shows the familiar “dll -> dll.so” list, as expected with the Mono pipeline.
• The “callback on a garbage collected delegate” error does not occur.
Notes on application code
• My OBD library is a managed library plus Android bindings:
• No P/Invoke, no UnmanagedFunctionPointer.
• It uses events, SynchronizationContext, and Java bindings, but does not explicitly hand delegates to native code.
• The only obvious “reverse callback” glue that matches the error message (callback_factory!callback_delegate__V::Invoke) is generated by the Export + Lifecycle.Event attributes on the Application subclass.
Given that:
• The pattern works on net9/net10.
• It works on net11 when forcing the Mono runtime.
• It fails only with the new .NET runtime path, and only when ProcessLifecycleOwner + Exported lifecycle callbacks on Application are enabled.
This strongly suggests a regression in the .NET 11 Android runtime’s implementation of these lifecycle callbacks (i.e. the callback_factory path and its delegate lifetime management), rather than in my OBD code.
Expected vs actual
Expected:
• Using Application + ProcessLifecycleOwner + Export + Lifecycle.Event callbacks should work on net11 the same way it does on net9/net10 and on net11 with UseMonoRuntime=true:
• No crash in Release.
• Lifecycle callbacks invoked as the process enters/leaves the foreground.
• Delegates used for these callbacks should not be garbage collected while AndroidX still holds references to them.
Actual:
• On .NET 11 Preview 2, using the new .NET runtime path:
• Release builds crash immediately on startup with “A callback was made on a garbage collected delegate of type 'callback_factory!callback_delegate__V::Invoke'” when the Application is registered with ProcessLifecycleOwner and has Exported lifecycle callbacks.
• Commenting out only the observer registration and the two Export attributes removes the crash.
• Forcing the Mono runtime (UseMonoRuntime=true) also removes the crash, even with the original lifecycle code enabled.
Request
• Please confirm whether this pattern (Application subclass + ProcessLifecycleOwner + [Export, Lifecycle.Event.OnStop/OnResume]) is expected to work with the new .NET runtime on Android in .NET 11.
• If so, this appears to be a runtime regression:
• It would be helpful to know whether this is a known issue, and if there is a plan to fix it in a future .NET 11 preview / RC / GA release.
• If this is not a pattern you intend to support with the new runtime:
• Some guidance on the recommended alternative would be appreciated (e.g. using a separate ILifecycleObserver class with Exported methods instead of hanging them off Application, or preferring Activity-level lifecycle for this scenario).
This issue is related to, but separate from, my R8 tooling issue tracked in #11030:
• #11030 covers the R8 command-line length problem and the desire to have the “use response file” fix backported to .NET 10.
• This new issue is specifically about the .NET 11 Android runtime crash in the lifecycle callback glue when using ProcessLifecycleOwner with Exported callbacks on Application.
Steps to Reproduce
N/A
Did you find any workaround?
No
Relevant log output
Android framework version
net11.0-android (Preview)
Affected platform version
VS 2026 Insider [11626.173
Description
.NET 11 Android: Release crash “callback on a garbage collected delegate” with Application + ProcessLifecycleOwner + [Export] lifecycle callbacks.
• Project: single-activity, long-lived commercial .NET for Android app
• Runtime configuration:
• Crash occurs with the default new .NET runtime (UseMonoRuntime not set / false).
• Crash does not occur with UseMonoRuntime=true.
In my Application subclass:
• I implement ILifecycleObserver.
• In OnCreate I register the Application instance with ProcessLifecycleOwner:
• I use Export + Lifecycle.Event attributes on two methods to detect process-level background/foreground:
The merged AndroidManifest already contains the AndroidX Startup metadata:
So ProcessLifecycleOwner is properly initialized by AndroidX.
This Application + ProcessLifecycleOwner pattern is used so that my OBD Service can continue logging data seamlessly while the app transitions between foreground and background (e.g. user is driving, gets a phone call, app goes to background, then returns). On .NET 9 / .NET 10 this has worked correctly; log files and a video submitted to Google Play Console (for a permission review, likely FOREGROUND_SERVICE or FOREGROUND_SERVICE_CONNECTED_DEVICE) show that there are no gaps in timestamps while switching between my app and another (e.g. Gmail).
Behaviour across runtimes
• Same Application + ProcessLifecycleOwner + Exported lifecycle callbacks.
• No crash in Release.
• Background/foreground behaviour as intended; OBD logging continues while app is backgrounded and resumes cleanly.
• Target: net11.0-android36.1.
• If the code above is enabled (observer registration + Export/Lifecycle.Event attributes), a Release build crashes immediately on startup with:
DOTNET: Process terminated.
DOTNET: A callback was made on a garbage collected delegate of type 'callback_factory!callback_delegate__V::Invoke'.
DOTNET: Aborting process.
• If I ONLY comment out:
• ProcessLifecycleOwner.Get().Lifecycle.AddObserver(this); and
• the [Export, Lifecycle.Event.OnStop] / [Export, Lifecycle.Event.OnResume] attributes,
leaving everything else (including my OBD lib) unchanged, then:
• The same net11.0-android36.1 Release build runs successfully on both devices.
• The DOTNET “callback was made on a garbage collected delegate of type 'callback_factory!callback_delegate__V::Invoke'” error does not occur.
• In my csproj I set:
• With these properties:
• I leave ProcessLifecycleOwner.Get().Lifecycle.AddObserver(this) and the Exported lifecycle callbacks fully enabled.
• Release builds no longer crash on startup; behaviour matches my net10 version for background logging and process lifecycle.
• The build output again shows the familiar “dll -> dll.so” list, as expected with the Mono pipeline.
• The “callback on a garbage collected delegate” error does not occur.
Notes on application code
• My OBD library is a managed library plus Android bindings:
• No P/Invoke, no UnmanagedFunctionPointer.
• It uses events, SynchronizationContext, and Java bindings, but does not explicitly hand delegates to native code.
• The only obvious “reverse callback” glue that matches the error message (callback_factory!callback_delegate__V::Invoke) is generated by the Export + Lifecycle.Event attributes on the Application subclass.
Given that:
• The pattern works on net9/net10.
• It works on net11 when forcing the Mono runtime.
• It fails only with the new .NET runtime path, and only when ProcessLifecycleOwner + Exported lifecycle callbacks on Application are enabled.
This strongly suggests a regression in the .NET 11 Android runtime’s implementation of these lifecycle callbacks (i.e. the callback_factory path and its delegate lifetime management), rather than in my OBD code.
Expected vs actual
Expected:
• Using Application + ProcessLifecycleOwner + Export + Lifecycle.Event callbacks should work on net11 the same way it does on net9/net10 and on net11 with UseMonoRuntime=true:
• No crash in Release.
• Lifecycle callbacks invoked as the process enters/leaves the foreground.
• Delegates used for these callbacks should not be garbage collected while AndroidX still holds references to them.
Actual:
• On .NET 11 Preview 2, using the new .NET runtime path:
• Release builds crash immediately on startup with “A callback was made on a garbage collected delegate of type 'callback_factory!callback_delegate__V::Invoke'” when the Application is registered with ProcessLifecycleOwner and has Exported lifecycle callbacks.
• Commenting out only the observer registration and the two Export attributes removes the crash.
• Forcing the Mono runtime (UseMonoRuntime=true) also removes the crash, even with the original lifecycle code enabled.
Request
• Please confirm whether this pattern (Application subclass + ProcessLifecycleOwner + [Export, Lifecycle.Event.OnStop/OnResume]) is expected to work with the new .NET runtime on Android in .NET 11.
• If so, this appears to be a runtime regression:
• It would be helpful to know whether this is a known issue, and if there is a plan to fix it in a future .NET 11 preview / RC / GA release.
• If this is not a pattern you intend to support with the new runtime:
• Some guidance on the recommended alternative would be appreciated (e.g. using a separate ILifecycleObserver class with Exported methods instead of hanging them off Application, or preferring Activity-level lifecycle for this scenario).
This issue is related to, but separate from, my R8 tooling issue tracked in #11030:
• #11030 covers the R8 command-line length problem and the desire to have the “use response file” fix backported to .NET 10.
• This new issue is specifically about the .NET 11 Android runtime crash in the lifecycle callback glue when using ProcessLifecycleOwner with Exported callbacks on Application.
Steps to Reproduce
N/A
Did you find any workaround?
No
Relevant log output