Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

.NET 6 Bindings: "Deprecated since" with Obsolete; UnsupportedOSPlatform #6349

Closed
bddckr opened this issue Sep 30, 2021 · 3 comments
Closed
Assignees
Labels
Area: Bindings Issues in Java Library Binding projects. needs-triage Issues that need to be assigned.

Comments

@bddckr
Copy link

bddckr commented Sep 30, 2021

Issue

I have a native API I'd like to generate bindings for. This API is available in API level A, was deprecated in B and removed in C. (With A < B < C.) What I'm thus looking for is a way to mark the API to be

  1. introduced in API level A and to not be available on earlier API levels.
  2. deprecated in API level B.
  3. not available starting with API level C.

It looks like xamarin/java.interop/#773 added SupportedOSPlatform, taking care of (1). I tested this with api-since="27" in my Metadata.xml and it works without issues 🎉

But for APIs that are deprecated only starting in a specific API level, it looks like the bindings generation process is not able to add anything to the generated output to tell the bindings consumer about the API level the API is deprecated in.

Here's an example:
DevicePolicyManager.ClearDeviceOwnerApp was introduced in API level 21 and deprecated in 26. Currently, the Xamarin.Android bindings ship with this (decompiled from the ref dll):

[Obsolete("deprecated")]
[Register("clearDeviceOwnerApp", "(Ljava/lang/String;)V", "GetClearDeviceOwnerApp_Ljava_lang_String_Handler")]
public virtual void ClearDeviceOwnerApp(string packageName)
{
    throw null;
}

Note that it just marks it as deprecated, with no way to figure out that it's actually available just fine if you target any version in [21, 26). So it seems like (2) cannot be handled currently. I'm not aware of anything in the .NET tooling to allow this, but I figured it's worth asking if there is a way.

For (3) I wonder if it's possible for the generator to add UnsupportedOSPlatform on a generated symbol. Just like support for SupportedOSPlatform was added already.

Version Information

VS 2022 (Version 17.0.0 Preview 4.1)
.NET 6 (6.0.100-rc.1.21463.6)

@bddckr bddckr added Area: Bindings Issues in Java Library Binding projects. needs-triage Issues that need to be assigned. labels Sep 30, 2021
@jpobst
Copy link
Contributor

jpobst commented Sep 30, 2021

The way this is handled in pre-NET6 is that we ship 10+ versions on Mono.Android.dll, one for each supported API level.

For example, it would not be marked as [Obsolete] in
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\ReferenceAssemblies\Microsoft\Framework\MonoAndroid\v5.0\Mono.Android.dll,
but it would be obsolete in
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\ReferenceAssemblies\Microsoft\Framework\MonoAndroid\v8.0\Mono.Android.dll.

You are correct that we do not have a good way to represent this in .NET 6, since we are only shipping a single Mono.Android.dll. I'll ask around to see if there's anything we can do for this.

But likely users will just have to live with the [Obsolete] warnings when targeting e.g. 21. It may still be useful to know that you are using something that is deprecated in newer versions, as presumably you will eventually have to update.

For Mono.Android.dll, (c) doesn't exist yet. I'm not aware of any API that has actually been removed from the Android API, as that would be a breaking change. We have CI checks that would break the build if API disappeared between versions. Perhaps Google will eventually remove api and we will have to deal with it then.

If you are trying to do (c) for your own library, you can add UnsupportedOSPlatform yourself using metadata to methods and constructors with customAttributes. It's not widely publicized, but we use it internally for building Mono.Android.dll.

Example:

<attr path="/api/package[@name='mono.android.app']/class[@name='IntentService']/constructor[count(parameter) = 0]" name="customAttributes">[Preserve(Conditional = true)]</attr>

Any string you put there will be placed in front of the method declaration. Note the value is an opaque string that generator doesn't understand, so it's on you to format it correctly, generator will just write it exactly as you specify.

@bddckr
Copy link
Author

bddckr commented Sep 30, 2021

Thank you for the detailed insight!

Obsoletion per dll, targeting a specific API level... interesting! This could work for me as well, but alas this is more of a runtime decision than a compile time decision. So as you say we just don't have anything in .NET 6 for now. Neither Xamarin itself, nor third parties.

I agree with the point that devs will want to be nudged towards getting rid of the obsolete API by already showing it as deprecated. To allow folks to run with TreatWarningsAsErrors or overcome "deprecation holes" however, a solution similar to (Un)SupportedOSPlatform is probably needed. But I understand that's more of a .NET core issue than it is specific to Xamarin.

  • By "deprecation holes" I mean API levels in which an API is not marked deprecated just yet, but due to it being marked as deprecated in the dll (based on the target API level), it is warning on runtime API levels that don't even have the new API available.

Thanks for asking around on that one - curious if this is something that's on the radar at all yet.

I'm not aware of any API that has actually been removed from the Android API

Good point. I don't think there actually is any API that was removed, however a few I encountered have been changed to no longer return any useful value, or even throw now. They're rare, but they exist for sure and those might be candidates for such an API annotation. Then again, they are there, you can call them - I guess it would be wrong by Xamarin to mark the API as unavailable.

My own goal here is to bind a few AOSP OEM APIs (among other things), and they do in fact remove those after a while (sometimes right away - without a grace deprecation period). For that customAttributes sounds perfect, thanks a lot for that hint!

@jpobst
Copy link
Contributor

jpobst commented Oct 26, 2021

I don't think there's much more for us to do here. This is on the .NET team now, if they choose to support scenarios like this in the future.

dotnet/runtime#47601

@jpobst jpobst closed this as completed Oct 26, 2021
@ghost ghost locked as resolved and limited conversation to collaborators Jun 2, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Area: Bindings Issues in Java Library Binding projects. needs-triage Issues that need to be assigned.
Projects
None yet
Development

No branches or pull requests

2 participants