[Java.Interop] Bump generator's minimum API level for SupportedOSPlatform/Obsolete to 24 - #12681
Closed
simonrozsival wants to merge 1 commit into
Closed
[Java.Interop] Bump generator's minimum API level for SupportedOSPlatform/Obsolete to 24#12681simonrozsival wants to merge 1 commit into
simonrozsival wants to merge 1 commit into
Conversation
…o 24
The Java.Interop generator's `MINIMUM_API_LEVEL` constant controlled
the floor below which `[SupportedOSPlatform]` (and the equivalent
`[ObsoletedOSPlatform]` early-obsolete fallback) is considered
redundant and therefore omitted. It was still set to 21, but
.NET for Android's actual minimum supported Android API level is
24 (`$(AndroidMinimumDotNetApiLevel)` in `Configuration.props`,
which must match `$(AndroidApiLevelMin)` in dotnet/runtime).
Because every API >= 21 is always available on every currently
supported target (API 24+), emitting `[SupportedOSPlatform
("android21.0"/"android22.0"/"android23.0")]` for such members is
dead weight: the attribute can never affect analyzer diagnostics
or trimming decisions, it only adds IL/metadata for the compiler
to skip. Bumping the constant to 24 removes these now-redundant
attributes while still emitting `[SupportedOSPlatform]` correctly
for APIs 25+.
`[UnsupportedOSPlatform]` is intentionally left untouched:
`AddUnsupportedOSPlatform` only checks `since > 0` and does not
reference `MINIMUM_API_LEVEL` at all, so "removed-since" semantics
are structurally independent of this floor and remain fully
correct.
Measurement (real, controlled generator invocation):
Built the current `generator.dll` and ran it directly against the
real, committed `src/Mono.Android/Profiles/api-37.2.xml` plus the
real Android SDK's `api-versions.xml` (android-37.2), using the
exact CLI flags `_GenerateBinding` uses in
`src/Mono.Android/Mono.Android.targets`, once with
MINIMUM_API_LEVEL=21 (baseline) and once with =24 (this change):
| Level | Baseline (21) | New (24) | Removed |
|-----------|---------------|----------|---------|
| android22 | 475 | 0 | 475 |
| android23 | 5,808 | 0 | 5,808 |
| android24 | 13,971 | 0 | 13,971 |
| **Total** | 84,978 | 64,724 | **20,254** |
So this change removes 20,254 redundant `[SupportedOSPlatform]`
attribute applications from the generated Mono.Android API-37
bindings (android25+ counts, e.g. android25=364, are unaffected).
Using the same per-attribute CustomAttribute-table-row +
constructor-argument-blob cost estimate previously used for this
class of change (~12 bytes/attribute), this corresponds to an
estimated ~243 KB of metadata savings. A full Mono.Android.dll
build/ildasm diff was not performed (would require a full product
build); the count above comes from directly invoking the real,
current generator against real generator inputs, which the task
explicitly allows as an alternative to a full build.
Test changes (external/Java.Interop/tests/generator-Tests):
* Added `SupportedOSPlatformOmittedAtOrBelowMinimumApiLevel`,
parametrized for android22/23/24 (must NOT emit
`[SupportedOSPlatform]`) and android25 (must emit it), directly
exercising the new floor.
* Fixed `ObsoletedOSPlatformAttributeUnneededSupport`: members with
`deprecated-since='22'` now fall back to plain `[Obsolete]`
(since 22 <= 24) instead of `[ObsoletedOSPlatform ("android22.0")]`
(since 22 <= 21 was false under the old floor). Verified the
fallback correctly preserves the raw Android deprecation message.
Verified: targeted filter (`ObsoletedOSPlatform|SupportedOSPlatform|
UnsupportedOSPlatform`, 21/21) and the full `generator-Tests` suite
(493/493) pass.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Copilot review overview
🟢 Approval recommended
The change is small, consistent with repo configuration (API 24), and the updated tests cover the new boundary behavior.
Review tier: Lite
Findings: 1
New issues introduced by this change (1)
| Severity | Finding |
|---|---|
external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorTests.cs — 💡 Consider deriving the minimum API level from the generator (and asserting it matches… |
What changed in this PR
This PR updates the Java.Interop generator’s notion of the minimum supported Android API level so it stops emitting redundant platform attributes for APIs that are always present on supported .NET for Android targets.
Changes:
- Bumped
MINIMUM_API_LEVELfrom 21 → 24 in the generator’sSourceWriterExtensionsto align with$(AndroidMinimumDotNetApiLevel). - Updated/expanded generator unit tests to validate
[SupportedOSPlatform]omission at/below the new floor and adjusted[ObsoletedOSPlatform]vs[Obsolete]expectations accordingly.
| File | Description |
|---|---|
| external/Java.Interop/tools/generator/SourceWriters/Extensions/SourceWriterExtensions.cs | Raises the generator floor to API 24 so [SupportedOSPlatform]/[ObsoletedOSPlatform] aren’t emitted when they can’t affect supported builds. |
| external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorTests.cs | Updates and adds tests to cover the new API-floor boundary behavior for platform attributes. |
Comment on lines
+1456
to
+1479
| [Test] | ||
| // MINIMUM_API_LEVEL is 24 (matches $(AndroidMinimumDotNetApiLevel) in Configuration.props), so | ||
| // there's no sense writing [SupportedOSPlatform] for an API available at or below that floor: | ||
| // it's available in every version we support. Only API levels above the floor need it. | ||
| [TestCase (22, false)] | ||
| [TestCase (23, false)] | ||
| [TestCase (24, false)] | ||
| [TestCase (25, true)] | ||
| public void SupportedOSPlatformOmittedAtOrBelowMinimumApiLevel (int apiLevel, bool expectAttribute) | ||
| { | ||
| var klass = SupportTypeBuilder.CreateClass ("java.code.MyClass", options); | ||
| klass.ApiAvailableSince = new AndroidSdkVersion (apiLevel); | ||
|
|
||
| generator.Context.ContextTypes.Push (klass); | ||
| generator.WriteType (klass, string.Empty, new GenerationInfo ("", "", "MyAssembly")); | ||
| generator.Context.ContextTypes.Pop (); | ||
|
|
||
| var attribute = $"[global::System.Runtime.Versioning.SupportedOSPlatformAttribute (\"android{apiLevel}.0\")]"; | ||
|
|
||
| if (expectAttribute) | ||
| StringAssert.Contains (attribute, builder.ToString (), $"Should contain SupportedOSPlatform for android{apiLevel}!"); | ||
| else | ||
| StringAssert.DoesNotContain (attribute, builder.ToString (), $"Should NOT contain SupportedOSPlatform for android{apiLevel}!"); | ||
| } |
Member
Author
|
Closing in favor of #12682, which now contains both this commit and the follow-up wiring change as a single combined PR against |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

What
Bumps the Java.Interop generator's
MINIMUM_API_LEVELconstant (inexternal/Java.Interop/tools/generator/SourceWriters/Extensions/SourceWriterExtensions.cs) from 21 to 24, so it matches .NET for Android's actual minimum supported Android API level.Why
This constant controls the floor below which
[SupportedOSPlatform](and the equivalent[ObsoletedOSPlatform]early-obsolete fallback) is considered redundant and omitted from generated bindings. It was still21, a leftover from before .NET for Android raised its floor. The authoritative source of truth is$(AndroidMinimumDotNetApiLevel)inConfiguration.props, which is24and must match$(AndroidApiLevelMin)in dotnet/runtime'sDirectory.Build.props.Since every API >= 21 is always available on every currently supported target (API 24+), emitting
[SupportedOSPlatform ("android21.0"/"android22.0"/"android23.0")]on such members is dead weight — the attribute can never influence analyzer diagnostics or trimming, it only adds generated source text and IL/metadata. Bumping the floor to 24 removes these now-redundant attributes while still correctly emitting[SupportedOSPlatform]for APIs 25+.I looked for an existing small, clean generator input (e.g. a CLI option) that already threads a "minimum API" value through the generator so this constant could just reuse it, but found none —
CodeGenerationOptionsand the generator CLI have no such parameter today. Per the scope of this change, a surgical constant bump is the right fix rather than introducing new wiring.[UnsupportedOSPlatform]is intentionally unchangedAddUnsupportedOSPlatformonly checkssince > 0and never referencesMINIMUM_API_LEVEL— "removed-since" semantics are structurally independent of this floor. There's nothing to change there, and this PR doesn't touch it.Measurement (real, controlled generator invocation)
Built the current
generator.dlland ran it directly against the real, committedsrc/Mono.Android/Profiles/api-37.2.xmlplus the real Android SDK'sapi-versions.xml(android-37.2 platform), using the exact CLI flags the_GenerateBindingMSBuild target uses (fromsrc/Mono.Android/Mono.Android.targets) — once withMINIMUM_API_LEVEL=21(baseline, via a temporary local revert) and once with=24(this change):(android25+ counts are unaffected, e.g. android25 stayed at 364 in both runs.)
So this removes 20,254 redundant
[SupportedOSPlatform]attribute applications from the generated Mono.Android API-37 bindings. Using the same per-attribute CustomAttribute-table-row + constructor-argument-blob cost estimate used in prior analysis of this class of change (~12 bytes/attribute), this is roughly ~243 KB of estimated metadata savings. A fullMono.Android.dllbuild + exact metadata/ildasm diff was not performed (it requires a full product build, and this environment is shared with concurrent builds from other sessions); the counts above come from directly invoking the actual, current generator against real generator inputs — the approach the task explicitly allows as an alternative to a full build. Note these exact counts differ somewhat from an earlier estimate (396/4,877/12,519 = 17,792) quoted for this change; the real, reproducible counts here are higher across all three levels, likely due to differences in the specific API-versions/profile XML snapshot used for the earlier estimate.Tests
In
external/Java.Interop/tests/generator-Tests/Unit-Tests/CodeGeneratorTests.cs:SupportedOSPlatformOmittedAtOrBelowMinimumApiLevel, parametrized for android22/23/24 (must not emit[SupportedOSPlatform]) and android25 (must emit it) — directly exercising the new floor boundary.ObsoletedOSPlatformAttributeUnneededSupport: members withdeprecated-since='22'now correctly fall back to plain[Obsolete](since22 <= 24) instead of[ObsoletedOSPlatform ("android22.0")](which was correct only under the old22 <= 21== false condition). I verified via the actual generated output that the fallback still correctly preserves the raw Android deprecation message text (the message-clearing logic for the literal string"deprecated"only runs in the[ObsoletedOSPlatform]branch, so this needed to be checked precisely rather than assumed).Results:
ObsoletedOSPlatform|SupportedOSPlatform|UnsupportedOSPlatform): 21/21 passedgenerator-Testssuite: 493/493 passedNo other generator test fixtures reference
SupportedOSPlatform/ObsoletedOSPlatformtext for API levels 21–24 that would need updating.Scope
This is a single, surgical constant change plus the test updates it requires — no other generator behavior, MSBuild targets, or product code were touched.