Skip to content

[android] fix Aspire integration / env vars#32119

Closed
jonathanpeppers wants to merge 1 commit intonet10.0from
dev/peppers/fix-android-env-vars
Closed

[android] fix Aspire integration / env vars#32119
jonathanpeppers wants to merge 1 commit intonet10.0from
dev/peppers/fix-android-env-vars

Conversation

@jonathanpeppers
Copy link
Member

I was trying to run a dotnet new maui project in .NET 10 RC 2, which crashed with:

10-21 14:14:34.785 14069 14069 E AndroidRuntime: FATAL EXCEPTION: main
10-21 14:14:34.785 14069 14069 E AndroidRuntime: Process: com.companyname.hellomaui, PID: 14069
10-21 14:14:34.785 14069 14069 E AndroidRuntime: android.runtime.JavaProxyThrowable: [System.IndexOutOfRangeException]: Arg_IndexOutOfRangeException
10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at Microsoft.Maui.Hosting.AppHostBuilderExtensions+<>c.<ConfigureEnvironmentVariables>b__2_2 + 0x0(Unknown Source)
10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at System.Linq.Enumerable.ToDictionary + 0x8c(Unknown Source)
10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at System.Linq.Enumerable.ToDictionary + 0x0(Unknown Source)
10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at Microsoft.Maui.Hosting.AppHostBuilderExtensions.ConfigureEnvironmentVariables + 0x5a(Unknown Source)
10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at Microsoft.Maui.Hosting.MauiAppBuilder..ctor + 0x12e(Unknown Source)
10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at Microsoft.Maui.Hosting.MauiApp.CreateBuilder + 0x0(Unknown Source)
10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at hellomaui.MauiProgram.CreateMauiApp + 0x0(Unknown Source)
10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at hellomaui.MainApplication.CreateMauiApp + 0x0(Unknown Source)
10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at Microsoft.Maui.MauiApplication.OnCreate + 0xb(Unknown Source)
10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at Android.App.Application.n_OnCreate + 0x16(Unknown Source)
10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at crc6488302ad6e9e4df1a.MauiApplication.n_onCreate(Native Method)
10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at crc6488302ad6e9e4df1a.MauiApplication.onCreate(MauiApplication.java:17)
10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1381)
10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at android.app.ActivityThread.handleBindApplication(ActivityThread.java:7830)
10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at android.app.ActivityThread.-$$Nest$mhandleBindApplication(Unknown Source:0)
10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2546)
10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at android.os.Handler.dispatchMessage(Handler.java:110)
10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at android.os.Looper.loopOnce(Looper.java:248)
10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at android.os.Looper.loop(Looper.java:338)
10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at android.app.ActivityThread.main(ActivityThread.java:9067)
10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at java.lang.reflect.Method.invoke(Native Method)
10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:593)
10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:932)

I reviewed the existing code:

var envVarLines = System.IO.File.ReadAllLines(androidEnvVarFilePath);
var fileEnvironmentVariables = envVarLines
.Select(line => line.Split('=', 2))
.ToDictionary(parts => parts[0], parts => parts[1]);

Which made me look at the contents of:

> adb pull /data/local/tmp/ide-launchenv.txt
/data/local/tmp/ide-launchenv.txt: 1 file pulled, 0 skipped. 0.0 MB/s (3 bytes in 0.002s)

The file contains a line with a space character two newlines. No idea what put that there?!?

I think the Select(line => line.Split('=', 2)) call is problematic, in addition to the ToDictionary() call. I think both of these could throw exceptions on malformed / weird files.

I also got "nerd sniped" to improve the performance:

  • System.IO.File.ReadAllLines() allocates a string[]

  • line.Split('=', 2) allocates a string[]

  • ToDictionary(...) allocates a dictionary and enumerates everything again.

We can just flatten the System.Linq usage here into a foreach loop and avoid those allocations. We can also use IndexOf('=') to find the split point.

After these changes, the app no longer crashes and starts up fine.

I was trying to run a `dotnet new maui` project in .NET 10 RC 2, which
crashed with:

    10-21 14:14:34.785 14069 14069 E AndroidRuntime: FATAL EXCEPTION: main
    10-21 14:14:34.785 14069 14069 E AndroidRuntime: Process: com.companyname.hellomaui, PID: 14069
    10-21 14:14:34.785 14069 14069 E AndroidRuntime: android.runtime.JavaProxyThrowable: [System.IndexOutOfRangeException]: Arg_IndexOutOfRangeException
    10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at Microsoft.Maui.Hosting.AppHostBuilderExtensions+<>c.<ConfigureEnvironmentVariables>b__2_2 + 0x0(Unknown Source)
    10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at System.Linq.Enumerable.ToDictionary + 0x8c(Unknown Source)
    10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at System.Linq.Enumerable.ToDictionary + 0x0(Unknown Source)
    10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at Microsoft.Maui.Hosting.AppHostBuilderExtensions.ConfigureEnvironmentVariables + 0x5a(Unknown Source)
    10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at Microsoft.Maui.Hosting.MauiAppBuilder..ctor + 0x12e(Unknown Source)
    10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at Microsoft.Maui.Hosting.MauiApp.CreateBuilder + 0x0(Unknown Source)
    10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at hellomaui.MauiProgram.CreateMauiApp + 0x0(Unknown Source)
    10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at hellomaui.MainApplication.CreateMauiApp + 0x0(Unknown Source)
    10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at Microsoft.Maui.MauiApplication.OnCreate + 0xb(Unknown Source)
    10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at Android.App.Application.n_OnCreate + 0x16(Unknown Source)
    10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at crc6488302ad6e9e4df1a.MauiApplication.n_onCreate(Native Method)
    10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at crc6488302ad6e9e4df1a.MauiApplication.onCreate(MauiApplication.java:17)
    10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1381)
    10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at android.app.ActivityThread.handleBindApplication(ActivityThread.java:7830)
    10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at android.app.ActivityThread.-$$Nest$mhandleBindApplication(Unknown Source:0)
    10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2546)
    10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at android.os.Handler.dispatchMessage(Handler.java:110)
    10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at android.os.Looper.loopOnce(Looper.java:248)
    10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at android.os.Looper.loop(Looper.java:338)
    10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at android.app.ActivityThread.main(ActivityThread.java:9067)
    10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at java.lang.reflect.Method.invoke(Native Method)
    10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:593)
    10-21 14:14:34.785 14069 14069 E AndroidRuntime: 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:932)

Reviewing the existing code:

https://github.com/dotnet/maui/blob/a4c124661c1e3c2f530ff2d4ec4c0a86eda8fcbb/src/Core/src/Hosting/Dispatching/AppHostBuilderExtensions.cs#L53-L57

So, I looked at the contents of:

    > adb pull /data/local/tmp/ide-launchenv.txt
    /data/local/tmp/ide-launchenv.txt: 1 file pulled, 0 skipped. 0.0 MB/s (3 bytes in 0.002s)

The file contains a line with a space character and a newline. No idea
what put that there?!?

I think the `Select(line => line.Split('=', 2))` call is problematic,
in addition to the `ToDictionary()` call. I think both of these could
throw exceptions on malformed / weird files.

I also got "nerd sniped" to improve the performance:

* `System.IO.File.ReadAllLines()` allocates a `string[]`

* `line.Split('=', 2)` allocates a `string[]`

* `ToDictionary(...)` allocates a dictionary and enumerates
  everything again.

We can just flatten the System.Linq usage here into a `foreach` loop
and avoid those allocations. We can also use `IndexOf('=')` to find
the split point.

After these changes, the app no longer crashes and starts up fine.
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR fixes a crash in Android MAUI applications caused by malformed environment variable files and improves performance by reducing allocations. The issue occurred when the ide-launchenv.txt file contained invalid entries (empty lines or lines without '=' delimiters), causing IndexOutOfRangeException during app startup.

Key Changes:

  • Replaced LINQ-based parsing with a manual foreach loop to handle malformed input gracefully
  • Added validation to skip invalid lines (empty lines or lines without '=' delimiter)
  • Improved performance by eliminating intermediate array and dictionary allocations

Comment on lines +55 to +61
int index = line.IndexOf('=', StringComparison.Ordinal);
if (index > 0)
{
string key = line.Substring(0, index);
string value = line.Substring(index + 1); // May be empty for values like "KEY="
environmentVariables[key] = value;
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't see a good way to write a test, @jfversluis can you check that Aspire still works with this change?

@jonathanpeppers jonathanpeppers added this to the .NET 10.0 GA milestone Oct 21, 2025
@PureWeen
Copy link
Member

/backport to release/10.0.1xx

@github-actions
Copy link
Contributor

Started backporting to release/10.0.1xx: https://github.com/dotnet/maui/actions/runs/18696186487

@PureWeen PureWeen added the p/0 Current heighest priority issues that we are targeting for a release. label Oct 21, 2025
@PureWeen PureWeen moved this from Todo to Ready To Review in MAUI SDK Ongoing Oct 21, 2025
@jonathanpeppers
Copy link
Member Author

@github-project-automation github-project-automation bot moved this from Ready To Review to Done in MAUI SDK Ongoing Oct 21, 2025
@github-actions github-actions bot locked and limited conversation to collaborators Nov 21, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

p/0 Current heighest priority issues that we are targeting for a release.

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants