Commit f96fcf9
[Xamarin.Android.Build.Tasks] FixAbstractMethodsStep overrides (#861)_wow
Context: https://bugzilla.xamarin.com/show_bug.cgi?id=22074
Context: https://bugzilla.xamarin.com/show_bug.cgi?id=59293
Context: https://developer.xamarin.com/releases/android/xamarin.android_6/xamarin.android_6.1/#Improved_Java_Interface_Versioning_Support
**Background**:
Until [C# gains support for default interface methods][ifaces], there
is an "impedance mismatch" between Java interfaces and C# interfaces:
Java methods can be added to interfaces *without* requiring that
existing classes implementing those interfaces implement the "new"
methods. (*This is not* Java default interface methods!)
[ifaces]: https://github.com/dotnet/csharplang/blob/master/proposals/default-interface-methods.md
Consider [`android.database.Cursor`][cursor]:
[cursor]: https://developer.android.com/reference/android/database/Cursor.html
```java
// API-1
interface Cursor {
void close();
// ...
}
class MyCursor implements Cursor {
public void close() {}
}
```
The `Cursor` interface had several methods added to it over time --
*before* the Android SDK supported default interface methods! --
e.g. the addition of `Cursor.getType()` in API-11:
```java
interface Cursor {
// in API-1
void close();
// ...
// Added in API-11
int getType(int columnIndex);
}
```
Question: What happens when `MyCursor.getType()` is invoked, if/when
`MyCursor` *has not* been recompiled?
```java
Cursor c = new MyCursor(); // Implements API-1 API, *not* API-11!
c.getType(0); // Method added in API-11!
```
What happens is that an [`AbstractMethodError`][ame] is thrown.
[ame]: https://developer.android.com/reference/java/lang/AbstractMethodError.html
Compare to C#, in which *the type cannot be loaded* if an interface
has a method added:
[ERROR] FATAL UNHANDLED EXCEPTION: System.TypeLoadException: VTable setup of type MyCursor failed
What this meant is [Bug #22074][b22074]: if you have a
Xamarin.Android library, and that library:
1. Has `$(TargetFrameworkVersion)`=v2.3 (API-10), and
2. Has a type which implements `Android.Database.ICursor`
and you then use the type (2) in an App which has
`$(TargetFrameworkVersion)`=v4.4, the app would crash with a
`TypeLoadException`.
[b22074]: https://bugzilla.xamarin.com/show_bug.cgi?id=22074
The fix, [introduced in Xamarin.Android 6.1][xa6.1], is the
`FixAbstractMethodsStep` step, which looks at every type in every
assembly to be included in the `.apk`, and checks to see if that type
is "missing" any abstract methods. If any such type is found, then
the "missing" method is *inserted*, and it will throw an
`AbstractMethodError`.
[xa6.1]: https://developer.xamarin.com/releases/android/xamarin.android_6/xamarin.android_6.1/#Improved_Java_Interface_Versioning_Support
For example, if an assembly `Lib.dll` built against API-10 has:
```csharp
public class MyCursor : Java.Lang.Object, Android.Database.ICursor {
// Implement `ICursor` methods from API-10
}
```
then when `Lib.dll` is packaged as part of an API-11+ app the
`FixAbstractMethodsStep` step will *add* the following method:
```csharp
int ICursor.GetType(int columnIndex)
{
throw new Java.Lang.AbstractMethodError();
}
```
**The Problem**: The Xamarin.Forms team ran into an issue with
[the debugger in Visual Studio][b59293]. During investigation it
turned out that our `FixAbstractMethodsStep` injects two methods
which were not needed, as the methods were already implemented.
[b59293]: https://bugzilla.xamarin.com/show_bug.cgi?id=59293
**The Fix**: Improve "missing abstract method" detection by looking
in `MethodDefinition.Overrides` to find the interface method and
compare it to the interface method we are looking for, not just
using the method name. This will be more resilient to compiler
changes -- not all compilers emit the same name for explicitly
implemented interface methods -- and prevent us from emitting
explicit interface methods when they're already present.1 parent 385699a commit f96fcf9
File tree
5 files changed
+30
-1
lines changed- src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner
- tests/CodeGen-Binding
- Xamarin.Android.FixJavaAbstractMethod-APIv1Binding/java/test/bindings
- Xamarin.Android.FixJavaAbstractMethod-APIv2Binding/java/test/bindings
- Xamarin.Android.FixJavaAbstractMethod-Library
- Xamarin.Android.JcwGen-Tests
5 files changed
+30
-1
lines changedLines changed: 15 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
95 | 95 | | |
96 | 96 | | |
97 | 97 | | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
98 | 110 | | |
99 | 111 | | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
100 | 115 | | |
101 | 116 | | |
102 | 117 | | |
| |||
Lines changed: 1 addition & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
| 6 | + | |
6 | 7 | | |
7 | 8 | | |
8 | 9 | | |
Lines changed: 1 addition & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| 8 | + | |
8 | 9 | | |
9 | 10 | | |
10 | 11 | | |
| |||
Lines changed: 8 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
6 | | - | |
| 6 | + | |
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
| |||
23 | 23 | | |
24 | 24 | | |
25 | 25 | | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
26 | 33 | | |
27 | 34 | | |
28 | 35 | | |
Lines changed: 5 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
179 | 179 | | |
180 | 180 | | |
181 | 181 | | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
182 | 187 | | |
183 | 188 | | |
184 | 189 | | |
| |||
0 commit comments