Skip to content

Compose DOTNET_STARTUP_HOOKS across all Android environment sources instead of overwriting#11187

Draft
Copilot wants to merge 4 commits intomainfrom
copilot/fix-dotnet-startup-hooks
Draft

Compose DOTNET_STARTUP_HOOKS across all Android environment sources instead of overwriting#11187
Copilot wants to merge 4 commits intomainfrom
copilot/fix-dotnet-startup-hooks

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 22, 2026

DOTNET_STARTUP_HOOKS was being rewritten by Hot Reload/trimmable typemap targets from @(RuntimeEnvironmentVariable) only, which silently dropped values provided via @(AndroidEnvironment) files. This change now composes startup hooks in two layers: contribution in targets, and final merge at environment consolidation time.

  • Compose target-level startup-hook contributions before environment file generation

    • Added _ComposeDotNetStartupHooks in Xamarin.Android.Common.targets (wired before _GenerateEnvironmentFiles).
    • Collects hooks from:
      • internal contributors via @(_AndroidDotnetStartupHooks)
      • existing @(RuntimeEnvironmentVariable) entries for DOTNET_STARTUP_HOOKS
    • Removes duplicates and emits one RuntimeEnvironmentVariable value joined with :.
  • Merge repeated DOTNET_STARTUP_HOOKS definitions at the final consolidation layer

    • Updated EnvironmentBuilder to merge repeated DOTNET_STARTUP_HOOKS values (from environment files and generated entries) instead of last-write-wins.
    • Uses colon-separated merge with deduplication so the final environment has one effective DOTNET_STARTUP_HOOKS value.
  • Stop Hot Reload from mutating @(RuntimeEnvironmentVariable) directly

    • _AndroidConfigureHotReloadEnvironment now contributes the normalized assembly name to @(_AndroidDotnetStartupHooks) instead of remove/re-add on DOTNET_STARTUP_HOOKS.
    • Keeps RuntimeHostConfigurationOption behavior unchanged.
  • Add focused coverage for cross-source merge behavior

    • Added a build test in EnvironmentContentTests that defines:
      • a runtime-provided hook (RuntimeEnvironmentVariable)
      • a file-provided hook (AndroidEnvironment)
    • Verifies final DOTNET_STARTUP_HOOKS contains both values.
<ItemGroup>
  <_AndroidDotnetStartupHooks Include="@(RuntimeEnvironmentVariable->WithMetadataValue('Identity', 'DOTNET_STARTUP_HOOKS')->'%(Value)')" />
</ItemGroup>

<RemoveDuplicates Inputs="@(_AndroidDotnetStartupHooks)">
  <Output TaskParameter="Filtered" ItemName="_AndroidDotnetStartupHooksDistinct" />
</RemoveDuplicates>

<RuntimeEnvironmentVariable Remove="DOTNET_STARTUP_HOOKS" />
<RuntimeEnvironmentVariable Include="DOTNET_STARTUP_HOOKS"
    Value="@(_AndroidDotnetStartupHooksDistinct,':')"
    Condition="'@(_AndroidDotnetStartupHooksDistinct)' != ''" />
if (name == "DOTNET_STARTUP_HOOKS" && environmentVariables.TryGetValue (escapedName, out string? existingStartupHooks)) {
	environmentVariables [escapedName] = MergeDotNetStartupHooks (existingStartupHooks, escapedValue);
} else {
	environmentVariables [escapedName] = escapedValue;
}

Copilot AI and others added 2 commits April 22, 2026 21:21
Agent-Logs-Url: https://github.com/dotnet/android/sessions/a0bba47d-8a89-476b-b420-c6c5e6914563

Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix overwriting of DOTNET_STARTUP_HOOKS from AndroidEnvironment files Compose DOTNET_STARTUP_HOOKS across all Android environment sources instead of overwriting Apr 22, 2026
Copilot AI requested a review from simonrozsival April 22, 2026 21:35
Copy link
Copy Markdown
Member

@simonrozsival simonrozsival left a comment

Choose a reason for hiding this comment

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

@copilot address my questions

</Target>

<Target Name="_GenerateEnvironmentFiles" DependsOnTargets="_AndroidConfigureHotReloadEnvironment">
<Target Name="_ComposeDotNetStartupHooks"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This target does not have Inputs and Outputs, should it have them?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good question. I kept _ComposeDotNetStartupHooks without Inputs/Outputs intentionally because it only transforms in-memory MSBuild items/properties for the current build graph; persisting incremental state there could skip needed recomposition. I also moved the final cross-file merge to EnvironmentBuilder in 120aedf, so this target stays lightweight and order-safe.

Comment on lines +1600 to +1602
<ReadLinesFromFile File="%(_AndroidEnvironmentStartupHookFiles.Identity)">
<Output TaskParameter="Lines" ItemName="_AndroidEnvironmentStartupHookLines" />
</ReadLinesFromFile>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If I understand it correctly, we will leave the original DOTNET_STARTUP_HOOKS values in the env files? Doesn't this mean that we will have multiple definitions of DOTNET_STARTUP_HOOKS in the final list of environment variables? Shouldn't we move the merging logic to the GenerateAdditionalProviderSources or EnvironmentBuilder or some other place where we eventually merge all the environment variables into a single list of definitions?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

You're right. I changed this in 120aedf: _ComposeDotNetStartupHooks no longer reads @(AndroidEnvironment)/@(LibraryEnvironments) lines, and EnvironmentBuilder now merges repeated DOTNET_STARTUP_HOOKS definitions while parsing the final environment inputs. This moves merging to the consolidation point and avoids duplicate final definitions.

Agent-Logs-Url: https://github.com/dotnet/android/sessions/eaf7b02c-a819-4e2f-8bd5-fedfee6f1931

Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 23, 2026

@copilot address my questions

Addressed in 120aedf. I answered both review questions and updated the implementation so final DOTNET_STARTUP_HOOKS merging happens in EnvironmentBuilder (the environment consolidation point), while _ComposeDotNetStartupHooks only prepares runtime/internal contributions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

DOTNET_STARTUP_HOOKS from @(AndroidEnvironment) files is silently overwritten

2 participants