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

[Mono.Android] Bind Android 14 DP 1. #7796

Merged
merged 9 commits into from
Mar 28, 2023
Merged

[Mono.Android] Bind Android 14 DP 1. #7796

merged 9 commits into from
Mar 28, 2023

Conversation

jpobst
Copy link
Contributor

@jpobst jpobst commented Feb 14, 2023

Context: https://developer.android.com/about/versions/14
Context: https://android-developers.googleblog.com/2023/02/first-developer-preview-android14.html

Android 14 Developer Preview 1 has been released. The Android 14
Developer Preview Program Overview Timeline and updates section
suggests the following timeline:

  • Feb/Mar: Developer Previews
  • April/May: Unstable Betas
  • June/July: Stable Betas
  • ???: Final

Acceptable Breakages

  • Type Dalvik.SystemInterop.DexFile was un-deprecated. A new nested class was added to it. (Documentation)

@jpobst jpobst force-pushed the api-34-dp1 branch 4 times, most recently from d34f285 to a126260 Compare February 16, 2023 21:37
jonpryor pushed a commit to dotnet/java-interop that referenced this pull request Mar 7, 2023
Context: dotnet/android#7796
Context: 22d5687
Context: 5a0e37e

Imagine the following covariant-return-type -using construct, which
is new in API-34 `android.jar`:

	// Java
	public abstract class Buffer  {
	    public abstract Buffer duplicate ();
	}
	public abstract class CharBuffer extends Buffer {
	    public abstract CharBuffer duplicate ();
	}

By default this is bound as:

	// C#
	[Register(…)]
	public abstract partial class Buffer {
	    [Register(…)]
	    public abstract Buffer Duplicate ();
	}
	[Register(…)]
	public abstract partial class CharBuffer : Buffer {
	    [Register(…)]
	    public abstract CharBuffer Duplicate ();
	}

Alas, this results in [error CS0533][0]:

	error CS0533: 'CharBuffer.Duplicate()' hides inherited abstract member 'Buffer.Duplicate()'

C# supports this semantic if we use [`abstract override`][1], similar
to [reabstraction of Default Interface Methods][2] in 22d5687:

	public abstract class CharBuffer : Buffer {
	    public override abstract CharBuffer Duplicate ();
	}

Theoretically, we can tell `generator` how to fix this via the
`//attr[@name='managedOverride']` metadata property (5a0e37e):

	<attr path="/api/package[@name='java.nio']/class[@name='CharBuffer']/method[@name='duplicate']"
	    name="managedOverride">override</attr>

However, `//attr[@name='managedOverride']` was not written to support
updating`abstract` methods.

Fix that oversight so that using `//attr[@name='managedOverride']`
can be used to emit `override abstract`:

	[Register(…)]
	public abstract partial class CharBuffer : Buffer {
	    [Register(…)]
	    public override abstract CharBuffer Duplicate ();
	}

~~ Method Invokers ~~

This gets us halfway there, but there is another issue: method invokers
for both the class and base class methods are *also* emitted into the
`*Invoker` subclass:

	partial class BufferInvoker : CharBuffer {
	    public override sealed unsafe Buffer Duplicate() {…}
	    // so far so good…
	}
	partial class CharBufferInvoker : CharBuffer {
	    [Register ("duplicate", "()Ljava/nio/Buffer;", "")]
	    public override sealed unsafe Buffer     Duplicate() {…}

	    [Register ("duplicate", "()Ljava/nio/CharBuffer;", "")]
	    public override sealed unsafe CharBuffer Duplicate() {…}
	    // uh oh
	}

This results in the following error:

	error CS0111: Type 'CharBufferInvoker' already defines a member called 'Duplicate' with the same parameter types
	error CS0508: 'CharBufferInvoker.Duplicate()': return type must be 'CharBuffer' to match overridden member 'CharBuffer.Duplicate()'

This perhaps(?) could be something `generator` could detect and
prevent, but the feasibility and cost is unknown and expected to be
high.  Since this is a very rare case, we will fix it with metadata,
however we have never had metadata to apply to invokers before.

We have decided to support `//attr[@name='skipInvokerMethods']`
metadata on the `class` that the invoker class would be created for:

	<attr path="/api/package[@name='java.nio']/class[@name='CharBuffer']"
	    name="skipInvokerMethods">java/nio/Buffer.duplicate()Ljava/nio/Buffer;</attr>

The value is a comma, space, and newline-separated list of
"JNI signature-like" values consisting of:

 1. The simplified JNI name of the declaring class that contains the
    the invoker method to skip, e.g. `java/nio/Buffer`
 2. `.`
 3. The Java name of the invoker method to skip, e.g. `duplicate`.
 4. The JNI method signature of the method to skip, e.g.
   `()Ljava/nio/Buffer;`

The above `java/nio/Buffer.duplicate()Ljava/nio/Buffer;` value tells
`generator` to skip generating the `Buffer Buffer.duplicate ()` invoker
method when generating the `CharBufferInvoker` type.  Multiple invokers
to skip can be specified as a comma or space separated list.

[0]: https://learn.microsoft.com/en-us/dotnet/csharp/misc/cs0533
[1]: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/classes#1467-abstract-methods
[2]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/default-interface-methods#reabstraction
@jpobst jpobst force-pushed the api-34-dp1 branch 2 times, most recently from e3efbc9 to 8f94b0c Compare March 8, 2023 21:31
@jpobst
Copy link
Contributor Author

jpobst commented Mar 8, 2023

@pjcollins We are going to use covariant return types in this binding level, which are not supported by Classic. With your recent work on building fewer API levels for Classic in main, do you know how we could only build API-34 for .NET 8 until we get to the point where we aren't building Classic at all?

@pjcollins
Copy link
Member

@pjcollins We are going to use covariant return types in this binding level, which are not supported by Classic. With your recent work on building fewer API levels for Classic in main, do you know how we could only build API-34 for .NET 8 until we get to the point where we aren't building Classic at all?

I think adding something like this to Mono.Android.csproj and Mono.Android.Runtime.csproj will work for now:

  <!-- Do not build classic for API versions above 33 -->
  <PropertyGroup Condition=" '$(TargetFramework)' == 'monoandroid10' And '$(AndroidApiLevel)' &gt; '33'">
    <BuildDependsOn></BuildDependsOn>
  </PropertyGroup>

We'll need more changes when we go to make this API level stable, but by then we will likely have pulled out more of the classic build.

@jpobst jpobst force-pushed the api-34-dp1 branch 3 times, most recently from ed1b3d3 to 8b7dac8 Compare March 23, 2023 15:23
@jpobst jpobst marked this pull request as ready for review March 24, 2023 00:42
@@ -31,6 +31,7 @@ public sealed class CheckApiCompatibility : Task
{ "v12.0", "v11.0" },
{ "v12.1", "v12.0" },
{ "v13.0", "v12.1" },
{ "v13.0.99", "v13.0" },
Copy link
Member

Choose a reason for hiding this comment

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

Does this task work in a .NET Android world order?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Apparently not! 😁

It appears we only run ApiCompat against the stable API platform on .NET. This is something that will need to be fixed, but will be much easier once Classic has been removed from main. I propose we prioritize this work for later. I ran it manually locally, so the breakages included in this PR are correct, but CI will not be able to verify them until then.

At the very worst, the PR in ~June that marks API-34 stable will check it with today's ApiCompat.

@@ -58,7 +58,7 @@ variables:
- name: ExcludedNUnitCategories
value: '& cat != DotNetIgnore & cat != HybridAOT & cat != MkBundle & cat != MonoSymbolicate & cat != PackagesConfig & cat != StaticProject & cat != SystemApplication'
- name: DefaultTestSdkPlatforms # Comma-separated SDK Platform(s) to install on test agents (no spaces)
value: 33
value: 33,UpsideDownCake
Copy link
Member

Choose a reason for hiding this comment

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

UpsideDownCake is required for tests?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, there are some tests to ensure users can build with our unstable packages.

{

#if ANDROID_34
// This implements an interface method that should be marked as 'default' but isn't.
Copy link
Member

Choose a reason for hiding this comment

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

MembersMustExist : Member 'public void Android.Views.PixelCopy.Request(Android.Views.Window, Android.Graphics.Bitmap, Android.Views.PixelCopy.IOnPixelCopyFinishedListener, Android.OS.Handler)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Android.Views.PixelCopy.Request(Android.Views.Window, Android.Graphics.Rect, Android.Graphics.Bitmap, Android.Views.PixelCopy.IOnPixelCopyFinishedListener, Android.OS.Handler)' does not exist in the implementation but it does exist in the contract.
CannotRemoveAttribute : Attribute 'System.ObsoleteAttribute' exists on 'Dalvik.SystemInterop.DexFile' in the contract but not the implementation.
CannotAddAbstractMembers : Member 'public Java.Nio.ByteBuffer Java.Nio.ByteBuffer.Slice(System.Int32, System.Int32)' is abstract in the implementation but is missing in the contract.
Copy link
Member

Choose a reason for hiding this comment

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

This confuses me; we're using compatVirtualMethod, which should emit a virtual method, not an abstract method, so why is this warning emitted at all?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was a rebase conflict error that I fixed incorrectly. Updated the acceptable-breakages to the only actual entry.

@jonpryor jonpryor merged commit e9f3143 into main Mar 28, 2023
@jonpryor jonpryor deleted the api-34-dp1 branch March 28, 2023 19:15
grendello added a commit to grendello/xamarin-android that referenced this pull request Mar 30, 2023
* main:
  [Mono.Android] Bind API-UpsideDownCake Developer Preview 1 (dotnet#7796)
  Bump to dotnet/installer@d109cba3ff 8.0.100-preview.4.23176.5 (dotnet#7921)
grendello added a commit to grendello/xamarin-android that referenced this pull request Apr 6, 2023
* main: (94 commits)
  [ci] Remove remaining Classic test jobs. (dotnet#7924)
  Add Nightly Tests for Humanizer
  [readme] Add aka.ms links for d17.5. (dotnet#7935)
  [tests] Remove `net472` multitargeting (dotnet#7932)
  [monodroid] Fix `ld` build error on Nightly Builds. (dotnet#7925)
  Bump to xamarin/Java.Interop/main@0355acf (dotnet#7931)
  [tests] Use msftconnecttest.com in QuoteInvalidQuoteUrlsShouldWork (dotnet#7919)
  [ci] Don't set demands for megapipeline (dotnet#7929)
  [Mono.Android] Bind API-UpsideDownCake Developer Preview 1 (dotnet#7796)
  Bump to dotnet/installer@d109cba3ff 8.0.100-preview.4.23176.5 (dotnet#7921)
  [Xamarin.Android.Build.Tasks] Fix Android Version Code for Release builds (dotnet#7795)
  Bump to dotnet/installer@27d6769dfb 8.0.100-preview.4.23172.16 (dotnet#7910)
  [Xamarin.Android.Build.Tasks] Fix native code generation when marshal methods are disabled (dotnet#7899)
  [ci] Optimize 'APK's .NET' test job overhead. (dotnet#7904)
  [Mono.Android] delay JNINativeWrapper.get_runtime_types() (dotnet#7913)
  Bump external/Java.Interop from `73ebad2` to `53bfb4a` (dotnet#7914)
  [build] remove .NET 6 support (dotnet#7900)
  [profiled-aot] update `dotnet.aotprofile` for .NET 8 (dotnet#7908)
  [tests] Add backup ssl sites in case of 429 response. (dotnet#7909)
  $(AndroidPackVersionSuffix)=preview.4; net8 is 34.0.0-preview.4 (dotnet#7912)
  ...
jpobst added a commit to dotnet/java-interop that referenced this pull request Jun 27, 2023
Context: dotnet/android#7796
Context: 22d5687
Context: 5a0e37e

Imagine the following covariant-return-type -using construct, which
is new in API-34 `android.jar`:

	// Java
	public abstract class Buffer  {
	    public abstract Buffer duplicate ();
	}
	public abstract class CharBuffer extends Buffer {
	    public abstract CharBuffer duplicate ();
	}

By default this is bound as:

	// C#
	[Register(…)]
	public abstract partial class Buffer {
	    [Register(…)]
	    public abstract Buffer Duplicate ();
	}
	[Register(…)]
	public abstract partial class CharBuffer : Buffer {
	    [Register(…)]
	    public abstract CharBuffer Duplicate ();
	}

Alas, this results in [error CS0533][0]:

	error CS0533: 'CharBuffer.Duplicate()' hides inherited abstract member 'Buffer.Duplicate()'

C# supports this semantic if we use [`abstract override`][1], similar
to [reabstraction of Default Interface Methods][2] in 22d5687:

	public abstract class CharBuffer : Buffer {
	    public override abstract CharBuffer Duplicate ();
	}

Theoretically, we can tell `generator` how to fix this via the
`//attr[@name='managedOverride']` metadata property (5a0e37e):

	<attr path="/api/package[@name='java.nio']/class[@name='CharBuffer']/method[@name='duplicate']"
	    name="managedOverride">override</attr>

However, `//attr[@name='managedOverride']` was not written to support
updating`abstract` methods.

Fix that oversight so that using `//attr[@name='managedOverride']`
can be used to emit `override abstract`:

	[Register(…)]
	public abstract partial class CharBuffer : Buffer {
	    [Register(…)]
	    public override abstract CharBuffer Duplicate ();
	}

~~ Method Invokers ~~

This gets us halfway there, but there is another issue: method invokers
for both the class and base class methods are *also* emitted into the
`*Invoker` subclass:

	partial class BufferInvoker : CharBuffer {
	    public override sealed unsafe Buffer Duplicate() {…}
	    // so far so good…
	}
	partial class CharBufferInvoker : CharBuffer {
	    [Register ("duplicate", "()Ljava/nio/Buffer;", "")]
	    public override sealed unsafe Buffer     Duplicate() {…}

	    [Register ("duplicate", "()Ljava/nio/CharBuffer;", "")]
	    public override sealed unsafe CharBuffer Duplicate() {…}
	    // uh oh
	}

This results in the following error:

	error CS0111: Type 'CharBufferInvoker' already defines a member called 'Duplicate' with the same parameter types
	error CS0508: 'CharBufferInvoker.Duplicate()': return type must be 'CharBuffer' to match overridden member 'CharBuffer.Duplicate()'

This perhaps(?) could be something `generator` could detect and
prevent, but the feasibility and cost is unknown and expected to be
high.  Since this is a very rare case, we will fix it with metadata,
however we have never had metadata to apply to invokers before.

We have decided to support `//attr[@name='skipInvokerMethods']`
metadata on the `class` that the invoker class would be created for:

	<attr path="/api/package[@name='java.nio']/class[@name='CharBuffer']"
	    name="skipInvokerMethods">java/nio/Buffer.duplicate()Ljava/nio/Buffer;</attr>

The value is a comma, space, and newline-separated list of
"JNI signature-like" values consisting of:

 1. The simplified JNI name of the declaring class that contains the
    the invoker method to skip, e.g. `java/nio/Buffer`
 2. `.`
 3. The Java name of the invoker method to skip, e.g. `duplicate`.
 4. The JNI method signature of the method to skip, e.g.
   `()Ljava/nio/Buffer;`

The above `java/nio/Buffer.duplicate()Ljava/nio/Buffer;` value tells
`generator` to skip generating the `Buffer Buffer.duplicate ()` invoker
method when generating the `CharBufferInvoker` type.  Multiple invokers
to skip can be specified as a comma or space separated list.

[0]: https://learn.microsoft.com/en-us/dotnet/csharp/misc/cs0533
[1]: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/classes#1467-abstract-methods
[2]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/default-interface-methods#reabstraction

(cherry picked from commit 73ebad2)
jonpryor pushed a commit to dotnet/java-interop that referenced this pull request Jun 29, 2023
Context: dotnet/android#7796
Context: 22d5687
Context: 5a0e37e

Imagine the following covariant-return-type -using construct, which
is new in API-34 `android.jar`:

	// Java
	public abstract class Buffer  {
	    public abstract Buffer duplicate ();
	}
	public abstract class CharBuffer extends Buffer {
	    public abstract CharBuffer duplicate ();
	}

By default this is bound as:

	// C#
	[Register(…)]
	public abstract partial class Buffer {
	    [Register(…)]
	    public abstract Buffer Duplicate ();
	}
	[Register(…)]
	public abstract partial class CharBuffer : Buffer {
	    [Register(…)]
	    public abstract CharBuffer Duplicate ();
	}

Alas, this results in [error CS0533][0]:

	error CS0533: 'CharBuffer.Duplicate()' hides inherited abstract member 'Buffer.Duplicate()'

C# supports this semantic if we use [`abstract override`][1], similar
to [reabstraction of Default Interface Methods][2] in 22d5687:

	public abstract class CharBuffer : Buffer {
	    public override abstract CharBuffer Duplicate ();
	}

Theoretically, we can tell `generator` how to fix this via the
`//attr[@name='managedOverride']` metadata property (5a0e37e):

	<attr path="/api/package[@name='java.nio']/class[@name='CharBuffer']/method[@name='duplicate']"
	    name="managedOverride">override</attr>

However, `//attr[@name='managedOverride']` was not written to support
updating`abstract` methods.

Fix that oversight so that using `//attr[@name='managedOverride']`
can be used to emit `override abstract`:

	[Register(…)]
	public abstract partial class CharBuffer : Buffer {
	    [Register(…)]
	    public override abstract CharBuffer Duplicate ();
	}

~~ Method Invokers ~~

This gets us halfway there, but there is another issue: method invokers
for both the class and base class methods are *also* emitted into the
`*Invoker` subclass:

	partial class BufferInvoker : CharBuffer {
	    public override sealed unsafe Buffer Duplicate() {…}
	    // so far so good…
	}
	partial class CharBufferInvoker : CharBuffer {
	    [Register ("duplicate", "()Ljava/nio/Buffer;", "")]
	    public override sealed unsafe Buffer     Duplicate() {…}

	    [Register ("duplicate", "()Ljava/nio/CharBuffer;", "")]
	    public override sealed unsafe CharBuffer Duplicate() {…}
	    // uh oh
	}

This results in the following error:

	error CS0111: Type 'CharBufferInvoker' already defines a member called 'Duplicate' with the same parameter types
	error CS0508: 'CharBufferInvoker.Duplicate()': return type must be 'CharBuffer' to match overridden member 'CharBuffer.Duplicate()'

This perhaps(?) could be something `generator` could detect and
prevent, but the feasibility and cost is unknown and expected to be
high.  Since this is a very rare case, we will fix it with metadata,
however we have never had metadata to apply to invokers before.

We have decided to support `//attr[@name='skipInvokerMethods']`
metadata on the `class` that the invoker class would be created for:

	<attr path="/api/package[@name='java.nio']/class[@name='CharBuffer']"
	    name="skipInvokerMethods">java/nio/Buffer.duplicate()Ljava/nio/Buffer;</attr>

The value is a comma, space, and newline-separated list of
"JNI signature-like" values consisting of:

 1. The simplified JNI name of the declaring class that contains the
    the invoker method to skip, e.g. `java/nio/Buffer`
 2. `.`
 3. The Java name of the invoker method to skip, e.g. `duplicate`.
 4. The JNI method signature of the method to skip, e.g.
   `()Ljava/nio/Buffer;`

The above `java/nio/Buffer.duplicate()Ljava/nio/Buffer;` value tells
`generator` to skip generating the `Buffer Buffer.duplicate ()` invoker
method when generating the `CharBufferInvoker` type.  Multiple invokers
to skip can be specified as a comma or space separated list.

[0]: https://learn.microsoft.com/en-us/dotnet/csharp/misc/cs0533
[1]: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/classes#1467-abstract-methods
[2]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/default-interface-methods#reabstraction

(cherry picked from commit 73ebad2)
@github-actions github-actions bot locked and limited conversation to collaborators Jan 23, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants