Skip to content

DOTNET_STARTUP_HOOKS from @(AndroidEnvironment) files is silently overwritten #11186

@simonrozsival

Description

@simonrozsival

Description

Both the HotReload targets (Microsoft.Android.Sdk.HotReload.targets) and the trimmable typemap targets (Microsoft.Android.Sdk.TypeMap.Trimmable.targets) compose DOTNET_STARTUP_HOOKS only from @(RuntimeEnvironmentVariable) items. However, users can also declare environment variables via @(AndroidEnvironment) text files:

DOTNET_STARTUP_HOOKS=MyStartupHook.dll

When the build targets run, they do:

<RuntimeEnvironmentVariable Remove="DOTNET_STARTUP_HOOKS" />
<RuntimeEnvironmentVariable Include="DOTNET_STARTUP_HOOKS" Value="..." />

This replaces the @(RuntimeEnvironmentVariable) value but never reads or merges values from @(AndroidEnvironment) files. The user's startup hook is silently dropped.

Affected targets

  1. _AndroidConfigureHotReloadEnvironment in Microsoft.Android.Sdk.HotReload.targets (L48-49) — replaces DOTNET_STARTUP_HOOKS without composing.
  2. _ConfigureTrimmableTypeMapStartupHook in Microsoft.Android.Sdk.TypeMap.Trimmable.targets (PR [TrimmableTypeMap] Per-assembly typemap universes with startup hook initialization #11181) — composes @(RuntimeEnvironmentVariable) entries but ignores @(AndroidEnvironment) files.

Expected behavior

All DOTNET_STARTUP_HOOKS values — regardless of source — should be merged (colon-separated) into the final environment written to the app.

Suggested approach

Introduce a new @(_AndroidDotnetStartupHooks) item group as the single collection point. A target running before _GenerateEnvironmentFiles merges all three sources:

  1. @(_AndroidDotnetStartupHooks) — internal contributors (HotReload, trimmable typemap) append their assembly names here instead of directly manipulating @(RuntimeEnvironmentVariable)
  2. @(RuntimeEnvironmentVariable) (filtered for DOTNET_STARTUP_HOOKS) — values passed in externally, e.g. by dotnet watch
  3. @(AndroidEnvironment) files — parsed for DOTNET_STARTUP_HOOKS=... lines

The target then:

  • Removes any DOTNET_STARTUP_HOOKS from @(RuntimeEnvironmentVariable)
  • Strips DOTNET_STARTUP_HOOKS=... lines from @(AndroidEnvironment) file content (or leaves them and deduplicates — TBD)
  • Joins all collected values with : into a single @(RuntimeEnvironmentVariable) entry

This approach:

  • Eliminates the fragile remove-then-add pattern each contributor currently does
  • Makes composition order-independent — no target needs to know about other contributors
  • Avoids duplicates naturally (items are distinct assembly names)
  • Starts as private (_ prefix) with the option to make it public and documented later

Context

Discussed in #11181 (comment)

Metadata

Metadata

Labels

copilot`copilot-cli` or other AIs were used to author this

Type

No fields configured for Task.

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions