Skip to content

Conversation

@radekdoulik
Copy link
Member

@radekdoulik radekdoulik commented Sep 6, 2018

Implementation of #2138

Also fixes dotnet/java-interop#387,
dotnet/java-interop#388

Conditionally generate JNI marshal methods for user and relevant SDK
assemblies. It is enabled by setting
AndroidGenerateJniMarshalMethods to True.

This is done by _GenerateJniMarshalMethods target, which runs
jnimarshalmethod-gen.exe with XA's mono. It is possible to pass
additional arguments to the tool by setting
AndroidGenerateJniMarshalMethodsAdditionalArguments property.

The target also passes the path to the JVM shared library to the tool
using --jvm option. The path comes from the updated ResolveSdks
task. The task will be optimized to improve performance by caching the
path.

The commit also removes the NotImplementedException throws from the
Android.Runtime.AndroidValueManager. The reason for that is that
this is now used from the generated marshal methods, which handle
primitive arrays. Namely AddPeer (IJavaPeerable value) is used. That
is something to further examine.

The RunJavaInteropTests was moved from _RunParallelTestTarget item
group to _RunTestTarget group, because it overwrites the
Java.Runtime.Environment.dll.config, which is required by
jnimarshalmethod-gen.exe to run. And so we need to run these tests after
apk tests. That should be fixed in future, hopefully by adding and/or
fixing the Inputs/Outputs of the relevant targets.

Enable JNI marshal methods in Mono.Android runtime test and
Xamarin.Forms test in Release and Release/AOT configurations.

Add custom JniCustomValueMarshaler's for Android.Graphics.Color
and for IJavaObject based objects, which don't implement
IJavaPeerable.

The generated Color class marshaler example:

using Android.Graphics;
using Java.Interop;
using System;

public static int n_getColor (IntPtr __jnienv, IntPtr __this)
{
	JniTransition jniTransition = new JniTransition (__jnienv);
	JniRuntime runtime = default(JniRuntime);
	try {
		runtime = JniEnvironment.Runtime;
		JniRuntime.JniValueManager valueManager = runtime.ValueManager;
		valueManager.WaitForGCBridgeProcessing ();
		MyPaint value = valueManager.GetValue<MyPaint> (__this);
		Color color = value.Color;
		return color.color;
	} catch (Exception ex) when (runtime.ExceptionShouldTransitionToJni (ex)) {
		jniTransition.SetPendingException (ex);
		return 0;
	} finally {
		jniTransition.Dispose ();
	}
	return 0;
}

The generated IJavaObject marshaler examples:

using Android.Runtime;
using Java.Interop;
using System;

public static void n_setAdapter_Landroid_widget_ListAdapter_ (IntPtr __jnienv, IntPtr __this, IntPtr value)
{
	JniTransition jniTransition = new JniTransition (__jnienv);
	JniRuntime runtime = default(JniRuntime);
	try {
		runtime = JniEnvironment.Runtime;
		JniRuntime.JniValueManager valueManager = runtime.ValueManager;
		valueManager.WaitForGCBridgeProcessing ();
		AbsListView value2 = valueManager.GetValue<AbsListView> (__this);
		IListAdapter listAdapter2 = value2.Adapter = Java.Interop.JavaConvert.FromJniHandle<IListAdapter> (value, JniHandleOwnership.DoNotTransfer);
	} catch (Exception ex) when (runtime.ExceptionShouldTransitionToJni (ex)) {
		jniTransition.SetPendingException (ex);
	} finally {
		jniTransition.Dispose ();
	}
}

and

using Android.Runtime;
using Java.Interop;
using System;

public static IntPtr n_getAdapter (IntPtr __jnienv, IntPtr __this)
{
	JniTransition jniTransition = new JniTransition (__jnienv);
	JniRuntime runtime = default(JniRuntime);
	try {
		runtime = JniEnvironment.Runtime;
		JniRuntime.JniValueManager valueManager = runtime.ValueManager;
		valueManager.WaitForGCBridgeProcessing ();
		AbsListView value = valueManager.GetValue<AbsListView> (__this);
		IListAdapter adapter = value.Adapter;
		return JNIEnv.ToLocalJniHandle (adapter);
	} catch (Exception ex) when (runtime.ExceptionShouldTransitionToJni (ex)) {
		jniTransition.SetPendingException (ex);
		return default(IntPtr);
	} finally {
		jniTransition.Dispose ();
	}
	IntPtr intPtr = default(IntPtr);
	return intPtr;
}

The Java.Interop submodule is bumped to have all the relevant fixes.

Profiling results of Xamarn.Forms test running on Pixel 2 XL phone:

Old marshaling

 133        1         15 Android.Runtime.JNIEnv:RegisterJniNatives (intptr,int,intptr,intptr,int)
 288        2          1 Android.Runtime.JNIEnv:Initialize (Android.Runtime.JnienvInitializeArgs*)

New marshaling

  68        1         15 Android.Runtime.JNIEnv:RegisterJniNatives (intptr,int,intptr,intptr,int)
 264        2          1 Android.Runtime.JNIEnv:Initialize (Android.Runtime.JnienvInitializeArgs*)

The native members registration is about 2 times faster and also the JNIEnv is about 20ms faster.

@radekdoulik radekdoulik added the do-not-merge PR should not be merged. label Sep 6, 2018
@radekdoulik
Copy link
Member Author

build

1 similar comment
@radekdoulik
Copy link
Member Author

build

public class JdkInfo : Task
{
[Output]
public string JdkJvmPath { get; set; }
Copy link
Contributor

@jonpryor jonpryor Sep 7, 2018

Choose a reason for hiding this comment

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

The addition of this task seems odd; I think it would make more sense to export this property in the <ResolveSdks/> task, a'la:

// Existing; line 84
JavaSdkPath    = MonoAndroidHelper.AndroidSdk.JavaSdkPath;

// New
try {
    var info = new JdkInfo (JavaSdkPath);
    JdkJvmPath = info.JdkJvmPath;
}
catch (Exception e) {
    Log.LogCodedError (...);
}

This way we ensure that we're consistent. By using JdkInfo.GetKnownSystemJdkInfos(), it's possible that <ResolveSdks/> will provide one JDK path, but JdkJvmPath could come from a different path. (Likely? I hope not, but possible, which is scary.)

Copy link
Member Author

Choose a reason for hiding this comment

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

Makes sense. That or use JavaSdkPath as an input for the task. I will try to extend the ResolveSdks first to see if it doesn't screw up the dependencies.

}
}

static Action<TraceLevel, string> CreateTaskLogger (Task task)
Copy link
Contributor

Choose a reason for hiding this comment

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

I already advocated for the removal of this task, but we already have this method, in Utilities/MSBuildExtensions.cs, as a .CreateTaskLogger() extension method.

DependsOnTargets="_ResolveAssemblies;_CreatePackageWorkspace;_GenerateJniMarshalMethods;_LinkAssembliesNoShrink;_LinkAssembliesShrink" />

<Target Name="_GenerateJniMarshalMethods"
Condition="'$(AndroidGenerateJniMarshalMethods)' == 'True' And '$(AndroidLinkMode)' != 'None'"
Copy link
Contributor

Choose a reason for hiding this comment

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

Code convention: attributes are indented an extra "tab stop" vs. child elements, thus:

<Target Name="_GenerateJniMarshalMethods"
    Condition="'$(AndroidGenerateJniMarshalMethods)' == 'True' And '$(AndroidLinkMode)' != 'None'"
    ...>
  <JdkInfo>
...

</JdkInfo>

<Exec
Command="MONO_PATH=$(_XATargetFrameworkDirectories) $(MonoAndroidBinDirectory)\mono $(MonoAndroidBinDirectory)\..\jnimarshalmethod-gen.exe --jvm=$(_AndroidJvmPath) @(ResolvedUserAssemblies->'$(MonoAndroidLinkerInputDir)%(Filename)%(Extension)', ' ')"
Copy link
Contributor

Choose a reason for hiding this comment

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

I suspect that this should be quoted: MONO_PATH=&quot;$(_XATargetFrameworkDirectories)&quot; ....

This should use $(MonoAndroidToolsDirectory) instead of $(MonoAndroidBinDirectory)\...

All parameters must be properly quoted, especially the @(ResolvedUserAssemblies->...) output, as those files are within the project directory, which could contain spaces.

Condition="'$(AndroidGenerateJniMarshalMethods)' == 'True' And '$(AndroidLinkMode)' != 'None'"
DependsOnTargets="_GetReferenceAssemblyPaths"
Inputs="@(ResolvedUserAssemblies->'$(MonoAndroidLinkerInputDir)%(Filename)%(Extension)')"
Outputs="$(_AndroidJniMarshalMethodsFlag)">
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we need a flag file and not the actual output assemblies, a'la _CreateIntermediateAssembliesDir?

Copy link
Member Author

Choose a reason for hiding this comment

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

We update the assemblies in place, so we need a flag.

@jonpryor
Copy link
Contributor

jonpryor commented Sep 7, 2018

The macOS PR Build is failing to build:

src/Xamarin.Android.NUnitLite/Xamarin.Android.NUnitLite.csproj(350,3): error MSB4019: The imported project "/Users/builder/jenkins/workspace/xamarin-android-pr-builder/xamarin-android/bin/Release/lib/xamarin.android/xbuild/Xamarin/Android/Xamarin.Android.CSharp.targets" was not found. Confirm that the path in the <Import> declaration is correct, and that the file exists on disk.

Er...what? That implies that Xamarin.Android.Build.Tasks.csproj isn't building?

Done Building Project "/Users/builder/jenkins/workspace/xamarin-android-pr-builder/xamarin-android/src/proguard/proguard.csproj" (default targets).
Done executing task "MSBuild" -- FAILED. (TaskId:1095)
Done building target "ResolveProjectReferences" in project "Xamarin.Android.Build.Tasks.csproj" -- FAILED.: (TargetId:1515)
Done Building Project "/Users/builder/jenkins/workspace/xamarin-android-pr-builder/xamarin-android/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj" (default targets) -- FAILED.

Xamarin.Android.Build.Tasks.csproj failed to build because proguard.csproj failed to build.

Which all seems rather odd; why are we trying to build Xamarin.Android.NUnitLite.csproj when it's dependency failed?

Why did the dependency fail to build?

In short, I'm finding this log file confusing. :-(

Worse, it gets more confusing:

Target "_InstallRuntimes: (TargetId:814)" in file "/Users/builder/jenkins/workspace/xamarin-android-pr-builder/xamarin-android/src/mono-runtimes/mono-runtimes.targets" from project "/Users/builder/jenkins/workspace/xamarin-android-pr-builder/xamarin-android/src/mono-runtimes/mono-runtimes.csproj
...
Task "Exec" (TaskId:613)
  Task Parameter:Command=""  "/Users/builder/jenkins/workspace/xamarin-android-pr-builder/xamarin-android/bin/Release/lib/xamarin.android/xbuild/Xamarin/Android/" (TaskId:613)
  ""  "/Users/builder/jenkins/workspace/xamarin-android-pr-builder/xamarin-android/bin/Release/lib/xamarin.android/xbuild/Xamarin/Android/" (TaskId:613)
  /var/folders/19/hjm21bn17913_0ck7nh3thdr0000gn/T/tmp5f93c396a869422e93beeaf4a0de90fe.exec.cmd: line 2: : command not found (TaskId:613)
/Users/builder/jenkins/workspace/xamarin-android-pr-builder/xamarin-android/src/mono-runtimes/mono-runtimes.targets(413,5): error MSB3073: The command """  "/Users/builder/jenkins/workspace/xamarin-android-pr-builder/xamarin-android/bin/Release/lib/xamarin.android/xbuild/Xamarin/Android/"" exited with code 127. [/Users/builder/jenkins/workspace/xamarin-android-pr-builder/xamarin-android/src/mono-runtimes/mono-runtimes.csproj]
Done executing task "Exec" -- FAILED. (TaskId:613)
Done building target "_InstallRuntimes" in project "mono-runtimes.csproj" -- FAILED.: (TargetId:814)
Done Building Project "/Users/builder/jenkins/workspace/xamarin-android-pr-builder/xamarin-android/src/mono-runtimes/mono-runtimes.csproj" (ForceBuild target(s)) -- FAILED.
Done executing task "MSBuild" -- FAILED. (TaskId:577)

I guess %(_MonoRuntime.Strip) isn't defined? https://github.com/xamarin/xamarin-android/blob/01aa6d98b7f68f0430b0cc827ef495005f6d962a/src/mono-runtimes/mono-runtimes.targets#L443

This PR has nothing to do with mono-runtimes.csproj. Why is it failing? Is the parent commit "bad"?

@radekdoulik radekdoulik force-pushed the pr-generate-jni-marshal-methods branch 2 times, most recently from 54a59f0 to 3f3e073 Compare September 12, 2018 14:00
@radekdoulik
Copy link
Member Author

build

@jonpryor
Copy link
Contributor

Could the MonoTests.System.Net.Http.HttpClientTest.CancelRequestViaProxy() failure possibly be related to this PR?

@radekdoulik
Copy link
Member Author

radekdoulik commented Sep 17, 2018

I hope it is not related. Retrying the build.

@radekdoulik
Copy link
Member Author

Retried build failed in weird way:

Task "Exec" (TaskId:489)
  Task Parameter:Command=MONO_PATH="/Users/builder/jenkins/workspace/xamarin-android-pr-builder/xamarin-android/bin/Release/lib/xamarin.android/xbuild-frameworks/MonoAndroid/v1.0/" "/Users/builder/jenkin
s/workspace/xamarin-android-pr-builder/xamarin-android/bin/Release/lib/xamarin.android/xbuild/Xamarin/Android/Darwin//mono" "/Users/builder/jenkins/workspace/xamarin-android-pr-builder/xamarin-android/bi
n/Release/lib/xamarin.android/xbuild/Xamarin/Android/jnimarshalmethod-gen.exe" --jvm="/Library/Java/JavaVirtualMachines/jdk1.8.0_91.jdk/Contents/Home/jre/lib/jli/libjli.dylib" "obj/Release/linksrc/Mono.A
ndroid-Tests.dll" "obj/Release/linksrc/TestRunner.Core.dll" "obj/Release/linksrc/TestRunner.NUnit.dll" "obj/Release/linksrc/Mono.Android.dll" "obj/Release/linksrc/Xamarin.Android.NUnitLite.dll" (TaskId:4
89)
  MONO_PATH="/Users/builder/jenkins/workspace/xamarin-android-pr-builder/xamarin-android/bin/Release/lib/xamarin.android/xbuild-frameworks/MonoAndroid/v1.0/" "/Users/builder/jenkins/workspace/xamarin-and
roid-pr-builder/xamarin-android/bin/Release/lib/xamarin.android/xbuild/Xamarin/Android/Darwin//mono" "/Users/builder/jenkins/workspace/xamarin-android-pr-builder/xamarin-android/bin/Release/lib/xamarin.a
ndroid/xbuild/Xamarin/Android/jnimarshalmethod-gen.exe" --jvm="/Library/Java/JavaVirtualMachines/jdk1.8.0_91.jdk/Contents/Home/jre/lib/jli/libjli.dylib" "obj/Release/linksrc/Mono.Android-Tests.dll" "obj/
Release/linksrc/TestRunner.Core.dll" "obj/Release/linksrc/TestRunner.NUnit.dll" "obj/Release/linksrc/Mono.Android.dll" "obj/Release/linksrc/Xamarin.Android.NUnitLite.dll" (TaskId:489)
EXEC : 7 [monodroid] mono runtime initialization error : (null) [/Users/builder/jenkins/workspace/xamarin-android-pr-builder/xamarin-android/src/Mono.Android/Test/Mono.Android-Tests.csproj]
/Users/builder/jenkins/workspace/xamarin-android-pr-builder/xamarin-android/bin/Release/lib/xamarin.android/xbuild/Xamarin/Android/Xamarin.Android.Common.targets(2097,3): error MSB3073: The command "MONO
_PATH="/Users/builder/jenkins/workspace/xamarin-android-pr-builder/xamarin-android/bin/Release/lib/xamarin.android/xbuild-frameworks/MonoAndroid/v1.0/" "/Users/builder/jenkins/workspace/xamarin-android-p
r-builder/xamarin-android/bin/Release/lib/xamarin.android/xbuild/Xamarin/Android/Darwin//mono" "/Users/builder/jenkins/workspace/xamarin-android-pr-builder/xamarin-android/bin/Release/lib/xamarin.android
/xbuild/Xamarin/Android/jnimarshalmethod-gen.exe" --jvm="/Library/Java/JavaVirtualMachines/jdk1.8.0_91.jdk/Contents/Home/jre/lib/jli/libjli.dylib" "obj/Release/linksrc/Mono.Android-Tests.dll" "obj/Releas
e/linksrc/TestRunner.Core.dll" "obj/Release/linksrc/TestRunner.NUnit.dll" "obj/Release/linksrc/Mono.Android.dll" "obj/Release/linksrc/Xamarin.Android.NUnitLite.dll"" exited with code 1. [/Users/builder/j
enkins/workspace/xamarin-android-pr-builder/xamarin-android/src/Mono.Android/Test/Mono.Android-Tests.csproj]
Done executing task "Exec" -- FAILED. (TaskId:489)

I guess it might be regression caused by 95ca102

@radekdoulik radekdoulik force-pushed the pr-generate-jni-marshal-methods branch from ad619d9 to 778d9e4 Compare October 2, 2018 10:56
<_AssembliesToProcess Include="@(ResolvedAssemblies)" Condition=" '%(Filename)' != '' And '@(_JniFrameworkAssembly)' != '' " />
</ItemGroup>
<Exec
Command="MONO_PATH=&quot;$(_XATargetFrameworkDirectories)&quot; &quot;$(MonoAndroidBinDirectory)\mono&quot; &quot;$(MonoAndroidToolsDirectory)\jnimarshalmethod-gen.exe&quot; --jvm=&quot;$(JdkJvmPath)&quot; @(_AssembliesToProcess->'&quot;$(MonoAndroidLinkerInputDir)%(Filename)%(Extension)&quot;', ' ')"
Copy link
Contributor

Choose a reason for hiding this comment

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

@jonpryor what is our preference there? using Exec or writing a Task to do this job?
If we add a test... we can add a unit test.....

Copy link
Member Author

Choose a reason for hiding this comment

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

@dellis1972, I am not sure what do you propose here. To have a task to run mono, similar to Adb task, or a task to generate the marshal methods?

Copy link
Contributor

Choose a reason for hiding this comment

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

@radekdoulik that is a good point. How will this work on windows? mono is not installed as part of windows.

Copy link
Contributor

Choose a reason for hiding this comment

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

It might be a good idea to use mono --debug here, to get filename & line number information from exception messages.

Copy link
Contributor

Choose a reason for hiding this comment

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

@dellis1972: We'll need to update the Xamarin.Android install so that we do install mono on Windows (and macOS, for that matter).

@radekdoulik: Either this PR or another will need to update src/mono-runtimes so that mono.exe for Windows is included into the bundle. A Darwin mono is already being included.

@radekdoulik: This may in turn require more "flexibility": iirc Mono on Windows has both a mono.exe and a monow.exe, which differ only on the Windows Subsystems that they target. Executing mono.exe may result in a "console window" "flashing" on the user's screen, which is really annoying. monow.exe won't cause such flashing, iirc.

Or we might want to use a dedicated Task, as @dellis1972 suggests, either so that we can use monow on Windows, or so that we can use a specific System.Diagnostics.Process which sets ProcessStartInfo.CreateNoWindow=true and ProcessStartInfo.WindowStyle=ProcessWindowStyle.Hidden, as is done elsewhere.

@jonpryor
Copy link
Contributor

The macOS PR Build failed after 36 minutes, so something horrific broke:

  MONO_PATH="/Users/builder/jenkins/workspace/xamarin-android-pr-builder/xamarin-android/bin/Release/lib/xamarin.android/xbuild-frameworks/MonoAndroid/v1.0/" "/Users/builder/jenkins/workspace/xamarin-android-pr-builder/xamarin-android/bin/Release/lib/xamarin.android/xbuild/Xamarin/A
ndroid/Darwin//mono" "/Users/builder/jenkins/workspace/xamarin-android-pr-builder/xamarin-android/bin/Release/lib/xamarin.android/xbuild/Xamarin/Android/jnimarshalmethod-gen.exe" --jvm="/Library/Java/JavaVirtualMachines/jdk1.8.0_91.jdk/Contents/Home/jre/lib/jli/libjli.dylib" "obj/Re
lease/linksrc/Mono.Android-Tests.dll" "obj/Release/linksrc/TestRunner.Core.dll" "obj/Release/linksrc/TestRunner.NUnit.dll" "obj/Release/linksrc/Mono.Android.dll" "obj/Release/linksrc/Xamarin.Android.NUnitLite.dll" (TaskId:480)
EXEC : error : jnimarshalmethod-gen: Unable to process assembly 'obj/Release/linksrc/Mono.Android-Tests.dll' [/Users/builder/jenkins/workspace/xamarin-android-pr-builder/xamarin-android/src/Mono.Android/Test/Mono.Android-Tests.csproj]
  Exception of type 'System.Reflection.ReflectionTypeLoadException' was thrown. (TaskId:480)
  System.Reflection.ReflectionTypeLoadException: Exception of type 'System.Reflection.ReflectionTypeLoadException' was thrown. (TaskId:480)
    at (wrapper managed-to-native) System.Reflection.Assembly.GetTypes(System.Reflection.Assembly,bool) (TaskId:480)
    at System.Reflection.Assembly.GetTypes () [0x00000] in <1e29a365ebcf4c9f8941ffa268f5d648>:0  (TaskId:480)
    at System.Reflection.Assembly+<get_DefinedTypes>d__141.MoveNext () [0x0001e] in <1e29a365ebcf4c9f8941ffa268f5d648>:0  (TaskId:480)
    at Xamarin.Android.Tools.JniMarshalMethodGenerator.App.CreateMarshalMethodAssembly (System.String path) [0x0034f] in <2828aaf78591440089c9e2389e7061cf>:0  (TaskId:480)
    at Xamarin.Android.Tools.JniMarshalMethodGenerator.App.ProcessAssemblies (System.Collections.Generic.List`1[T] assemblies) [0x0010a] in <2828aaf78591440089c9e2389e7061cf>:0  (TaskId:480)
/Users/builder/jenkins/workspace/xamarin-android-pr-builder/xamarin-android/bin/Release/lib/xamarin.android/xbuild/Xamarin/Android/Xamarin.Android.Common.targets(2096,3): error MSB3073: The command "MONO_PATH="/Users/builder/jenkins/workspace/xamarin-android-pr-builder/xamarin-android/bin/Release/lib/xamarin.android/xbuild-frameworks/MonoAndroid/v1.0/" "/Users/builder/jenkins/workspace/xamarin-android-pr-builder/xamarin-android/bin/Release/lib/xamarin.android/xbuild/Xamarin/Android/Darwin//mono" "/Users/builder/jenkins/workspace/xamarin-android-pr-builder/xamarin-android/bin/Release/lib/xamarin.android/xbuild/Xamarin/Android/jnimarshalmethod-gen.exe" --jvm="/Library/Java/JavaVirtualMachines/jdk1.8.0_91.jdk/Contents/Home/jre/lib/jli/libjli.dylib" "obj/Release/linksrc/Mono.Android-Tests.dll" "obj/Release/linksrc/TestRunner.Core.dll" "obj/Release/linksrc/TestRunner.NUnit.dll" "obj/Release/linksrc/Mono.Android.dll" "obj/Release/linksrc/Xamarin.Android.NUnitLite.dll"" exited with code 1. [/Users/builder/jenkins/workspace/xamarin-android-pr-builder/xamarin-android/src/Mono.Android/Test/Mono.Android-Tests.csproj]
Done executing task "Exec" -- FAILED. (TaskId:480)

<_AssembliesToProcess Include="@(ResolvedAssemblies)" Condition=" '%(Filename)' != '' And '@(_JniFrameworkAssembly)' != '' " />
</ItemGroup>
<Exec
Command="MONO_PATH=&quot;$(_XATargetFrameworkDirectories)&quot; &quot;$(MonoAndroidBinDirectory)\mono&quot; &quot;$(MonoAndroidToolsDirectory)\jnimarshalmethod-gen.exe&quot; --jvm=&quot;$(JdkJvmPath)&quot; @(_AssembliesToProcess->'&quot;$(MonoAndroidLinkerInputDir)%(Filename)%(Extension)&quot;', ' ')"
Copy link
Contributor

Choose a reason for hiding this comment

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

It might be a good idea to use mono --debug here, to get filename & line number information from exception messages.

<_AssembliesToProcess Include="@(ResolvedAssemblies)" Condition=" '%(Filename)' != '' And '@(_JniFrameworkAssembly)' != '' " />
</ItemGroup>
<Exec
Command="MONO_PATH=&quot;$(_XATargetFrameworkDirectories)&quot; &quot;$(MonoAndroidBinDirectory)\mono&quot; &quot;$(MonoAndroidToolsDirectory)\jnimarshalmethod-gen.exe&quot; --jvm=&quot;$(JdkJvmPath)&quot; @(_AssembliesToProcess->'&quot;$(MonoAndroidLinkerInputDir)%(Filename)%(Extension)&quot;', ' ')"
Copy link
Contributor

Choose a reason for hiding this comment

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

@dellis1972: We'll need to update the Xamarin.Android install so that we do install mono on Windows (and macOS, for that matter).

@radekdoulik: Either this PR or another will need to update src/mono-runtimes so that mono.exe for Windows is included into the bundle. A Darwin mono is already being included.

@radekdoulik: This may in turn require more "flexibility": iirc Mono on Windows has both a mono.exe and a monow.exe, which differ only on the Windows Subsystems that they target. Executing mono.exe may result in a "console window" "flashing" on the user's screen, which is really annoying. monow.exe won't cause such flashing, iirc.

Or we might want to use a dedicated Task, as @dellis1972 suggests, either so that we can use monow on Windows, or so that we can use a specific System.Diagnostics.Process which sets ProcessStartInfo.CreateNoWindow=true and ProcessStartInfo.WindowStyle=ProcessWindowStyle.Hidden, as is done elsewhere.

@radekdoulik
Copy link
Member Author

The macOS PR Build failed after 36 minutes, so something horrific broke:

Yup, that looks like another System.Reflection behavior change after mono-2018-06 bump. I will need to handle System.Reflection.ReflectionTypeLoadException. Unfortunately I have trouble building XA from scratch at the moment, so either I will try to fix it and run on build bots or find out why I get errors in XA's make prepare.

@radekdoulik
Copy link
Member Author

I am unable to repro even with clean build. So restarted the build to see whether it is a real issue.

The new marshaling code uses `JniValueManager`, so we don't want to
trow here. Just keep it empty to make things work, until we have
proper implementation of it.
Bump Java.Interop to get all the fixes for jnimarshalmethod-gen.exe
and value manager marshaling. That fixes all the remaining issues in
the XF test with JNI marshal methods enabled.

Finally enable the marshaling in the XF test.
As new marshaling is an experimental feature, it is convenient to get
more information when something breaks.
Until we have the mono[w].exe in the bundle and are able to run
jnimarshalmethod-gen.exe on Windows
That might hopefully fix the type loading problems
JI tests overwrite Java.Runtime.Environment.dll.config. The original
updated config file is needed for apk tests as some of them now use
jnimarshalmethod-gen.exe tool.
To allow passing of additional arguments to the
`jnimarshalmethod-gen.exe` tool. This comes handy when debugging, so
that one can pass options like `-v`, `-d` or `--keeptemp` easily.
Fixes dotnet/java-interop#387

The custom value marshaler takes care about marshaling the `Color` as
`int` and thus avoiding proxy objects and their marshaling.
Once dotnet/java-interop#389 is merged, it
should fix dotnet/java-interop#388

Example of updated marshalers:

    using Android.Runtime;
    using Java.Interop;
    using System;

    public static void n_setAdapter_Landroid_widget_ListAdapter_ (IntPtr __jnienv, IntPtr __this, IntPtr value)
    {
    	JniTransition jniTransition = new JniTransition (__jnienv);
    	JniRuntime runtime = default(JniRuntime);
    	try {
    		runtime = JniEnvironment.Runtime;
    		JniRuntime.JniValueManager valueManager = runtime.ValueManager;
    		valueManager.WaitForGCBridgeProcessing ();
    		AbsListView value2 = valueManager.GetValue<AbsListView> (__this);
    		IListAdapter listAdapter2 = value2.Adapter = Java.Interop.JavaConvert.FromJniHandle<IListAdapter> (value, JniHandleOwnership.DoNotTransfer);
    	} catch (Exception ex) when (runtime.ExceptionShouldTransitionToJni (ex)) {
    		jniTransition.SetPendingException (ex);
    	} finally {
    		jniTransition.Dispose ();
    	}
    }

and

    using Android.Runtime;
    using Java.Interop;
    using System;

    public static IntPtr n_getAdapter (IntPtr __jnienv, IntPtr __this)
    {
    	JniTransition jniTransition = new JniTransition (__jnienv);
    	JniRuntime runtime = default(JniRuntime);
    	try {
    		runtime = JniEnvironment.Runtime;
    		JniRuntime.JniValueManager valueManager = runtime.ValueManager;
    		valueManager.WaitForGCBridgeProcessing ();
    		AbsListView value = valueManager.GetValue<AbsListView> (__this);
    		IListAdapter adapter = value.Adapter;
    		return JNIEnv.ToLocalJniHandle (adapter);
    	} catch (Exception ex) when (runtime.ExceptionShouldTransitionToJni (ex)) {
    		jniTransition.SetPendingException (ex);
    		return default(IntPtr);
    	} finally {
    		jniTransition.Dispose ();
    	}
    	IntPtr intPtr = default(IntPtr);
    	return intPtr;
    }
... when building the tests, which use jnimarshalmethod-gen.exe
Log.LogCodedError ("XA5300", $"Unable to find {nameof (JdkJvmPath)}{Environment.NewLine}{e}");
return false;
}

Copy link
Member

Choose a reason for hiding this comment

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

@radekdoulik quick question about this task. There is a Visual Studio team very focused on the performance of "solution create", which is basically the initial design-time build from our targets.

Since looking up JdkJvmPath takes extra time, could it:

  • Not run on DesignTimeBuild=True?
  • Not run unless AndroidGenerateJniMarshalMethods=True?
  • It also might be worth splitting this out into another MSBuild task?

Copy link
Member Author

Choose a reason for hiding this comment

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

It is now only used by jnimarshalmethod-gen, so we can look it up only when AndroidGenerateJniMarshalMethods is true

Copy link
Member

Choose a reason for hiding this comment

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

Ok, cool. I might look at making those changes ^^ I'll have you review.

Might not happen this week, though. 😃

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.

Problem with Android.Graphics.Paint.Color property marshalers

4 participants