Skip to content

[ApiXmlAdjuster] Fix for finding "mono.app.android.IntentService". #718

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

Merged
merged 1 commit into from
Sep 18, 2020

Conversation

jpobst
Copy link
Contributor

@jpobst jpobst commented Sep 17, 2020

Fixes: #717

A long time ago, we moved our managed binding of android.app.IntentService to mono.android.app.IntentService. When a user switches from jar2xml to class-parse and tries to reference this type it cannot be found because type resolution is now done in C# rather than Java.

We likely can't move the type back due to backwards compatibility issues, so we modify our type resolver to specially case this type and know where it moved to.

@jpobst jpobst marked this pull request as ready for review September 17, 2020 16:10
@jonpryor jonpryor merged commit a76edb8 into master Sep 18, 2020
@jonpryor jonpryor deleted the resolve-intentservice branch September 18, 2020 01:42
jonpryor pushed a commit that referenced this pull request Sep 18, 2020
…#718)

Fixes: #717

A long time ago (2011-Jan-28), [Novell Bug #655342][0] was filed:
the following fragment was expected to work, but didn't:

	// C#
	[Service]
	class MyService : Android.App.IntentService {
	    public MyService()
	    {
	    }

	    protected override void OnHandleIntent(Intent intent)
	    {
	    }
	}

Why didn't it work?  Two reasons:

 1. `android.app.IntentService` has no default constructor; it only
    has an [`IntentService(String)`][1] constructor.

 2. In 2011, there was no way for a C# type to provide constructor
    parameters to the Java constructor.

The result is that the Java Callable Wrapper for `MyService` was not
valid Java code, as it attempted to use a non-existent constructor:

	// Java
	/* partial */ class MyService extends android.app.IntentService {
	    public MyService() {
	        super(); // javac error; no such constructor exists
	        // …
	    }
	}

Note that there's no way to make `MyService() : base("name")` work,
which would be the "obvious" solution, unless `jcw-gen` contains an
IL interpreter to determine what parameters were provided to the base
class constructor, and…no.  Too complicated.  Not happening.

Note: (2) later got "solved" [in 2013][2] by adding the
[`ExportAttribute.SuperArgumentsString` property][3], which would allow:

	[Service]
	partial class MyService : Android.App.IntentService {
	    [Export(SuperArgumentsString="\"name\"")]
	    public MyService() : base ("name")
	    {
	    }
	}

--End note.

Lacking a time machine, [the 2011 fix][4] was to "fudge" it:

 1. Add a new [`mono.android.app.IntentService`][5] Java type which
    contains a default constructor.

 2. ["Rename"][6] `android.app.IntentService` as
    `mono.android.app.IntentService`.

That way, the original C# declaration would generate a Java Callable
Wrapper resembling:

	// Java
	/* partial */ class MyService extends mono.android.app.IntentService {
	    public MyService() {
	        super(); // now valid; it exists!
	        // …
	    }
	}

Unfortunately, this doesn't properly address *bindings*: what happens
if a *Java* type inherits `android.app.IntentService`, as is the case
in [`Microsoft.Intune.MAM.SDK.aar`][7], and that type is bound?

In the original `jar2xml` world order, it worked: [`jar2xml`][8] is a
Java app, and for it to run `$CLASSPATH` needed to contain
`android.jar`, which *did* have `android.app.IntentService`.  Thus,
all required types could be resolved.

In the new `class-parse` world order, this isn't the case:
`class-parse` directly reads Java bytecode; no JVM is used.

The result is that binding projects which move from `jar2xml` to
`class-parse` could now get a new error:

	Error while processing type '[Class] com.microsoft.intune.mam.client.app.MAMIntentService':
	Type 'android.app.IntentService' was not found.

`android.app.IntentService` wasn't found because `Mono.Android.dll`
doesn't contain a binding for that type; it only binds
`mono.android.app.IntentService`.

The fix for this unfortunate state of affairs is Yet Another Kludge
to maintain backward compatibility: update
`JavaApiTypeResolverExtensions.FindNonGenericType()` so that it knows
about the 2011 kludge: if `android.app.IntentService` is requested,
hand it back the `JavaType` instance for
`mono.android.app.IntentService`.

[0]: http://bugzilla.novell.com/show_bug.cgi?id=655342
[1]: https://developer.android.com/reference/android/app/IntentService#IntentService(java.lang.String)
[2]: https://github.com/xamarin/monodroid/commit/a6c3497f4db9f628e086493580c908c6f05098fa
[3]: https://docs.microsoft.com/en-us/dotnet/api/java.interop.exportattribute.superargumentsstring
[4]: https://github.com/xamarin/monodroid/commit/7a42b46a39
[5]: https://github.com/xamarin/xamarin-android/blob/a7bda88d05b58efd26c17be3956c7140d05868e1/src/Mono.Android/java/mono/android/app/IntentService.java
[6]: https://github.com/xamarin/xamarin-android/blob/a7bda88d05b58efd26c17be3956c7140d05868e1/src/Mono.Android/metadata#L570-L583
[7]: https://github.com/msintuneappsdk/ms-intune-app-sdk-android/blob/master/Microsoft.Intune.MAM.SDK.aar
[8]: https://github.com/xamarin/jar2xml
@jpobst jpobst added this to the 11.0 (16.8 / 8.8) milestone Sep 22, 2020
@github-actions github-actions bot locked and limited conversation to collaborators Apr 13, 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.

Cannot inherit android.app.IntentService with class-parse
2 participants