Skip to content

Commit 8c83f64

Browse files
committed
[Java.Interop] "Java Activation": API Declaration
Next can-o'-worms to start implementing: Java Activation: http://docs.xamarin.com/guides/android/under_the_hood/architecture/#Java_Activation There are logically two ways to create a "managed peer"/"native peer" instance pair: 1. By creating the managed peer, which will automagically create the native peer instance (see the JavaObject default constructor); or 2. By creating the native peer. (1) is implemented. (2) has not been, meaning at present if Java code were to create an instance of a "native peer", no corresponding managed peer instance would be created, and thus any `native` methods wouldn't be registered, and things would blow up rather quickly. How should this be exposed? Xamarin.Android has two related methods: * mono.android.Runtime.register(): registers native methods for a Java class. * mono.android.TypeManager.Activate(): invoked by the Java constructor, and responsible for associating the native peer with a managed peer, creating a new managed peer if necessary. The pattern for TypeManager.Activate() invocation is as follows: // Xamarin.Android constructor style public JavaPeerType(Args... args) { super (args...); if (getClass() == JavaPeerType.class) TypeManager.Activate ( AssemblyQualifiedTypeName, ConstructorSignature, this, new java.lang.Object[]{ args } ); } The need for the getClass() check is so that TypeManager.Activate() is only executed once, on the most derived native peer type, and not once per type in the inheritance chain. My feeling is that Runtime.register() and TypeManager.Activate() should be more closely related, because they both operate on peer types. (Runtime.register() is also a semantically poor name, and the it's only in Runtime for "where else should we put it?" reasons.) The alternative Java.Interop API? ManagedPeer.runConstructor() (and later, ManagedPeer.registerNativeMethods()), which also alters parameter ordering and now takes the Class for the declaring class: // Java.Interop constructor style: public JavaPeerType(Args... args) { super (args...); ManagedPeer.runConstructor ( JavaPeerType.class, this, AssemblyQualifiedTypeName, ConstructorSignature, args... ); } This "moves" the getClass() check into ManagedPeer.runConstructor(), allowing ManagedPeer methods to consistently take a Class instance, and also provides possible future flexibility on behavior. ManagedPeer.runConstructor() doesn't do anything at this time; this is just stubbing out the API, adding the appropriate calls to our Java "native peer" test types, and providing the initial C# implementation.
1 parent 084a8f4 commit 8c83f64

11 files changed

+131
-1
lines changed

src/Java.Interop/Java.Interop.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,12 @@
9191
<Compile Include="Java.Interop\JavaProxyThrowable.cs" />
9292
<Compile Include="Java.Interop\JniEnvironment.Errors.cs" />
9393
<Compile Include="Java.Interop\JniMarshalMethod.cs" />
94+
<Compile Include="Java.Interop\ManagedPeer.cs" />
9495
</ItemGroup>
9596
<ItemGroup>
9697
<CompileJavaInteropJar Include="java\com\xamarin\android\internal\JavaProxyObject.java" />
9798
<CompileJavaInteropJar Include="java\com\xamarin\android\internal\JavaProxyThrowable.java" />
99+
<CompileJavaInteropJar Include="java\com\xamarin\android\ManagedPeer.java" />
98100
</ItemGroup>
99101
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
100102
<PropertyGroup>

src/Java.Interop/Java.Interop/JavaVM.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,8 @@ protected JavaVM (JavaVMOptions options)
177177
}
178178

179179
JavaVMs.TryAdd (SafeHandle.DangerousGetHandle (), this);
180+
181+
ManagedPeer.Init ();
180182
}
181183

182184
~JavaVM ()
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
using System;
2+
using System.Diagnostics;
3+
using System.Reflection;
4+
using System.Text;
5+
6+
namespace Java.Interop {
7+
8+
[JniTypeInfo (ManagedPeer.JniTypeName)]
9+
/* static */ class ManagedPeer : JavaObject {
10+
11+
internal const string JniTypeName = "com/xamarin/android/ManagedPeer";
12+
13+
14+
static readonly JniPeerMembers _members = new JniPeerMembers (JniTypeName, typeof (ManagedPeer));
15+
16+
static ManagedPeer ()
17+
{
18+
_members.JniPeerType.RegisterNativeMethods (
19+
new JniNativeMethodRegistration ("runConstructor", RunConstructorSignature, (Action<IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, IntPtr>) RunConstructor)
20+
);
21+
}
22+
23+
ManagedPeer ()
24+
{
25+
}
26+
27+
internal static void Init ()
28+
{
29+
// Present so that JavaVM has _something_ to reference to
30+
// prompt invocation of the static constructor & registration
31+
}
32+
33+
public override JniPeerMembers JniPeerMembers {
34+
get {return _members;}
35+
}
36+
37+
const string RunConstructorSignature = "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V";
38+
39+
static void RunConstructor (
40+
IntPtr jnienv,
41+
IntPtr klass,
42+
IntPtr n_self,
43+
IntPtr n_assemblyQualifiedName,
44+
IntPtr n_constructorSignature,
45+
IntPtr n_constructorArguments)
46+
{
47+
}
48+
}
49+
}
50+

src/Java.Interop/Tests/Java.Interop-Tests.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@
9696
</ItemGroup>
9797
<Target Name="BuildJars" Inputs="@(JavaInteropTestJar)" Outputs="@(TestJar)">
9898
<MakeDir Directories="$(OutputPath)it-classes" />
99-
<Exec Command="javac -d &quot;$(OutputPath)it-classes&quot; @(JavaInteropTestJar -&gt; '%(Identity)', ' ')" />
99+
<Exec Command="javac -d &quot;$(OutputPath)it-classes&quot; -classpath &quot;$(OutputPath)\java-interop.jar&quot; @(JavaInteropTestJar -&gt; '%(Identity)', ' ')" />
100100
<Exec Command="jar cf &quot;$(OutputPath)interop-test.jar&quot; -C &quot;$(OutputPath)it-classes&quot; ." />
101101
</Target>
102102
<ItemGroup>

src/Java.Interop/Tests/java/com/xamarin/interop/CallNonvirtualBase.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22

33
public class CallNonvirtualBase {
44

5+
public CallNonvirtualBase () {
6+
com.xamarin.android.ManagedPeer.runConstructor (
7+
CallNonvirtualBase.class,
8+
this,
9+
"Java.InteropTests.CallNonvirtualBase, Java.Interop-Tests, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null",
10+
""
11+
);
12+
}
13+
514
boolean methodInvoked;
615
public void method () {
716
System.out.println ("CallNonvirtualBase.method() invoked!");

src/Java.Interop/Tests/java/com/xamarin/interop/CallNonvirtualDerived.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22

33
public class CallNonvirtualDerived extends CallNonvirtualBase {
44

5+
public CallNonvirtualDerived () {
6+
com.xamarin.android.ManagedPeer.runConstructor (
7+
CallNonvirtualDerived.class,
8+
this,
9+
"Java.InteropTests.CallNonvirtualDerived, Java.Interop-Tests, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null",
10+
""
11+
);
12+
}
13+
514
boolean methodInvoked;
615
public void method () {
716
System.out.println ("CallNonvirtualDerived.method() invoked!");
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
11
package com.xamarin.interop;
22

33
public class CallNonvirtualDerived2 extends CallNonvirtualDerived {
4+
5+
public CallNonvirtualDerived2 () {
6+
com.xamarin.android.ManagedPeer.runConstructor (
7+
CallNonvirtualDerived2.class,
8+
this,
9+
"Java.InteropTests.CallNonvirtualDerived2, Java.Interop-Tests, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null",
10+
""
11+
);
12+
}
413
}

src/Java.Interop/Tests/java/com/xamarin/interop/CallVirtualFromConstructorBase.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@
33
public class CallVirtualFromConstructorBase {
44

55
public CallVirtualFromConstructorBase (int value) {
6+
com.xamarin.android.ManagedPeer.runConstructor (
7+
CallVirtualFromConstructorBase.class,
8+
this,
9+
"Java.InteropTests.CallVirtualFromConstructorBase, Java.Interop-Tests, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null",
10+
"System.Int32",
11+
value
12+
);
613
calledFromConstructor (value);
714
}
815

src/Java.Interop/Tests/java/com/xamarin/interop/CallVirtualFromConstructorDerived.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@ public class CallVirtualFromConstructorDerived extends CallVirtualFromConstructo
44

55
public CallVirtualFromConstructorDerived (int value) {
66
super (value);
7+
com.xamarin.android.ManagedPeer.runConstructor (
8+
CallVirtualFromConstructorDerived.class,
9+
this,
10+
"Java.InteropTests.CallVirtualFromConstructorDerived, Java.Interop-Tests, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null",
11+
"System.Int32",
12+
value
13+
);
714
}
815

916
public native void calledFromConstructor (int value);

src/Java.Interop/Tests/java/com/xamarin/interop/TestType.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22

33
public class TestType {
44

5+
public TestType () {
6+
com.xamarin.android.ManagedPeer.runConstructor (
7+
TestType.class,
8+
this,
9+
"Java.InteropTests.TestType, Java.Interop-Tests, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null",
10+
""
11+
);
12+
}
13+
514
public void runTests () {
615
int n = getInt32Value ();
716
if (getInt32Value() != 42)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.xamarin.android;
2+
3+
public /* static */ class ManagedPeer {
4+
private ManagedPeer () {
5+
}
6+
7+
// public static native void registerNativeMethods (java.lang.Class<?> nativeClass, String managedType, String methods);
8+
9+
public static void runConstructor (
10+
Class<?> declaringClass,
11+
Object self,
12+
String assemblyQualifiedName,
13+
String constructorSignature,
14+
Object... arguments) {
15+
if (self.getClass() != declaringClass)
16+
return;
17+
runConstructor (self, assemblyQualifiedName, constructorSignature, arguments);
18+
}
19+
20+
static native void runConstructor (
21+
Object self,
22+
String assemblyQualifiedName,
23+
String constructorSignature,
24+
Object... arguments
25+
);
26+
}

0 commit comments

Comments
 (0)