Skip to content

Incremental _ManifestMerger build ignores @(AndroidManifestOverlay) changes #11006

Description

@Redth

Android framework version

Likely affects any current SDK-based Android app path using the current targets. I noticed this while inspecting the current main branch and would expect it to matter for net8.0-android, net9.0-android, and net10.0-android.

Affected platform version

Current main as of commit 0d3996623b902210d15d6327e25ddf14d30d398b.

Description

There seems to be an incremental build bug around manifest overlays generated via the public BeforeGenerateAndroidManifest extension point.

The scenario is:

  • A custom target is added to $(BeforeGenerateAndroidManifest).
  • That target generates or updates an overlay file and adds it to @(AndroidManifestOverlay).
  • _ManifestMerger later consumes @(AndroidManifestOverlay) via ManifestOverlayFiles="@(AndroidManifestOverlay)".

This looks like a supported scenario:

  • build-properties.md documents BeforeGenerateAndroidManifest as running directly before _GenerateJavaStubs.
  • In Microsoft.Android.Sdk.TypeMap.LlvmIr.targets, _GenerateJavaStubs is wired as:
<Target Name="_GenerateJavaStubs"
    DependsOnTargets="$(_GenerateJavaStubsDependsOnTargets);$(BeforeGenerateAndroidManifest)"
  • _ManifestMerger then runs after _GenerateJavaStubs.

However, _ManifestMerger's incremental Inputs do not include @(AndroidManifestOverlay), even though the task consumes those items:

<Target Name="_ManifestMerger"
    Inputs="$(IntermediateOutputPath)AndroidManifest.xml;@(ExtractedManifestDocuments);$(_AndroidBuildPropertiesCache);@(_AndroidMSBuildAllProjects)"
    Outputs="$(IntermediateOutputPath)android\AndroidManifest.xml">

  <ManifestMerger
      AndroidManifest="$(IntermediateOutputPath)AndroidManifest.xml"
      OutputManifestFile="$(IntermediateOutputPath)android\AndroidManifest.xml"
      LibraryManifestFiles="@(ExtractedManifestDocuments)"
      ManifestOverlayFiles="@(AndroidManifestOverlay)"
      ... />
</Target>

Because of that, if only the overlay changes, the custom target can run and update the overlay file, but _ManifestMerger can still be considered up-to-date and skipped. The merged manifest under obj/.../android/AndroidManifest.xml then does not reflect the updated overlay.

That makes the public BeforeGenerateAndroidManifest hook unreliable for generated overlays unless callers use brittle workarounds.

Steps to Reproduce

  1. Create an Android app.
  2. Add a custom target to $(BeforeGenerateAndroidManifest).
  3. Have that target generate $(IntermediateOutputPath)CustomOverlay.xml from some input file and add it to @(AndroidManifestOverlay).
  4. Build once.
  5. Change only the custom target's input so the generated overlay content changes.
  6. Build again.
  7. Observe that the custom target may run and update the overlay file, but _ManifestMerger can still be skipped because @(AndroidManifestOverlay) is not part of its declared Inputs.

Did you find any workaround?

A workaround is to also touch or rewrite $(IntermediateOutputPath)AndroidManifest.xml when the overlay changes, since that file is in _ManifestMerger's Inputs.

That works, but it is brittle and leaks an implementation detail of the current target graph into consumers that are otherwise trying to use the documented public hook.

Relevant log output

No binlog attached here, but the issue is visible from the target definitions above:

  • Microsoft.Android.Sdk.TypeMap.LlvmIr.targets wires $(BeforeGenerateAndroidManifest) into _GenerateJavaStubs
  • Xamarin.Android.Common.targets consumes @(AndroidManifestOverlay) in _ManifestMerger but omits it from the target Inputs

Proposed solution

Include @(AndroidManifestOverlay) in _ManifestMerger's Inputs so its incremental behavior matches the inputs actually consumed by the ManifestMerger task.

Something along these lines:

<Target Name="_ManifestMerger"
    Inputs="$(IntermediateOutputPath)AndroidManifest.xml;@(ExtractedManifestDocuments);@(AndroidManifestOverlay);$(_AndroidBuildPropertiesCache);@(_AndroidMSBuildAllProjects)"
    Outputs="$(IntermediateOutputPath)android\AndroidManifest.xml">

It would also be great to add a regression test covering a generated overlay added through BeforeGenerateAndroidManifest, so that a change in just the overlay causes _ManifestMerger to rerun.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Area: App+Library BuildIssues when building Library projects or Application projects.needs-triageIssues that need to be assigned.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions