Skip to content

Conversation

jonathanpeppers
Copy link
Member

Context: https://developer.android.com/about/versions/16/qpr2/
Context: dotnet/android@35d471e
Context: https://developer.android.com/reference/android/os/Build.VERSION#SDK_INT_FULL

Android 16 Quarterly Platform Release 2 (QPR2) Beta 2 has been released.

Android 16 QPR2 adds a new concept, "minor" SDK versions:

> The new [`SDK_INT_FULL`][0] constant can be used for API checks…
>
>     if (SDK_INT_FULL >= VERSION_CODES_FULL.[MAJOR or MINOR RELEASE]) {
>       // Use APIs introduced in a major or minor release
>     }
>
> You can also use the [`Build.getMinorSdkVersion()`][1] method to
> get just the minor SDK version:
>
>     minorSdkVersion = Build.getMinorSdkVersion(Build.VERSION_CODES_FULL.BAKLAVA);

To mirror this in .NET, we introduced a new $(TargetFramework) such as net10.0-android36.1 where C# developers could use:

if (OperatingSystem.IsAndroidVersionAtLeast(36, 1))
{
    // Use APIs introduced in Android 36.1
}

Reviewing Android's implementation of Build.VERSION.SDK_INT_FULL we can check the ro.build.version.sdk_full system property to get the minor version and falling back to ro.build.version.sdk otherwise.

libSystem.Native.so can return the value from SystemNative_GetUnixRelease() making both Environment.OSVersion and System.IsAndroidVersionAtLeast() support minor Android releases.

An example of the system properties available on the latest emulator:

% adb shell getprop | grep ro.build.version.sdk
[ro.build.version.sdk]: [36]
[ro.build.version.sdk_full]: [36.1]

The release notes mention QPR2 Beta 2 is API stable, so we should be safe to rely on this behavior going forward:

QPR2 Beta 2 is now available and has released Platform Stability.
That means that the API surface is locked, and the app-facing behaviors
are final, so you can incorporate them into your apps and take advantage
of our latest platform innovations.

To test this behavior, I set $DOTNET_ANDROID_VERSION_FROM_JAVA in the Android test runner, to verify we get the same value from Java and .NET.

…eleases

Context: https://developer.android.com/about/versions/16/qpr2/
Context: dotnet/android@35d471e
Context: https://developer.android.com/reference/android/os/Build.VERSION#SDK_INT_FULL

Android 16 Quarterly Platform Release 2 (QPR2) Beta 2 has been released.

Android 16 QPR2 adds a new concept, "minor" SDK versions:

    > The new [`SDK_INT_FULL`][0] constant can be used for API checks…
    >
    >     if (SDK_INT_FULL >= VERSION_CODES_FULL.[MAJOR or MINOR RELEASE]) {
    >       // Use APIs introduced in a major or minor release
    >     }
    >
    > You can also use the [`Build.getMinorSdkVersion()`][1] method to
    > get just the minor SDK version:
    >
    >     minorSdkVersion = Build.getMinorSdkVersion(Build.VERSION_CODES_FULL.BAKLAVA);

To mirror this in .NET, we introduced a new `$(TargetFramework)` such as
`net10.0-android36.1` where C# developers could use:

    if (OperatingSystem.IsAndroidVersionAtLeast(36, 1))
    {
        // Use APIs introduced in Android 36.1
    }

Reviewing Android's implementation of `Build.VERSION.SDK_INT_FULL` we
can check the `ro.build.version.sdk_full` system property to get the
minor version and falling back to `ro.build.version.sdk` otherwise.

`libSystem.Native.so` can return the value from
`SystemNative_GetUnixRelease()` making both `Environment.OSVersion`
and `System.IsAndroidVersionAtLeast()` support minor Android releases.

An example of the system properties available on the latest emulator:

    % adb shell getprop | grep ro.build.version.sdk
    [ro.build.version.sdk]: [36]
    [ro.build.version.sdk_full]: [36.1]

The release notes mention QPR2 Beta 2 is API stable, so we should be
safe to rely on this behavior going forward:

> QPR2 Beta 2 is now available and has released Platform Stability.
> That means that the API surface is locked, and the app-facing behaviors
> are final, so you can incorporate them into your apps and take advantage
> of our latest platform innovations.

To test this behavior, I set `$DOTNET_ANDROID_VERSION_FROM_JAVA` in the
Android test runner, to verify we get the same value from Java and .NET.

[0]: https://developer.android.com/reference/android/os/Build.VERSION#SDK_INT_FULL
[1]: https://developer.android.com/reference/android/os/Build#getMinorSdkVersion(int)
@Copilot Copilot AI review requested due to automatic review settings September 17, 2025 22:09
@github-actions github-actions bot added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Sep 17, 2025
Copy link
Contributor

@Copilot 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 adds support for Android 16's new "minor" SDK versions by enabling detection of both major and minor version numbers. The changes implement support for Android's new ro.build.version.sdk_full system property to capture minor releases like Android 36.1, ensuring consistency between Java and .NET version detection.

Key changes:

  • Modified native C code to check ro.build.version.sdk_full before falling back to the traditional ro.build.version.sdk
  • Added Java helper method to extract Android version with minor SDK support using Build.getMinorSdkVersion()
  • Added test infrastructure to verify consistency between Java and .NET version detection

Reviewed Changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
src/native/libs/System.Native/pal_runtimeinformation.c Updates native code to prioritize ro.build.version.sdk_full for minor version detection
src/tasks/AndroidAppBuilder/Templates/MonoRunner.java Adds getAndroidVersion() method and sets environment variable for test validation
src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/EnvironmentTests.cs Adds test cases for Android minor versions and validation against Java implementation

These were useful to at least test the new code works:

09-17 16:41:13.701  7106  7121 D DOTNET  : Setting env var: DOTNET_ANDROID_VERSION_FROM_JAVA=36.1
...
09-17 16:41:14.927  7106  7130 I DOTNET  :     [PASS] System.Tests.EnvironmentTests.OSVersion_ValidVersion_AndroidMinor
@akoeplinger akoeplinger added area-System.Runtime os-android and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Sep 18, 2025
Copy link
Contributor

Tagging subscribers to this area: @dotnet/area-system-runtime
See info in area-owners.md if you want to be subscribed.

@akoeplinger
Copy link
Member

/backport to release/10.0

Copy link
Contributor

Started backporting to release/10.0: https://github.com/dotnet/runtime/actions/runs/17832867982

@jonathanpeppers jonathanpeppers merged commit 60a7500 into dotnet:main Sep 18, 2025
113 checks passed
xtqqczze pushed a commit to xtqqczze/dotnet-runtime that referenced this pull request Sep 20, 2025
…eleases (dotnet#119826)

Context: https://developer.android.com/about/versions/16/qpr2/
Context: dotnet/android@35d471e
Context: https://developer.android.com/reference/android/os/Build.VERSION#SDK_INT_FULL

Android 16 Quarterly Platform Release 2 (QPR2) Beta 2 has been released.

Android 16 QPR2 adds a new concept, "minor" SDK versions:

    > The new [`SDK_INT_FULL`][0] constant can be used for API checks…
    >
    >     if (SDK_INT_FULL >= VERSION_CODES_FULL.[MAJOR or MINOR RELEASE]) {
    >       // Use APIs introduced in a major or minor release
    >     }
    >
    > You can also use the [`Build.getMinorSdkVersion()`][1] method to
    > get just the minor SDK version:
    >
    >     minorSdkVersion = Build.getMinorSdkVersion(Build.VERSION_CODES_FULL.BAKLAVA);

To mirror this in .NET, we introduced a new `$(TargetFramework)` such as
`net10.0-android36.1` where C# developers could use:

    if (OperatingSystem.IsAndroidVersionAtLeast(36, 1))
    {
        // Use APIs introduced in Android 36.1
    }

Reviewing Android's implementation of `Build.VERSION.SDK_INT_FULL` we
can check the `ro.build.version.sdk_full` system property to get the
minor version and falling back to `ro.build.version.sdk` otherwise.

`libSystem.Native.so` can return the value from
`SystemNative_GetUnixRelease()` making both `Environment.OSVersion`
and `System.IsAndroidVersionAtLeast()` support minor Android releases.

An example of the system properties available on the latest emulator:

    % adb shell getprop | grep ro.build.version.sdk
    [ro.build.version.sdk]: [36]
    [ro.build.version.sdk_full]: [36.1]

The release notes mention QPR2 Beta 2 is API stable, so we should be
safe to rely on this behavior going forward:

> QPR2 Beta 2 is now available and has released Platform Stability.
> That means that the API surface is locked, and the app-facing behaviors
> are final, so you can incorporate them into your apps and take advantage
> of our latest platform innovations.

To test this behavior, I set `$DOTNET_ANDROID_VERSION_FROM_JAVA` in the
Android test runner, to verify we get the same value from Java and .NET.

* Removed test changes, to be added in dotnet/android instead.

Tests were originally useful to test the new code works:

    09-17 16:41:13.701  7106  7121 D DOTNET  : Setting env var: DOTNET_ANDROID_VERSION_FROM_JAVA=36.1
    ...
    09-17 16:41:14.927  7106  7130 I DOTNET  :     [PASS] System.Tests.EnvironmentTests.OSVersion_ValidVersion_AndroidMinor

[0]: https://developer.android.com/reference/android/os/Build.VERSION#SDK_INT_FULL
[1]: https://developer.android.com/reference/android/os/Build#getMinorSdkVersion(int)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants