Skip to content

Commit cba6137

Browse files
authored
[Java.Interop] Add JniRuntime.JniValueManager.ActivatePeer() (#784)
Context: dotnet/android#5400 The `Java.Interop.ManagedPeer` type uses `System.Linq.Expressions` in order to invoke a constructor as part of Java-side activation; see also 8c83f64. The use of `System.Linq.Expressions` and `JniRuntime.JniMarshalMemberBuilder.CreateConstructActivationPeerFunc()` increases Xamarin.Android `.apk` size by ~136KB, which is undesirable as ~no Xamarin.Android apps *use* `ManagedPeer`, other than the `Mono.Android-Tests` unit test app. Add a new `JniRuntime.JniValueManager.ActivatePeer()` method, which `ManagedPeer.Construct()` can now call instead of `CreateConstructActivationPeerFunc()`. This allows the `CreateConstructActivationPeerFunc()` invocation to be moved into `Java.Runtime.Environment.dll`. (Xamarin.Android instead uses `System.Reflection.Emit`, and doesn't use `System.Linq.Expressions`.) This in turn means that `System.Linq.Expressions` is no longer used in the "default" Xamarin.Android app case, allowing smaller `.apk`s.
1 parent 8c7194f commit cba6137

File tree

6 files changed

+70
-29
lines changed

6 files changed

+70
-29
lines changed

src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ protected virtual void Dispose (bool disposing)
8686

8787
public abstract List<JniSurfacedPeerInfo> GetSurfacedPeers ();
8888

89+
public abstract void ActivatePeer (IJavaPeerable? self, JniObjectReference reference, ConstructorInfo cinfo, object? []? argumentValues);
90+
8991
public void ConstructPeer (IJavaPeerable peer, ref JniObjectReference reference, JniObjectReferenceOptions options)
9092
{
9193
if (peer == null)

src/Java.Interop/Java.Interop/ManagedPeer.cs

Lines changed: 17 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -93,31 +93,17 @@ static void Construct (
9393

9494
var ptypes = GetParameterTypes (JniEnvironment.Strings.ToString (n_constructorSignature));
9595
var pvalues = GetValues (runtime, new JniObjectReference (n_constructorArguments), ptypes);
96-
var ctor = type.GetConstructors (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
97-
.FirstOrDefault (c =>
98-
c.GetParameters ().Select (p => p.ParameterType).SequenceEqual (ptypes));
99-
if (ctor == null) {
96+
var cinfo = type.GetConstructor (ptypes);
97+
if (cinfo == null) {
10098
throw CreateMissingConstructorException (type, ptypes);
10199
}
100+
102101
if (self != null) {
103-
ctor.Invoke (self, pvalues);
102+
cinfo.Invoke (self, pvalues);
104103
return;
105104
}
106105

107-
try {
108-
var f = JniEnvironment.Runtime.MarshalMemberBuilder.CreateConstructActivationPeerFunc (ctor);
109-
f (ctor, new JniObjectReference (n_self), pvalues);
110-
}
111-
catch (Exception e) {
112-
var m = string.Format ("Could not activate {{ PeerReference={0} IdentityHashCode=0x{1} Java.Type={2} }} for managed type '{3}'.",
113-
r_self,
114-
runtime.ValueManager.GetJniIdentityHashCode (r_self).ToString ("x"),
115-
JniEnvironment.Types.GetJniTypeNameFromInstance (r_self),
116-
type.FullName);
117-
Debug.WriteLine (m);
118-
119-
throw new NotSupportedException (m, e);
120-
}
106+
JniEnvironment.Runtime.ValueManager.ActivatePeer (self, new JniObjectReference (n_self), cinfo, pvalues);
121107
}
122108
catch (Exception e) when (JniEnvironment.Runtime.ExceptionShouldTransitionToJni (e)) {
123109
envp.SetPendingException (e);
@@ -127,29 +113,33 @@ static void Construct (
127113
}
128114
}
129115

130-
static Exception CreateJniLocationException ()
131-
{
132-
using (var e = new JavaException ()) {
133-
return new JniLocationException (e.ToString ());
134-
}
135-
}
136-
137-
static Exception CreateMissingConstructorException (Type type, Type[] ptypes)
116+
static Exception CreateMissingConstructorException (Type type, Type [] ptypes)
138117
{
139118
var message = new StringBuilder ();
140119
message.Append ("Unable to find constructor ");
141120
message.Append (type.FullName);
142121
message.Append ("(");
122+
143123
if (ptypes.Length > 0) {
144124
message.Append (ptypes [0].FullName);
145125
for (int i = 1; i < ptypes.Length; ++i)
146126
message.Append (", ").Append (ptypes [i].FullName);
147127
}
128+
148129
message.Append (")");
149130
message.Append (". Please provide the missing constructor.");
131+
150132
return new NotSupportedException (message.ToString (), CreateJniLocationException ());
151133
}
152134

135+
136+
static Exception CreateJniLocationException ()
137+
{
138+
using (var e = new JavaException ()) {
139+
return new JniLocationException (e.ToString ());
140+
}
141+
}
142+
153143
static Type[] GetParameterTypes (string? signature)
154144
{
155145
if (string.IsNullOrEmpty (signature))

src/Java.Interop/Properties/AssemblyInfo.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,10 @@
2828
"814f144e5d817efc4c6502cc012df310783348304e3ae38573c6d658c234025821fda87a0be8a0" +
2929
"d504df564e2c93b2b878925f42503e9d54dfef9f9586d9e6f38a305769587b1de01f6c0410328b" +
3030
"2c9733db")]
31+
[assembly: InternalsVisibleTo (
32+
"Java.Runtime.Environment, PublicKey=" +
33+
"0024000004800000940000000602000000240000525341310004000011000000438ac2a5acfbf1" +
34+
"6cbd2b2b47a62762f273df9cb2795ceccdf77d10bf508e69e7a362ea7a45455bbf3ac955e1f2e2" +
35+
"814f144e5d817efc4c6502cc012df310783348304e3ae38573c6d658c234025821fda87a0be8a0" +
36+
"d504df564e2c93b2b878925f42503e9d54dfef9f9586d9e6f38a305769587b1de01f6c0410328b" +
37+
"2c9733db")]

src/Java.Runtime.Environment/Java.Interop/MonoRuntimeValueManager.cs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1-
using System;
1+
using System;
22
using System.Collections.Generic;
3+
using System.Diagnostics;
4+
using System.Linq;
5+
using System.Reflection;
36
using System.Runtime.CompilerServices;
47
using System.Runtime.InteropServices;
8+
using System.Text;
59

610
namespace Java.Interop {
711

@@ -229,6 +233,32 @@ public override IJavaPeerable PeekPeer (JniObjectReference reference)
229233
return null;
230234
}
231235

236+
static Exception CreateJniLocationException ()
237+
{
238+
using (var e = new JavaException ()) {
239+
return new JniLocationException (e.ToString ());
240+
}
241+
}
242+
243+
public override void ActivatePeer (IJavaPeerable self, JniObjectReference reference, ConstructorInfo cinfo, object [] argumentValues)
244+
{
245+
var runtime = JniEnvironment.Runtime;
246+
247+
try {
248+
var f = runtime.MarshalMemberBuilder.CreateConstructActivationPeerFunc (cinfo);
249+
f (cinfo, reference, argumentValues);
250+
} catch (Exception e) {
251+
var m = string.Format ("Could not activate {{ PeerReference={0} IdentityHashCode=0x{1} Java.Type={2} }} for managed type '{3}'.",
252+
reference,
253+
runtime.ValueManager.GetJniIdentityHashCode (reference).ToString ("x"),
254+
JniEnvironment.Types.GetJniTypeNameFromInstance (reference),
255+
cinfo.DeclaringType.FullName);
256+
Debug.WriteLine (m);
257+
258+
throw new NotSupportedException (m, e);
259+
}
260+
}
261+
232262
public override void FinalizePeer (IJavaPeerable value)
233263
{
234264
var h = value.PeerReference;

tests/Java.Interop-Tests/Java.Interop/JniRuntime.JniValueManagerTests.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System;
1+
using System;
2+
using System.Reflection;
23
using System.Collections.Generic;
34

45
using Java.Interop;
@@ -59,6 +60,11 @@ public override IJavaPeerable PeekPeer (JniObjectReference reference)
5960
{
6061
return null;
6162
}
63+
64+
public override void ActivatePeer (IJavaPeerable self, JniObjectReference reference, ConstructorInfo cinfo, object [] argumentValues)
65+
{
66+
throw new NotImplementedException ();
67+
}
6268
}
6369

6470
[Test]

tests/Java.Interop-Tests/Java.Interop/JniRuntimeTest.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Reflection;
23
using System.Collections.Generic;
34
using System.Threading;
45

@@ -151,6 +152,11 @@ public override IJavaPeerable PeekPeer (JniObjectReference reference)
151152
return null;
152153
}
153154

155+
public override void ActivatePeer (IJavaPeerable self, JniObjectReference reference, ConstructorInfo cinfo, object [] argumentValues)
156+
{
157+
throw new NotImplementedException ();
158+
}
159+
154160
public override void RemovePeer (IJavaPeerable peer)
155161
{
156162
}

0 commit comments

Comments
 (0)