diff --git a/Xamarin.Android-Tests.sln b/Xamarin.Android-Tests.sln
index 0d6de66b5dc..5b2db998e1b 100644
--- a/Xamarin.Android-Tests.sln
+++ b/Xamarin.Android-Tests.sln
@@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.27428.2037
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29411.108
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Android-Tests", "src\Mono.Android\Test\Mono.Android-Tests.csproj", "{40EAD437-216B-4DF4-8258-3F47E1672C3A}"
EndProject
@@ -90,6 +90,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Android-Test.Library",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Android-TestsMultiDex", "tests\Runtime-MultiDex\Mono.Android-TestsMultiDex.csproj", "{9ECBEA14-B79F-4F92-9266-495C03A32571}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Java.Interop.GenericMarshaler", "external\Java.Interop\src\Java.Interop.GenericMarshaler\Java.Interop.GenericMarshaler.csproj", "{D1243BAB-23CA-4566-A2A3-3ADA2C2DC3AF}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Java.Interop-Tests", "src\Mono.Android\Test\Java.Interop-Tests\Java.Interop-Tests.csproj", "{6CB00820-A66B-43E5-8785-ED456C6E9F39}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Java.Interop", "external\Java.Interop\src\Java.Interop\Java.Interop.csproj", "{94BD81F7-B06F-4295-9636-F8A3B6BDC762}"
+EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
src\Mono.Android\Test\Mono.Android-Test.Shared.projitems*{0ab4956e-6fb9-4da0-9d49-ab65a3ff403a}*SharedItemsImports = 13
@@ -111,6 +117,10 @@ Global
{2305B00D-DE81-4744-B0DA-357835CAFE5A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2305B00D-DE81-4744-B0DA-357835CAFE5A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2305B00D-DE81-4744-B0DA-357835CAFE5A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6BE66B30-9346-4DA6-B09A-0CDC1DFE33C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6BE66B30-9346-4DA6-B09A-0CDC1DFE33C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6BE66B30-9346-4DA6-B09A-0CDC1DFE33C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6BE66B30-9346-4DA6-B09A-0CDC1DFE33C2}.Release|Any CPU.Build.0 = Release|Any CPU
{05768F39-7BAF-43E6-971E-712F5771E88E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{05768F39-7BAF-43E6-971E-712F5771E88E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{05768F39-7BAF-43E6-971E-712F5771E88E}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -223,18 +233,6 @@ Global
{056ED976-618F-4A3E-910E-AA25230C2296}.Debug|Any CPU.Build.0 = Debug|Any CPU
{056ED976-618F-4A3E-910E-AA25230C2296}.Release|Any CPU.ActiveCfg = Release|Any CPU
{056ED976-618F-4A3E-910E-AA25230C2296}.Release|Any CPU.Build.0 = Release|Any CPU
- {B160F0E7-799A-4EB9-92B8-D71623C7674A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {B160F0E7-799A-4EB9-92B8-D71623C7674A}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {B160F0E7-799A-4EB9-92B8-D71623C7674A}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {B160F0E7-799A-4EB9-92B8-D71623C7674A}.Release|Any CPU.Build.0 = Release|Any CPU
- {FA8EEC88-CA3C-4D69-B206-54B392570DC6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {FA8EEC88-CA3C-4D69-B206-54B392570DC6}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {FA8EEC88-CA3C-4D69-B206-54B392570DC6}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {FA8EEC88-CA3C-4D69-B206-54B392570DC6}.Release|Any CPU.Build.0 = Release|Any CPU
- {6BE66B30-9346-4DA6-B09A-0CDC1DFE33C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {6BE66B30-9346-4DA6-B09A-0CDC1DFE33C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {6BE66B30-9346-4DA6-B09A-0CDC1DFE33C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {6BE66B30-9346-4DA6-B09A-0CDC1DFE33C2}.Release|Any CPU.Build.0 = Release|Any CPU
{8B5E63B7-8C18-4BA7-BAAB-A1955B257F5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8B5E63B7-8C18-4BA7-BAAB-A1955B257F5E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8B5E63B7-8C18-4BA7-BAAB-A1955B257F5E}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -249,6 +247,18 @@ Global
{9ECBEA14-B79F-4F92-9266-495C03A32571}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9ECBEA14-B79F-4F92-9266-495C03A32571}.Release|Any CPU.Build.0 = Release|Any CPU
{9ECBEA14-B79F-4F92-9266-495C03A32571}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ {D1243BAB-23CA-4566-A2A3-3ADA2C2DC3AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D1243BAB-23CA-4566-A2A3-3ADA2C2DC3AF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D1243BAB-23CA-4566-A2A3-3ADA2C2DC3AF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D1243BAB-23CA-4566-A2A3-3ADA2C2DC3AF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6CB00820-A66B-43E5-8785-ED456C6E9F39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6CB00820-A66B-43E5-8785-ED456C6E9F39}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6CB00820-A66B-43E5-8785-ED456C6E9F39}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6CB00820-A66B-43E5-8785-ED456C6E9F39}.Release|Any CPU.Build.0 = Release|Any CPU
+ {94BD81F7-B06F-4295-9636-F8A3B6BDC762}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {94BD81F7-B06F-4295-9636-F8A3B6BDC762}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {94BD81F7-B06F-4295-9636-F8A3B6BDC762}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {94BD81F7-B06F-4295-9636-F8A3B6BDC762}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -256,6 +266,7 @@ Global
GlobalSection(NestedProjects) = preSolution
{40EAD437-216B-4DF4-8258-3F47E1672C3A} = {EFBC4DC0-DBFF-4DAA-B0B8-6D0CB02A25F5}
{2305B00D-DE81-4744-B0DA-357835CAFE5A} = {43A4FB09-279A-4138-8027-EC1E1CED2E8A}
+ {6BE66B30-9346-4DA6-B09A-0CDC1DFE33C2} = {43A4FB09-279A-4138-8027-EC1E1CED2E8A}
{05768F39-7BAF-43E6-971E-712F5771E88E} = {D6BFEDF6-2F48-44B2-9553-F2F6F92531BD}
{9D5C83B5-70D5-4CC2-9DB7-78B23DC8F255} = {D6BFEDF6-2F48-44B2-9553-F2F6F92531BD}
{EF798EB3-D639-4E09-9DB0-233E67F727B0} = {2EFFECF5-1CCA-4005-AE62-1D6F01C88DF4}
@@ -280,10 +291,12 @@ Global
{F4DAFD78-BE76-46C9-A1AD-85D8C91CD77B} = {9B63992C-2201-4BB0-BD00-D637B481A995}
{2DD1EE75-6D8D-4653-A800-0A24367F7F38} = {9B63992C-2201-4BB0-BD00-D637B481A995}
{37CAA28C-40BE-4253-BA68-CC5D7316A617} = {68B8E272-5B12-47AA-8923-550B9CE535C7}
- {6BE66B30-9346-4DA6-B09A-0CDC1DFE33C2} = {43A4FB09-279A-4138-8027-EC1E1CED2E8A}
{0AB4956E-6FB9-4DA0-9D49-AB65A3FF403A} = {EFBC4DC0-DBFF-4DAA-B0B8-6D0CB02A25F5}
{8CB5FF58-FF95-43B9-9064-9ACE9525866F} = {EFBC4DC0-DBFF-4DAA-B0B8-6D0CB02A25F5}
{9ECBEA14-B79F-4F92-9266-495C03A32571} = {EFBC4DC0-DBFF-4DAA-B0B8-6D0CB02A25F5}
+ {D1243BAB-23CA-4566-A2A3-3ADA2C2DC3AF} = {EFBC4DC0-DBFF-4DAA-B0B8-6D0CB02A25F5}
+ {6CB00820-A66B-43E5-8785-ED456C6E9F39} = {EFBC4DC0-DBFF-4DAA-B0B8-6D0CB02A25F5}
+ {94BD81F7-B06F-4295-9636-F8A3B6BDC762} = {EFBC4DC0-DBFF-4DAA-B0B8-6D0CB02A25F5}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {8643CD20-B195-4919-8135-27549488237E}
diff --git a/build-tools/Xamarin.Android.Tools.BootstrapTasks/result-packaging.targets b/build-tools/Xamarin.Android.Tools.BootstrapTasks/result-packaging.targets
index 4a555505ced..52daf68165d 100644
--- a/build-tools/Xamarin.Android.Tools.BootstrapTasks/result-packaging.targets
+++ b/build-tools/Xamarin.Android.Tools.BootstrapTasks/result-packaging.targets
@@ -12,6 +12,14 @@
<_BuildStatusFiles Include="$(XamarinAndroidSourcePath)bin\Build$(Configuration)\*.projitems" />
<_BuildStatusFiles Include="$(XamarinAndroidSourcePath)bin\Build$(Configuration)\*.cmake" />
<_BuildStatusFiles Include="$(XamarinAndroidSourcePath)bin\Build$(Configuration)\*.targets" />
+ <_BuildStatusFiles Include="$(XamarinAndroidSourcePath)bin\Test$(Configuration)\XABuildConfig.cs" Condition="Exists('$(XamarinAndroidSourcePath)bin\Test$(Configuration)\XABuildConfig.cs')" />
+ <_BuildStatusFiles Include="$(XamarinAndroidSourcePath)bin\Test$(Configuration)\*.binlog" />
+ <_BuildStatusFiles Include="$(XamarinAndroidSourcePath)bin\Test$(Configuration)\prepare*.log" />
+ <_BuildStatusFiles Include="$(XamarinAndroidSourcePath)bin\Test$(Configuration)\*.mk" />
+ <_BuildStatusFiles Include="$(XamarinAndroidSourcePath)bin\Test$(Configuration)\*.projitems" />
+ <_BuildStatusFiles Include="$(XamarinAndroidSourcePath)bin\Test$(Configuration)\*.cmake" />
+ <_BuildStatusFiles Include="$(XamarinAndroidSourcePath)bin\Test$(Configuration)\*.targets" />
+ <_BuildStatusFiles Include="$(XamarinAndroidSourcePath)external\Java.Interop\bin\Build$(Configuration)\*.props" />
<_BuildStatusFiles Include="$(XamarinAndroidSourcePath)**\ThirdPartyNotices.txt" />
<_BuildStatusFiles Include="$(XamarinAndroidSourcePath)**\config.log" />
<_BuildStatusFiles Include="$(XamarinAndroidSourcePath)**\config.status" />
diff --git a/build-tools/scripts/Jar.targets b/build-tools/scripts/Jar.targets
index 327013349b9..91552910d10 100644
--- a/build-tools/scripts/Jar.targets
+++ b/build-tools/scripts/Jar.targets
@@ -11,8 +11,20 @@
$(JavaSdkDirectory)\bin\javac
+
+
+ <_JIJar_InTree>$([System.IO.Path]::GetFullPath ('$(XAInstallPrefix)'))\xbuild\Xamarin\Android\java-interop.jar
+ <_JIJar_System Condition=" '$(_XamarinAndroidMSBuildDirectory)' != '' ">$(_XamarinAndroidMSBuildDirectory)\java-interop.jar
+ <_JavaInteropJarPath Condition=" Exists($(_JIJar_InTree)) ">$(_JIJar_InTree)
+ <_JavaInteropJarPath Condition=" '$(_JavaInteropJarPath)' == '' ">$(_JIJar_System)
+
+
+
@@ -25,10 +37,11 @@
<_Jar>"$(JarPath)"
<_Targets>-source $(_JavacSourceVersion) -target $(_JavacTargetVersion)
<_DestDir>$(IntermediateOutputPath)__CreateTestJarFile-bin
- <_AndroidJar>-cp "$(AndroidSdkDirectory)\platforms\android-$(_AndroidApiLevelName)\android.jar"
+ <_AndroidJar>-bootclasspath "$(AndroidSdkDirectory)\platforms\android-$(_AndroidApiLevelName)\android.jar"
+ <_CP>-cp "$(_JavaInteropJarPath)"
-
+
ExecuteOSSpecific (Context context, NuGetRunner nuget)
if (!result)
return false;
- string javaInteropDir = context.Properties.GetRequiredValue (KnownProperties.JavaInteropFullPath);
- Log.StatusLine ();
- result = await make.Run (
- logTag: "java-interop-prepare",
- workingDirectory: javaInteropDir,
- arguments: new List {
- "prepare",
- $"CONFIGURATION={context.Configuration}",
- $"JAVA_HOME={context.OS.JavaHome}",
- $"JI_MAX_JDK={Configurables.Defaults.MaxJDKVersion}",
- }
- );
- if (!result)
- return false;
-
- Log.StatusLine ();
- result = await make.Run (
- logTag: "java-interop-props",
- workingDirectory: javaInteropDir,
- arguments: new List {
- $"bin/Build{context.Configuration}/JdkInfo.props",
- $"CONFIGURATION={context.Configuration}",
- $"JI_MAX_JDK={Configurables.Defaults.MaxJDKVersion}",
- }
- );
return result;
}
}
diff --git a/build-tools/xaprepare/xaprepare/Steps/Step_PrepareExternalJavaInterop.Unix.cs b/build-tools/xaprepare/xaprepare/Steps/Step_PrepareExternalJavaInterop.Unix.cs
new file mode 100644
index 00000000000..2da742d8e1c
--- /dev/null
+++ b/build-tools/xaprepare/xaprepare/Steps/Step_PrepareExternalJavaInterop.Unix.cs
@@ -0,0 +1,42 @@
+using System.Collections.Generic;
+using System.IO;
+using System.Threading.Tasks;
+
+namespace Xamarin.Android.Prepare
+{
+ partial class Step_PrepareExternalJavaInterop
+ {
+ async Task ExecuteOSSpecific (Context context)
+ {
+ string javaInteropDir = context.Properties.GetRequiredValue (KnownProperties.JavaInteropFullPath);
+ Log.StatusLine ();
+ var make = new MakeRunner (context) {
+ NoParallelJobs = true
+ };
+ var result = await make.Run (
+ logTag: "java-interop-prepare",
+ workingDirectory: javaInteropDir,
+ arguments: new List {
+ "prepare",
+ $"CONFIGURATION={context.Configuration}",
+ $"JAVA_HOME={context.OS.JavaHome}",
+ $"JI_MAX_JDK={Configurables.Defaults.MaxJDKVersion}",
+ }
+ );
+ if (!result)
+ return false;
+
+ Log.StatusLine ();
+ result = await make.Run (
+ logTag: "java-interop-props",
+ workingDirectory: javaInteropDir,
+ arguments: new List {
+ $"bin/Build{context.Configuration}/JdkInfo.props",
+ $"CONFIGURATION={context.Configuration}",
+ $"JI_MAX_JDK={Configurables.Defaults.MaxJDKVersion}",
+ }
+ );
+ return result;
+ }
+ }
+}
diff --git a/build-tools/xaprepare/xaprepare/Steps/Step_PrepareExternalJavaInterop.Windows.cs b/build-tools/xaprepare/xaprepare/Steps/Step_PrepareExternalJavaInterop.Windows.cs
new file mode 100644
index 00000000000..e341c97cb89
--- /dev/null
+++ b/build-tools/xaprepare/xaprepare/Steps/Step_PrepareExternalJavaInterop.Windows.cs
@@ -0,0 +1,14 @@
+using System.IO;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace Xamarin.Android.Prepare
+{
+ partial class Step_PrepareExternalJavaInterop
+ {
+ async Task ExecuteOSSpecific (Context context)
+ {
+ return true;
+ }
+ }
+}
diff --git a/build-tools/xaprepare/xaprepare/Steps/Step_PrepareExternalJavaInterop.cs b/build-tools/xaprepare/xaprepare/Steps/Step_PrepareExternalJavaInterop.cs
new file mode 100644
index 00000000000..e57193610e1
--- /dev/null
+++ b/build-tools/xaprepare/xaprepare/Steps/Step_PrepareExternalJavaInterop.cs
@@ -0,0 +1,18 @@
+using System.Collections.Generic;
+using System.IO;
+using System.Threading.Tasks;
+
+namespace Xamarin.Android.Prepare
+{
+ partial class Step_PrepareExternalJavaInterop : Step
+ {
+ public Step_PrepareExternalJavaInterop ()
+ : base ("Preparing external/Java.Interop")
+ {}
+
+ protected override async Task Execute (Context context)
+ {
+ return await ExecuteOSSpecific (context);
+ }
+ }
+}
diff --git a/build-tools/xaprepare/xaprepare/ThirdPartyNotices/Java.Interop.cs b/build-tools/xaprepare/xaprepare/ThirdPartyNotices/Java.Interop.cs
index b9fa35b9076..ca4bcd82c9e 100644
--- a/build-tools/xaprepare/xaprepare/ThirdPartyNotices/Java.Interop.cs
+++ b/build-tools/xaprepare/xaprepare/ThirdPartyNotices/Java.Interop.cs
@@ -13,7 +13,7 @@ class JavaInterop_External_Dependencies_Group : ThirdPartyNoticeGroup
new JavaInterop_xamarin_Java_Interop_TPN (),
new JavaInterop_gityf_crc_TPN (),
new JavaInterop_xamarin_mono_cecil_TPN (),
- new JavaInterop_jonpryor_mono_linq_expressions_TPN (),
+ new JavaInterop_jbevain_mono_linq_expressions_TPN (),
new JavaInterop_mono_csharp_TPN (),
new JavaInterop_mono_LineEditor_TPN (),
new JavaInterop_mono_Options_TPN (),
@@ -82,12 +82,12 @@ class JavaInterop_xamarin_mono_cecil_TPN : ThirdPartyNotice
public override string LicenseText => null;
}
- class JavaInterop_jonpryor_mono_linq_expressions_TPN : ThirdPartyNotice
+ class JavaInterop_jbevain_mono_linq_expressions_TPN : ThirdPartyNotice
{
- static readonly Uri url = new Uri ("https://github.com/jonpryor/mono.linq.expressions/");
+ static readonly Uri url = new Uri ("https://github.com/jbevain/mono.linq.expressions/");
public override string LicenseFile => null;
- public override string Name => "jonpryor/mono.linq.expressions";
+ public override string Name => "jbevain/mono.linq.expressions";
public override Uri SourceUrl => url;
public override string LicenseText => @"
diff --git a/build-tools/xaprepare/xaprepare/xaprepare.csproj b/build-tools/xaprepare/xaprepare/xaprepare.csproj
index 520c68b7e7d..81d59485f1e 100644
--- a/build-tools/xaprepare/xaprepare/xaprepare.csproj
+++ b/build-tools/xaprepare/xaprepare/xaprepare.csproj
@@ -127,6 +127,7 @@
+
@@ -142,6 +143,7 @@
+
@@ -196,6 +198,7 @@
+
@@ -259,6 +262,7 @@
+
diff --git a/src/Mono.Android/Android.Runtime/AndroidRuntime.cs b/src/Mono.Android/Android.Runtime/AndroidRuntime.cs
index f0fc6bd0f22..93a5fc0e9de 100644
--- a/src/Mono.Android/Android.Runtime/AndroidRuntime.cs
+++ b/src/Mono.Android/Android.Runtime/AndroidRuntime.cs
@@ -36,14 +36,23 @@ public override string GetCurrentManagedThreadStackTrace (int skipFrames, bool f
.ToString ();
}
- public override Exception GetExceptionForThrowable (ref JniObjectReference value, JniObjectReferenceOptions transfer)
+ public override Exception GetExceptionForThrowable (ref JniObjectReference reference, JniObjectReferenceOptions options)
{
- var throwable = Java.Lang.Object.GetObject(value.Handle, JniHandleOwnership.DoNotTransfer);
- JniObjectReference.Dispose (ref value, transfer);
- var p = throwable as JavaProxyThrowable;
- if (p != null)
- return p.InnerException;
- return throwable;
+ if (!reference.IsValid)
+ return null;
+ var peeked = JNIEnv.AndroidValueManager.PeekPeer (reference);
+ var peekedExc = peeked as Exception;
+ if (peekedExc == null) {
+ var throwable = Java.Lang.Object.GetObject (reference.Handle, JniHandleOwnership.DoNotTransfer);
+ JniObjectReference.Dispose (ref reference, options);
+ return throwable;
+ }
+ JniObjectReference.Dispose (ref reference, options);
+ var unwrapped = JNIEnv.AndroidValueManager.UnboxException (peeked);
+ if (unwrapped != null) {
+ return unwrapped;
+ }
+ return peekedExc;
}
public override void RaisePendingException (Exception pendingException)
@@ -222,11 +231,16 @@ protected override IEnumerable GetTypesForSimpleReference (string jniSimpl
protected override IEnumerable GetSimpleReferences (Type type)
{
- var j = JNIEnv.GetJniName (type);
- if (j == null)
- return base.GetSimpleReferences (type);
- return base.GetSimpleReferences (type)
- .Concat (Enumerable.Repeat (j, 1));
+ foreach (var simpleRef in base.GetSimpleReferences (type)) {
+ yield return simpleRef;
+ }
+ var j = JNIEnv.monodroid_typemap_managed_to_java (type.FullName + ", " + type.Assembly.GetName ().Name);
+ if (j != IntPtr.Zero) {
+ yield return Marshal.PtrToStringAnsi (j);
+ }
+ if (JNIEnv.IsRunningOnDesktop) {
+ yield return JavaNativeTypeManager.ToJniName (type);
+ }
}
delegate Delegate GetCallbackHandler ();
@@ -318,17 +332,21 @@ static bool CallRegisterMethodByIndex (JniNativeMethodRegistrationArguments argu
}
}
- public override void RegisterNativeMembers (JniType jniType, Type type, string methods)
+ public override void RegisterNativeMembers (JniType nativeClass, Type type, string methods)
{
- if (FastRegisterNativeMembers (jniType, type, methods))
+ if (FastRegisterNativeMembers (nativeClass, type, methods))
return;
- if (methods == null)
+ if (string.IsNullOrEmpty (methods)) {
+ base.RegisterNativeMembers (nativeClass, type, methods);
return;
+ }
string[] members = methods.Split ('\n');
- if (members.Length == 0)
+ if (members.Length < 2) {
+ base.RegisterNativeMembers (nativeClass, type, methods);
return;
+ }
JniNativeMethodRegistration[] natives = new JniNativeMethodRegistration [members.Length-1];
for (int i = 0; i < members.Length; ++i) {
@@ -351,41 +369,344 @@ public override void RegisterNativeMembers (JniType jniType, Type type, string m
natives [i] = new JniNativeMethodRegistration (toks [0], toks [1], callback);
}
- JniEnvironment.Types.RegisterNatives (jniType.PeerReference, natives, natives.Length);
+ JniEnvironment.Types.RegisterNatives (nativeClass.PeerReference, natives, natives.Length);
}
}
class AndroidValueManager : JniRuntime.JniValueManager {
+ Dictionary instances = new Dictionary ();
+
public override void WaitForGCBridgeProcessing ()
{
JNIEnv.WaitForBridgeProcessing ();
}
+ public override IJavaPeerable CreatePeer (ref JniObjectReference reference, JniObjectReferenceOptions options, Type targetType)
+ {
+ if (!reference.IsValid)
+ return null;
+
+ var peer = Java.Interop.TypeManager.CreateInstance (reference.Handle, JniHandleOwnership.DoNotTransfer, targetType) as IJavaPeerable;
+ JniObjectReference.Dispose (ref reference, options);
+ return peer;
+ }
+
public override void AddPeer (IJavaPeerable value)
{
+ if (value == null)
+ throw new ArgumentNullException (nameof (value));
+ if (!value.PeerReference.IsValid)
+ throw new ArgumentException ("Must have a valid JNI object reference!", nameof (value));
+
+ var reference = value.PeerReference;
+ var hash = JNIEnv.IdentityHash (reference.Handle);
+
+ AddPeer (value, reference, hash);
+ }
+
+ internal void AddPeer (IJavaPeerable value, JniObjectReference reference, IntPtr hash)
+ {
+ lock (instances) {
+ IdentityHashTargets targets;
+ if (!instances.TryGetValue (hash, out targets)) {
+ targets = new IdentityHashTargets (value);
+ instances.Add (hash, targets);
+ return;
+ }
+ bool found = false;
+ for (int i = 0; i < targets.Count; ++i) {
+ IJavaPeerable target;
+ var wref = targets [i];
+ if (ShouldReplaceMapping (wref, reference, out target)) {
+ found = true;
+ targets [i] = IdentityHashTargets.CreateWeakReference (value);
+ break;
+ }
+ if (JniEnvironment.Types.IsSameObject (value.PeerReference, target.PeerReference)) {
+ found = true;
+ if (Logger.LogGlobalRef) {
+ Logger.Log (LogLevel.Info, "monodroid-gref",
+ string.Format ("warning: not replacing previous registered handle {0} with handle {1} for key_handle 0x{2}",
+ target.PeerReference.ToString (), reference.ToString (), hash.ToString ("x")));
+ }
+ }
+ }
+ if (!found) {
+ targets.Add (value);
+ }
+ }
+ }
+
+ internal void AddPeer (IJavaPeerable value, IntPtr handle, JniHandleOwnership transfer, out IntPtr handleField)
+ {
+ if (handle == IntPtr.Zero) {
+ handleField = handle;
+ return;
+ }
+
+ var transferType = transfer & (JniHandleOwnership.DoNotTransfer | JniHandleOwnership.TransferLocalRef | JniHandleOwnership.TransferGlobalRef);
+ switch (transferType) {
+ case JniHandleOwnership.DoNotTransfer:
+ handleField = JNIEnv.NewGlobalRef (handle);
+ break;
+ case JniHandleOwnership.TransferLocalRef:
+ handleField = JNIEnv.NewGlobalRef (handle);
+ JNIEnv.DeleteLocalRef (handle);
+ break;
+ case JniHandleOwnership.TransferGlobalRef:
+ handleField = handle;
+ break;
+ default:
+ throw new ArgumentOutOfRangeException ("transfer", transfer,
+ "Invalid `transfer` value: " + transfer + " on type " + value.GetType ());
+ }
+ if (handleField == IntPtr.Zero)
+ throw new InvalidOperationException ("Unable to allocate Global Reference for object '" + value.ToString () + "'!");
+
+ IntPtr hash = JNIEnv.IdentityHash (handleField);
+ value.SetJniIdentityHashCode ((int) hash);
+ if ((transfer & JniHandleOwnership.DoNotRegister) == 0) {
+ AddPeer (value, new JniObjectReference (handleField, JniObjectReferenceType.Global), hash);
+ }
+
+ if (Logger.LogGlobalRef) {
+ JNIEnv._monodroid_gref_log ("handle 0x" + handleField.ToString ("x") +
+ "; key_handle 0x" + hash.ToString ("x") +
+ ": Java Type: `" + JNIEnv.GetClassNameFromInstance (handleField) + "`; " +
+ "MCW type: `" + value.GetType ().FullName + "`\n");
+ }
+ }
+
+ bool ShouldReplaceMapping (WeakReference current, JniObjectReference reference, out IJavaPeerable target)
+ {
+ target = null;
+
+ if (current == null)
+ return true;
+
+ // Target has been GC'd; see also FIXME, above, in finalizer
+ if (!current.TryGetTarget (out target) || target == null)
+ return true;
+
+ // It's possible that the instance was GC'd, but the finalizer
+ // hasn't executed yet, so the `instances` entry is stale.
+ if (!target.PeerReference.IsValid)
+ return true;
+
+ if (!JniEnvironment.Types.IsSameObject (target.PeerReference, reference))
+ return false;
+
+ // JNIEnv.NewObject/JNIEnv.CreateInstance() compatibility.
+ // When two MCW's are created for one Java instance [0],
+ // we want the 2nd MCW to replace the 1st, as the 2nd is
+ // the one the dev created; the 1st is an implicit intermediary.
+ //
+ // [0]: If Java ctor invokes overridden virtual method, we'll
+ // transition into managed code w/o a registered instance, and
+ // thus will create an "intermediary" via
+ // (IntPtr, JniHandleOwnership) .ctor.
+ if ((target.JniManagedPeerState & JniManagedPeerStates.Replaceable) == JniManagedPeerStates.Replaceable)
+ return true;
+
+ return false;
}
public override void RemovePeer (IJavaPeerable value)
{
+ if (value == null)
+ throw new ArgumentNullException (nameof (value));
+ if (!value.PeerReference.IsValid)
+ throw new ArgumentException ("Must have a valid JNI object reference!", nameof (value));
+
+ var reference = value.PeerReference;
+ var hash = JNIEnv.IdentityHash (reference.Handle);
+
+ RemovePeer (value, hash);
+ }
+
+ internal void RemovePeer (IJavaPeerable value, IntPtr hash)
+ {
+ lock (instances) {
+ IdentityHashTargets targets;
+ if (!instances.TryGetValue (hash, out targets)) {
+ return;
+ }
+ for (int i = targets.Count - 1; i >= 0; i--) {
+ var wref = targets [i];
+ if (!wref.TryGetTarget (out IJavaPeerable target)) {
+ // wref is invalidated; remove it.
+ targets.RemoveAt (i);
+ continue;
+ }
+ if (!object.ReferenceEquals (target, value)) {
+ continue;
+ }
+ targets.RemoveAt (i);
+ }
+ if (targets.Count == 0) {
+ instances.Remove (hash);
+ }
+ }
}
public override IJavaPeerable PeekPeer (JniObjectReference reference)
{
- return (IJavaPeerable) Java.Lang.Object.GetObject (reference.Handle, JniHandleOwnership.DoNotTransfer);
+ if (!reference.IsValid)
+ return null;
+
+ var hash = JNIEnv.IdentityHash (reference.Handle);
+ lock (instances) {
+ IdentityHashTargets targets;
+ if (instances.TryGetValue (hash, out targets)) {
+ for (int i = targets.Count - 1; i >= 0; i--) {
+ var wref = targets [i];
+ if (!wref.TryGetTarget (out var result) || !result.PeerReference.IsValid) {
+ targets.RemoveAt (i);
+ continue;
+ }
+ if (!JniEnvironment.Types.IsSameObject (reference, result.PeerReference))
+ continue;
+ return result;
+ }
+ }
+ }
+ return null;
+ }
+
+ protected override bool TryUnboxPeerObject (IJavaPeerable value, out object result)
+ {
+ var proxy = value as JavaProxyThrowable;
+ if (proxy != null) {
+ result = proxy.InnerException;
+ return true;
+ }
+ return base.TryUnboxPeerObject (value, out result);
+ }
+
+ internal Exception UnboxException (IJavaPeerable value)
+ {
+ object r;
+ if (TryUnboxPeerObject (value, out r) && r is Exception e) {
+ return e;
+ }
+ return null;
}
public override void CollectPeers ()
{
+ GC.Collect ();
}
public override void FinalizePeer (IJavaPeerable value)
{
+ if (value == null)
+ throw new ArgumentNullException (nameof (value));
+
+ if (Logger.LogGlobalRef) {
+ JNIEnv._monodroid_gref_log ($"Finalizing handle {value.PeerReference}\n");
+ }
+
+ // FIXME: need hash cleanup mechanism.
+ // Finalization occurs after a test of java persistence. If the
+ // handle still contains a java reference, we can't finalize the
+ // object and should "resurrect" it.
+ if (value.PeerReference.IsValid) {
+ GC.ReRegisterForFinalize (value);
+ } else {
+ RemovePeer (value, (IntPtr) value.JniIdentityHashCode);
+ value.SetPeerReference (new JniObjectReference ());
+ value.Finalized ();
+ }
}
public override List GetSurfacedPeers ()
{
- return null;
+ lock (instances) {
+ var surfacedPeers = new List (instances.Count);
+ foreach (var e in instances) {
+ for (int i = 0; i < e.Value.Count; i++) {
+ var value = e.Value [i];
+ surfacedPeers.Add (new JniSurfacedPeerInfo (e.Key.ToInt32 (), value));
+ }
+ }
+ return surfacedPeers;
+ }
+ }
+ }
+
+ class InstancesKeyComparer : IEqualityComparer
+ {
+
+ public bool Equals (IntPtr x, IntPtr y)
+ {
+ return x == y;
+ }
+
+ public int GetHashCode (IntPtr value)
+ {
+ return value.GetHashCode ();
+ }
+ }
+
+ class IdentityHashTargets {
+ WeakReference first;
+ List> rest;
+
+ public static WeakReference CreateWeakReference (IJavaPeerable value)
+ {
+ return new WeakReference (value, trackResurrection: true);
+ }
+
+ public IdentityHashTargets (IJavaPeerable value)
+ {
+ first = CreateWeakReference (value);
+ }
+
+ public int Count => (first != null ? 1 : 0) + (rest != null ? rest.Count : 0);
+
+ public WeakReference this [int index] {
+ get {
+ if (index == 0)
+ return first;
+ index -= 1;
+ if (rest == null || index >= rest.Count)
+ return null;
+ return rest [index];
+ }
+ set {
+ if (index == 0) {
+ first = value;
+ return;
+ }
+ index -= 1;
+ rest [index] = value;
+ }
+ }
+
+ public void Add (IJavaPeerable value)
+ {
+ if (first == null) {
+ first = CreateWeakReference (value);
+ return;
+ }
+ if (rest == null)
+ rest = new List> ();
+ rest.Add (CreateWeakReference (value));
+ }
+
+ public void RemoveAt (int index)
+ {
+ if (index == 0) {
+ first = null;
+ if (rest?.Count > 0) {
+ first = rest [0];
+ rest.RemoveAt (0);
+ }
+ return;
+ }
+ index -= 1;
+ rest.RemoveAt (index);
}
}
}
diff --git a/src/Mono.Android/Android.Runtime/InputStreamInvoker.cs b/src/Mono.Android/Android.Runtime/InputStreamInvoker.cs
index 484f70207a7..da48df7bda8 100644
--- a/src/Mono.Android/Android.Runtime/InputStreamInvoker.cs
+++ b/src/Mono.Android/Android.Runtime/InputStreamInvoker.cs
@@ -122,10 +122,10 @@ public static Stream FromJniHandle (IntPtr handle, JniHandleOwnership transfer)
if (handle == IntPtr.Zero)
return null;
- IJavaObject inst = Java.Lang.Object.PeekObject (handle);
+ IJavaObject inst = (IJavaObject) Java.Lang.Object.PeekObject (handle);
if (inst == null)
- inst = Java.Interop.TypeManager.CreateInstance (handle, transfer);
+ inst = (IJavaObject) Java.Interop.TypeManager.CreateInstance (handle, transfer);
else
JNIEnv.DeleteRef (handle, transfer);
diff --git a/src/Mono.Android/Android.Runtime/JNIEnv.cs b/src/Mono.Android/Android.Runtime/JNIEnv.cs
index 98a78239cc9..fe7a10aae70 100644
--- a/src/Mono.Android/Android.Runtime/JNIEnv.cs
+++ b/src/Mono.Android/Android.Runtime/JNIEnv.cs
@@ -61,6 +61,8 @@ public static partial class JNIEnv {
static AndroidRuntime androidRuntime;
static BoundExceptionType BoundExceptionType;
+ internal static AndroidValueManager AndroidValueManager;
+
[DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)]
extern static void monodroid_log (LogLevel level, LogCategories category, string message);
@@ -166,6 +168,7 @@ internal static unsafe void Initialize (JnienvInitializeArgs* args)
BoundExceptionType = (BoundExceptionType)args->ioExceptionType;
androidRuntime = new AndroidRuntime (args->env, args->javaVm, androidSdkVersion > 10, args->grefLoader, args->Loader_loadClass);
+ AndroidValueManager = (AndroidValueManager) androidRuntime.ValueManager;
AllocObjectSupported = androidSdkVersion > 10;
IsRunningOnDesktop = args->isRunningOnDesktop == 1;
diff --git a/src/Mono.Android/Android.Runtime/JavaCollection.cs b/src/Mono.Android/Android.Runtime/JavaCollection.cs
index 8a0a83cb20f..7eedb3f4ae5 100644
--- a/src/Mono.Android/Android.Runtime/JavaCollection.cs
+++ b/src/Mono.Android/Android.Runtime/JavaCollection.cs
@@ -178,7 +178,7 @@ public static ICollection FromJniHandle (IntPtr handle, JniHandleOwnership trans
if (handle == IntPtr.Zero)
return null;
- IJavaObject inst = Java.Lang.Object.PeekObject (handle);
+ IJavaObject inst = (IJavaObject) Java.Lang.Object.PeekObject (handle);
if (inst == null)
inst = new JavaCollection (handle, transfer);
else
@@ -397,7 +397,7 @@ public static ICollection FromJniHandle (IntPtr handle, JniHandleOwnership tr
if (handle == IntPtr.Zero)
return null;
- IJavaObject inst = Java.Lang.Object.PeekObject (handle);
+ IJavaObject inst = (IJavaObject) Java.Lang.Object.PeekObject (handle);
if (inst == null)
inst = new JavaCollection (handle, transfer);
else
diff --git a/src/Mono.Android/Android.Runtime/JavaDictionary.cs b/src/Mono.Android/Android.Runtime/JavaDictionary.cs
index 49f618ea7c2..4593d334779 100644
--- a/src/Mono.Android/Android.Runtime/JavaDictionary.cs
+++ b/src/Mono.Android/Android.Runtime/JavaDictionary.cs
@@ -359,7 +359,7 @@ public static IDictionary FromJniHandle (IntPtr handle, JniHandleOwnership trans
if (handle == IntPtr.Zero)
return null;
- IJavaObject inst = Java.Lang.Object.PeekObject (handle);
+ IJavaObject inst = (IJavaObject) Java.Lang.Object.PeekObject (handle);
if (inst == null)
inst = new JavaDictionary (handle, transfer);
else
@@ -630,7 +630,7 @@ public static IDictionary FromJniHandle (IntPtr handle, JniHandleOwnership
if (handle == IntPtr.Zero)
return null;
- IJavaObject inst = Java.Lang.Object.PeekObject (handle);
+ IJavaObject inst = (IJavaObject) Java.Lang.Object.PeekObject (handle);
if (inst == null)
inst = new JavaDictionary (handle, transfer);
else
diff --git a/src/Mono.Android/Android.Runtime/JavaList.cs b/src/Mono.Android/Android.Runtime/JavaList.cs
index b260b101e78..f771ef8f6f0 100644
--- a/src/Mono.Android/Android.Runtime/JavaList.cs
+++ b/src/Mono.Android/Android.Runtime/JavaList.cs
@@ -480,7 +480,7 @@ public static IList FromJniHandle (IntPtr handle, JniHandleOwnership transfer)
if (handle == IntPtr.Zero)
return null;
- IJavaObject inst = Java.Lang.Object.PeekObject (handle);
+ IJavaObject inst = (IJavaObject) Java.Lang.Object.PeekObject (handle);
if (inst == null)
inst = new JavaList (handle, transfer);
else
@@ -936,7 +936,7 @@ public static IList FromJniHandle (IntPtr handle, JniHandleOwnership transfer
if (handle == IntPtr.Zero)
return null;
- IJavaObject inst = Java.Lang.Object.PeekObject (handle, typeof (IList));
+ IJavaObject inst = (IJavaObject) Java.Lang.Object.PeekObject (handle, typeof (IList));
if (inst == null)
inst = new JavaList (handle, transfer);
else
diff --git a/src/Mono.Android/Android.Runtime/JavaSet.cs b/src/Mono.Android/Android.Runtime/JavaSet.cs
index d01d4eca4bf..ccf9a03a985 100644
--- a/src/Mono.Android/Android.Runtime/JavaSet.cs
+++ b/src/Mono.Android/Android.Runtime/JavaSet.cs
@@ -243,7 +243,7 @@ public static ICollection FromJniHandle (IntPtr handle, JniHandleOwnership trans
if (handle == IntPtr.Zero)
return null;
- IJavaObject inst = Java.Lang.Object.PeekObject (handle);
+ IJavaObject inst = (IJavaObject) Java.Lang.Object.PeekObject (handle);
if (inst == null)
inst = new JavaSet (handle, transfer);
else
@@ -429,7 +429,7 @@ public static ICollection FromJniHandle (IntPtr handle, JniHandleOwnership tr
if (handle == IntPtr.Zero)
return null;
- IJavaObject inst = Java.Lang.Object.PeekObject (handle);
+ IJavaObject inst = (IJavaObject) Java.Lang.Object.PeekObject (handle);
if (inst == null)
inst = new JavaSet (handle, transfer);
else
diff --git a/src/Mono.Android/Android.Runtime/OutputStreamInvoker.cs b/src/Mono.Android/Android.Runtime/OutputStreamInvoker.cs
index 4a15b45df6c..b192cf607fa 100644
--- a/src/Mono.Android/Android.Runtime/OutputStreamInvoker.cs
+++ b/src/Mono.Android/Android.Runtime/OutputStreamInvoker.cs
@@ -136,10 +136,10 @@ internal static Stream FromNative (IntPtr handle, JniHandleOwnership transfer)
if (handle == IntPtr.Zero)
return null;
- IJavaObject inst = Java.Lang.Object.PeekObject (handle);
+ IJavaObject inst = (IJavaObject) Java.Lang.Object.PeekObject (handle);
if (inst == null)
- inst = Java.Interop.TypeManager.CreateInstance (handle, transfer);
+ inst = (IJavaObject) Java.Interop.TypeManager.CreateInstance (handle, transfer);
else
JNIEnv.DeleteRef (handle, transfer);
diff --git a/src/Mono.Android/Android.Runtime/XmlPullParserReader.cs b/src/Mono.Android/Android.Runtime/XmlPullParserReader.cs
index 1bc5102633a..32a5f525bad 100644
--- a/src/Mono.Android/Android.Runtime/XmlPullParserReader.cs
+++ b/src/Mono.Android/Android.Runtime/XmlPullParserReader.cs
@@ -35,9 +35,9 @@ static XmlResourceParserReader FromNative (IntPtr handle, JniHandleOwnership tra
{
if (handle == IntPtr.Zero)
return null;
- IJavaObject inst = Java.Lang.Object.PeekObject (handle);
+ IJavaObject inst = (IJavaObject) Java.Lang.Object.PeekObject (handle);
if (inst == null)
- inst = Java.Interop.TypeManager.CreateInstance (handle, transfer);
+ inst = (IJavaObject) Java.Interop.TypeManager.CreateInstance (handle, transfer);
else
JNIEnv.DeleteRef (handle, transfer);
return new XmlResourceParserReader (inst.JavaCast ());
@@ -392,9 +392,9 @@ static XmlReader FromNative (IntPtr handle, JniHandleOwnership transfer)
{
if (handle == IntPtr.Zero)
return null;
- IJavaObject inst = Java.Lang.Object.PeekObject (handle);
+ IJavaObject inst = (IJavaObject) Java.Lang.Object.PeekObject (handle);
if (inst == null)
- inst = Java.Interop.TypeManager.CreateInstance (handle, transfer);
+ inst = (IJavaObject) Java.Interop.TypeManager.CreateInstance (handle, transfer);
else
JNIEnv.DeleteRef (handle, transfer);
return new XmlPullParserReader (inst.JavaCast ());
diff --git a/src/Mono.Android/Java.Interop/JavaConvert.cs b/src/Mono.Android/Java.Interop/JavaConvert.cs
index fb1a3c76e01..399a59a18ec 100644
--- a/src/Mono.Android/Java.Interop/JavaConvert.cs
+++ b/src/Mono.Android/Java.Interop/JavaConvert.cs
@@ -104,7 +104,7 @@ public static T FromJniHandle(IntPtr handle, JniHandleOwnership transfer, out
return default (T);
}
- IJavaObject interned = Java.Lang.Object.PeekObject (handle);
+ IJavaObject interned = (IJavaObject) Java.Lang.Object.PeekObject (handle);
if (interned != null) {
T r = FromJavaObject(interned, out set);
if (set) {
@@ -138,7 +138,7 @@ public static object FromJniHandle (IntPtr handle, JniHandleOwnership transfer,
return null;
}
- IJavaObject interned = Java.Lang.Object.PeekObject (handle);
+ IJavaObject interned = (IJavaObject) Java.Lang.Object.PeekObject (handle);
if (interned != null) {
var unwrapped = FromJavaObject (interned, targetType);
if (unwrapped != null) {
diff --git a/src/Mono.Android/Java.Interop/JavaObjectExtensions.cs b/src/Mono.Android/Java.Interop/JavaObjectExtensions.cs
index 2a67b624367..90516e0ba0a 100644
--- a/src/Mono.Android/Java.Interop/JavaObjectExtensions.cs
+++ b/src/Mono.Android/Java.Interop/JavaObjectExtensions.cs
@@ -109,7 +109,7 @@ internal static IJavaObject JavaCast (IJavaObject instance, Type resultType)
return CastClass (instance, resultType);
}
else if (resultType.IsInterface) {
- return Java.Lang.Object.GetObject (instance.Handle, JniHandleOwnership.DoNotTransfer, resultType);
+ return (IJavaObject) Java.Lang.Object.GetObject (instance.Handle, JniHandleOwnership.DoNotTransfer, resultType);
}
else
throw new NotSupportedException (string.Format ("Unable to convert type '{0}' to '{1}'.",
diff --git a/src/Mono.Android/Java.Interop/Runtime.cs b/src/Mono.Android/Java.Interop/Runtime.cs
index b4e28f584fa..50703a35925 100644
--- a/src/Mono.Android/Java.Interop/Runtime.cs
+++ b/src/Mono.Android/Java.Interop/Runtime.cs
@@ -8,9 +8,16 @@ namespace Java.Interop {
public static class Runtime {
+ [Obsolete ("Please use Java.Interop.JniEnvironment.Runtime.ValueManager.GetSurfacedPeers()")]
public static List GetSurfacedObjects ()
{
- return Java.Lang.Object.GetSurfacedObjects_ForDiagnosticsOnly ();
+ var peers = JNIEnv.AndroidValueManager.GetSurfacedPeers ();
+ var r = new List (peers.Count);
+ foreach (var p in peers) {
+ if (p.SurfacedPeer.TryGetTarget (out var target))
+ r.Add (new WeakReference (target, trackResurrection: true));
+ }
+ return r;
}
[DllImport ("__Internal", CallingConvention = CallingConvention.Cdecl)]
diff --git a/src/Mono.Android/Java.Interop/TypeManager.cs b/src/Mono.Android/Java.Interop/TypeManager.cs
index 98efa0c5a09..0cf4265f62c 100644
--- a/src/Mono.Android/Java.Interop/TypeManager.cs
+++ b/src/Mono.Android/Java.Interop/TypeManager.cs
@@ -236,12 +236,12 @@ internal static Type GetJavaToManagedType (string class_name)
return null;
}
- internal static IJavaObject CreateInstance (IntPtr handle, JniHandleOwnership transfer)
+ internal static IJavaPeerable CreateInstance (IntPtr handle, JniHandleOwnership transfer)
{
return CreateInstance (handle, transfer, null);
}
- internal static IJavaObject CreateInstance (IntPtr handle, JniHandleOwnership transfer, Type targetType)
+ internal static IJavaPeerable CreateInstance (IntPtr handle, JniHandleOwnership transfer, Type targetType)
{
Type type = null;
IntPtr class_ptr = JNIEnv.GetObjectClass (handle);
@@ -284,13 +284,13 @@ internal static IJavaObject CreateInstance (IntPtr handle, JniHandleOwnership tr
}
- IJavaObject result = null;
+ IJavaPeerable result = null;
try {
- result = (IJavaObject) CreateProxy (type, handle, transfer);
- var ex = result as IJavaObjectEx;
- if (Runtime.IsGCUserPeer (result) && ex != null)
- ex.IsProxy = true;
+ result = (IJavaPeerable) CreateProxy (type, handle, transfer);
+ if (Runtime.IsGCUserPeer (result.PeerReference.Handle)) {
+ result.SetJniManagedPeerState (JniManagedPeerStates.Replaceable);
+ }
} catch (MissingMethodException e) {
var key_handle = JNIEnv.IdentityHash (handle);
JNIEnv.DeleteRef (handle, transfer);
@@ -302,18 +302,30 @@ internal static IJavaObject CreateInstance (IntPtr handle, JniHandleOwnership tr
return result;
}
+ static readonly Type[] XAConstructorSignature = new Type [] { typeof (IntPtr), typeof (JniHandleOwnership) };
+ static readonly Type[] JIConstructorSignature = new Type [] { typeof (JniObjectReference).MakeByRefType (), typeof (JniObjectReferenceOptions) };
+
internal static object CreateProxy (Type type, IntPtr handle, JniHandleOwnership transfer)
{
// Skip Activator.CreateInstance() as that requires public constructors,
// and we want to hide some constructors for sanity reasons.
BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
- ConstructorInfo c = type.GetConstructor (flags, null, new[]{typeof (IntPtr), typeof (JniHandleOwnership)}, null);
- if (c == null) {
- throw new MissingMethodException (
- "No constructor found for " + type.FullName + "::.ctor(System.IntPtr, Android.Runtime.JniHandleOwnership)",
- CreateJavaLocationException ());
+ ConstructorInfo c = type.GetConstructor (flags, null, XAConstructorSignature, null);
+ if (c != null) {
+ return c.Invoke (new object [] { handle, transfer });
+ }
+ c = type.GetConstructor (flags, null, JIConstructorSignature, null);
+ if (c != null) {
+ JniObjectReference r = new JniObjectReference (handle);
+ JniObjectReferenceOptions o = JniObjectReferenceOptions.Copy;
+ var peer = (IJavaPeerable) c.Invoke (new object [] { r, o });
+ JNIEnv.DeleteRef (handle, transfer);
+ peer.SetJniManagedPeerState (peer.JniManagedPeerState | JniManagedPeerStates.Replaceable);
+ return peer;
}
- return c.Invoke (new object[]{handle, transfer});
+ throw new MissingMethodException (
+ "No constructor found for " + type.FullName + "::.ctor(System.IntPtr, Android.Runtime.JniHandleOwnership)",
+ CreateJavaLocationException ());
}
public static void RegisterType (string java_class, Type t)
diff --git a/src/Mono.Android/Java.Lang/Object.cs b/src/Mono.Android/Java.Lang/Object.cs
index 496a235b1ce..b9a084788ce 100644
--- a/src/Mono.Android/Java.Lang/Object.cs
+++ b/src/Mono.Android/Java.Lang/Object.cs
@@ -15,9 +15,6 @@ public partial class Object : IDisposable, IJavaObject, IJavaObjectEx
, IJavaPeerable
#endif // JAVA_INTEROP
{
-
- static Dictionary> instances = new Dictionary> (new InstancesKeyComparer ());
-
IntPtr key_handle;
IntPtr weak_handle;
JObjectRefType handle_type;
@@ -52,21 +49,15 @@ IntPtr IJavaObjectEx.ToLocalJniHandle ()
~Object ()
{
- if (Logger.LogGlobalRef) {
- JNIEnv._monodroid_gref_log (
- string.Format ("Finalizing handle 0x{0}\n", handle.ToString ("x")));
- }
// FIXME: need hash cleanup mechanism.
// Finalization occurs after a test of java persistence. If the
// handle still contains a java reference, we can't finalize the
// object and should "resurrect" it.
refs_added = 0;
- if (handle != IntPtr.Zero)
- GC.ReRegisterForFinalize (this);
- else {
- Dispose (false);
- DeregisterInstance (this, key_handle);
+ if (Environment.HasShutdownStarted) {
+ return;
}
+ JniEnvironment.Runtime.ValueManager.FinalizePeer (this);
}
public Object (IntPtr handle, JniHandleOwnership transfer)
@@ -163,17 +154,17 @@ void IJavaPeerable.DisposeUnlessReferenced ()
public void UnregisterFromRuntime ()
{
- DeregisterInstance (this, key_handle);
+ JNIEnv.AndroidValueManager.RemovePeer (this, key_handle);
}
void IJavaPeerable.Disposed ()
{
- throw new NotSupportedException ();
+ Dispose (disposing: true);
}
void IJavaPeerable.Finalized ()
{
- throw new NotSupportedException ();
+ Dispose (disposing: false);
}
void IJavaPeerable.SetJniIdentityHashCode (int value)
@@ -200,16 +191,14 @@ void IJavaPeerable.SetPeerReference (JniObjectReference reference)
public void Dispose ()
{
- Dispose (true);
- Dispose (this, ref handle, key_handle, handle_type);
- GC.SuppressFinalize (this);
+ JNIEnv.AndroidValueManager.DisposePeer (this);
}
protected virtual void Dispose (bool disposing)
{
}
- internal static void Dispose (object instance, ref IntPtr handle, IntPtr key_handle, JObjectRefType handle_type)
+ internal static void Dispose (IJavaPeerable instance, ref IntPtr handle, IntPtr key_handle, JObjectRefType handle_type)
{
if (handle == IntPtr.Zero)
return;
@@ -219,7 +208,7 @@ internal static void Dispose (object instance, ref IntPtr handle, IntPtr key_han
string.Format ("Disposing handle 0x{0}\n", handle.ToString ("x")));
}
- DeregisterInstance (instance, key_handle);
+ JNIEnv.AndroidValueManager.RemovePeer (instance, key_handle);
switch (handle_type) {
case JObjectRefType.Global:
@@ -242,174 +231,18 @@ internal static void Dispose (object instance, ref IntPtr handle, IntPtr key_han
protected void SetHandle (IntPtr value, JniHandleOwnership transfer)
{
- RegisterInstance (this, value, transfer, out handle);
+ JNIEnv.AndroidValueManager.AddPeer (this, value, transfer, out handle);
handle_type = JObjectRefType.Global;
}
- internal static void RegisterInstance (IJavaObject instance, IntPtr value, JniHandleOwnership transfer, out IntPtr handle)
- {
- if (value == IntPtr.Zero) {
- handle = value;
- return;
- }
-
- var transferType = transfer & (JniHandleOwnership.DoNotTransfer | JniHandleOwnership.TransferLocalRef | JniHandleOwnership.TransferGlobalRef);
- switch (transferType) {
- case JniHandleOwnership.DoNotTransfer:
- handle = JNIEnv.NewGlobalRef (value);
- break;
- case JniHandleOwnership.TransferLocalRef:
- handle = JNIEnv.NewGlobalRef (value);
- JNIEnv.DeleteLocalRef (value);
- break;
- case JniHandleOwnership.TransferGlobalRef:
- handle = value;
- break;
- default:
- throw new ArgumentOutOfRangeException ("transfer", transfer,
- "Invalid `transfer` value: " + transfer + " on type " + instance.GetType ());
- }
- if (handle == IntPtr.Zero)
- throw new InvalidOperationException ("Unable to allocate Global Reference for object '" + instance.ToString () + "'!");
-
- IntPtr key = JNIEnv.IdentityHash (handle);
- if ((transfer & JniHandleOwnership.DoNotRegister) == 0) {
- _RegisterInstance (instance, key, handle);
- }
- var ex = instance as IJavaObjectEx;
- if (ex != null)
- ex.KeyHandle = key;
-
- if (Logger.LogGlobalRef) {
- JNIEnv._monodroid_gref_log ("handle 0x" + handle.ToString ("x") +
- "; key_handle 0x" + key.ToString ("x") +
- ": Java Type: `" + JNIEnv.GetClassNameFromInstance (handle) + "`; " +
- "MCW type: `" + instance.GetType ().FullName + "`\n");
- }
- }
-
- static void _RegisterInstance (IJavaObject instance, IntPtr key, IntPtr handle)
- {
- lock (instances) {
- List wrefs;
- if (!instances.TryGetValue (key, out wrefs)) {
- wrefs = new List (1) {
- new WeakReference (instance, true),
- };
- instances.Add (key, wrefs);
- }
- else {
- bool found = false;
- for (int i = 0; i < wrefs.Count; ++i) {
- var wref = wrefs [i];
- if (ShouldReplaceMapping (wref, handle)) {
- found = true;
- wrefs.Remove (wref);
- wrefs.Add (new WeakReference (instance, true));
- break;
- }
- var cur = wref == null ? null : (IJavaObject) wref.Target;
- var _c = cur == null ? IntPtr.Zero : cur.Handle;
- if (_c != IntPtr.Zero && JNIEnv.IsSameObject (handle, _c)) {
- found = true;
- if (Logger.LogGlobalRef) {
- Logger.Log (LogLevel.Info, "monodroid-gref",
- string.Format ("warning: not replacing previous registered handle 0x{0} with handle 0x{1} for key_handle 0x{2}",
- _c.ToString ("x"), handle.ToString ("x"), key.ToString ("x")));
- }
- break;
- }
- }
- if (!found) {
- wrefs.Add (new WeakReference (instance, true));
- }
- }
- }
- }
-
- static bool ShouldReplaceMapping (WeakReference current, IntPtr handle)
+ internal static IJavaPeerable PeekObject (IntPtr handle, Type requiredType = null)
{
- if (current == null)
- return true;
-
- // Target has been GC'd; see also FIXME, above, in finalizer
- object target = current.Target;
- if (target == null)
- return true;
-
- // It's possible that the instance was GC'd, but the finalizer
- // hasn't executed yet, so the `instances` entry is stale.
- var ijo = (IJavaObject) target;
- if (ijo.Handle == IntPtr.Zero)
- return true;
-
- if (!JNIEnv.IsSameObject (ijo.Handle, handle))
- return false;
-
- // JNIEnv.NewObject/JNIEnv.CreateInstance() compatibility.
- // When two MCW's are created for one Java instance [0],
- // we want the 2nd MCW to replace the 1st, as the 2nd is
- // the one the dev created; the 1st is an implicit intermediary.
- //
- // [0]: If Java ctor invokes overridden virtual method, we'll
- // transition into managed code w/o a registered instance, and
- // thus will create an "intermediary" via
- // (IntPtr, JniHandleOwnership) .ctor.
- var ex = target as IJavaObjectEx;
- if (ex != null && ex.IsProxy)
- return true;
-
- return false;
- }
-
- internal static void DeregisterInstance (object instance, IntPtr key_handle)
- {
- lock (instances) {
- List wrefs;
- if (instances.TryGetValue (key_handle, out wrefs)) {
- for (int i = wrefs.Count-1; i >= 0; --i) {
- var wref = wrefs [i];
- if (wref.Target == null || wref.Target == instance) {
- wrefs.RemoveAt (i);
- }
- }
- if (wrefs.Count == 0)
- instances.Remove (key_handle);
- }
- }
- }
-
- internal static List GetSurfacedObjects_ForDiagnosticsOnly ()
- {
- lock (instances) {
- var surfaced = new List (instances.Count);
- foreach (var e in instances) {
- surfaced.AddRange (e.Value);
- }
- return surfaced;
- }
- }
-
- internal static IJavaObject PeekObject (IntPtr handle, Type requiredType = null)
- {
- if (handle == IntPtr.Zero)
+ var peeked = JNIEnv.AndroidValueManager.PeekPeer (new JniObjectReference (handle));
+ if (peeked == null)
return null;
-
- lock (instances) {
- List wrefs;
- if (instances.TryGetValue (JNIEnv.IdentityHash (handle), out wrefs)) {
- for (int i = 0; i < wrefs.Count; ++i) {
- var wref = wrefs [i];
- IJavaObject res = wref.Target as IJavaObject;
- if (res != null && res.Handle != IntPtr.Zero && JNIEnv.IsSameObject (handle, res.Handle)) {
- if (requiredType != null && !requiredType.IsAssignableFrom (res.GetType ()))
- return null;
- return res;
- }
- }
- }
- }
- return null;
+ if (requiredType != null && !requiredType.IsAssignableFrom (peeked.GetType ()))
+ return null;
+ return peeked;
}
internal static T PeekObject (IntPtr handle)
@@ -438,30 +271,15 @@ internal static T _GetObject (IntPtr handle, JniHandleOwnership transfer)
return (T) GetObject (handle, transfer, typeof (T));
}
- internal static IJavaObject GetObject (IntPtr handle, JniHandleOwnership transfer, Type type = null)
+ internal static IJavaPeerable GetObject (IntPtr handle, JniHandleOwnership transfer, Type type = null)
{
if (handle == IntPtr.Zero)
return null;
- lock (instances) {
- List wrefs;
- if (instances.TryGetValue (JNIEnv.IdentityHash (handle), out wrefs)) {
- for (int i = 0; i < wrefs.Count; ++i) {
- var wref = wrefs [i];
- var result = wref.Target as IJavaObject;
- var exists = result != null && result.Handle != IntPtr.Zero && JNIEnv.IsSameObject (handle, result.Handle);
- if (exists) {
- if (type == null ? true : type.IsAssignableFrom (result.GetType ())) {
- JNIEnv.DeleteRef (handle, transfer);
- return result;
- }
- /*
- Logger.Log (LogLevel.Warn, "*jonp*", "# jonp: Object.GetObject: handle=0x" + handle.ToString ("x") + " found but is of type '" + result.GetType ().FullName +
- "' and not the required targetType of '" + type + "'.");
- */
- }
- }
- }
+ var r = PeekObject (handle, type);
+ if (r != null) {
+ JNIEnv.DeleteRef (handle, transfer);
+ return r;
}
return Java.Interop.TypeManager.CreateInstance (handle, transfer, type);
@@ -725,17 +543,4 @@ public static explicit operator string[] (Java.Lang.Object value)
return value.ToArray();
}
}
-
- class InstancesKeyComparer : IEqualityComparer {
-
- public bool Equals (IntPtr x, IntPtr y)
- {
- return x == y;
- }
-
- public int GetHashCode (IntPtr value)
- {
- return value.GetHashCode ();
- }
- }
}
diff --git a/src/Mono.Android/Java.Lang/Throwable.cs b/src/Mono.Android/Java.Lang/Throwable.cs
index d562565096d..504b658b08b 100644
--- a/src/Mono.Android/Java.Lang/Throwable.cs
+++ b/src/Mono.Android/Java.Lang/Throwable.cs
@@ -226,7 +226,7 @@ public unsafe Java.Lang.Class Class {
protected void SetHandle (IntPtr value, JniHandleOwnership transfer)
{
- Java.Lang.Object.RegisterInstance (this, value, transfer, out handle);
+ JNIEnv.AndroidValueManager.AddPeer (this, value, transfer, out handle);
handle_type = JObjectRefType.Global;
}
@@ -251,18 +251,11 @@ public static System.Exception ToException (Throwable e)
~Throwable ()
{
- if (Logger.LogGlobalRef) {
- JNIEnv._monodroid_gref_log (
- string.Format ("Finalizing Throwable handle 0x{0}\n", handle.ToString ("x")));
- }
-
refs_added = 0;
- if (handle != IntPtr.Zero)
- GC.ReRegisterForFinalize (this);
- else {
- Dispose (false);
- Object.DeregisterInstance (this, key_handle);
+ if (Environment.HasShutdownStarted) {
+ return;
}
+ JniEnvironment.Runtime.ValueManager.FinalizePeer (this);
}
#if JAVA_INTEROP
@@ -288,17 +281,17 @@ void IJavaPeerable.DisposeUnlessReferenced ()
public void UnregisterFromRuntime ()
{
- Object.DeregisterInstance (this, key_handle);
+ JNIEnv.AndroidValueManager.RemovePeer (this, key_handle);
}
void IJavaPeerable.Disposed ()
{
- throw new NotSupportedException ();
+ Dispose (disposing: true);
}
void IJavaPeerable.Finalized ()
{
- throw new NotSupportedException ();
+ Dispose (disposing: false);
}
void IJavaPeerable.SetJniIdentityHashCode (int value)
@@ -324,10 +317,7 @@ void IJavaPeerable.SetPeerReference (JniObjectReference reference)
public void Dispose ()
{
- Dispose (true);
- Java.Lang.Object.Dispose (this, ref handle, key_handle, handle_type);
- key_handle = IntPtr.Zero;
- GC.SuppressFinalize (this);
+ JNIEnv.AndroidValueManager.DisposePeer (this);
}
protected virtual void Dispose (bool disposing)
diff --git a/src/Mono.Android/Test/Java.Interop-Tests/.gitignore b/src/Mono.Android/Test/Java.Interop-Tests/.gitignore
new file mode 100644
index 00000000000..d996c0b7286
--- /dev/null
+++ b/src/Mono.Android/Test/Java.Interop-Tests/.gitignore
@@ -0,0 +1 @@
+Jars
diff --git a/src/Mono.Android/Test/Java.Interop-Tests/Java.Interop-Tests.csproj b/src/Mono.Android/Test/Java.Interop-Tests/Java.Interop-Tests.csproj
new file mode 100644
index 00000000000..a587304a775
--- /dev/null
+++ b/src/Mono.Android/Test/Java.Interop-Tests/Java.Interop-Tests.csproj
@@ -0,0 +1,90 @@
+
+
+
+ Debug
+ AnyCPU
+ 8.0.30703
+ 2.0
+ {6CB00820-A66B-43E5-8785-ED456C6E9F39}
+ {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ {9ef11e43-1701-4396-8835-8392d57abb70}
+ Library
+ Properties
+ Java.Interop_Tests
+ Java.Interop-Tests
+ 512
+ Resources\Resource.designer.cs
+ Off
+ v10.0
+ true
+
+
+
+ $(AndroidFrameworkVersion)
+ true
+ portable
+ false
+ bin\Debug\
+ DEBUG;TRACE;NO_MARSHAL_MEMBER_BUILDER_SUPPORT
+ prompt
+ 4
+
+
+ $(AndroidFrameworkVersion)
+
+ true
+ bin\Release\
+ TRACE;NO_MARSHAL_MEMBER_BUILDER_SUPPORT
+ prompt
+ 4
+
+
+
+
+
+
+
+
+
+
+
+ ..\..\..\..\packages\mono.linq.expressions.2.0.0\lib\netstandard2.0\Mono.Linq.Expressions.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {D1243BAB-23CA-4566-A2A3-3ADA2C2DC3AF}
+ Java.Interop.GenericMarshaler
+
+
+
+
+
+
+ BuildTestJarFile;
+ _CopyTestJarFiles;
+ $(BuildDependsOn)
+
+
+
+
+ CleanTestJarFile;
+ $(CleanDependsOn);
+ CleanLocal;
+
+
+
\ No newline at end of file
diff --git a/src/Mono.Android/Test/Java.Interop-Tests/Java.Interop-Tests.targets b/src/Mono.Android/Test/Java.Interop-Tests/Java.Interop-Tests.targets
new file mode 100644
index 00000000000..c6a3371fcc7
--- /dev/null
+++ b/src/Mono.Android/Test/Java.Interop-Tests/Java.Interop-Tests.targets
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+ Jars\Mono.Android-Test-classes.jar
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Mono.Android/Test/Java.Interop-Tests/Java.InteropTests/JavaInterop_Tests_Reference.cs b/src/Mono.Android/Test/Java.Interop-Tests/Java.InteropTests/JavaInterop_Tests_Reference.cs
new file mode 100644
index 00000000000..e0a898e5cd8
--- /dev/null
+++ b/src/Mono.Android/Test/Java.Interop-Tests/Java.InteropTests/JavaInterop_Tests_Reference.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace Java.InteropTests
+{
+ // Exists for "easy" reference by Mono.Android-Tests.dll
+ public class JavaInterop_Tests_Reference
+ {
+ }
+}
diff --git a/src/Mono.Android/Test/Java.Interop-Tests/Properties/AssemblyInfo.cs b/src/Mono.Android/Test/Java.Interop-Tests/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000000..887802784b2
--- /dev/null
+++ b/src/Mono.Android/Test/Java.Interop-Tests/Properties/AssemblyInfo.cs
@@ -0,0 +1,30 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using Android.App;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Java.Interop_Tests")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Java.Interop_Tests")]
+[assembly: AssemblyCopyright("Copyright © 2018")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: ComVisible(false)]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/src/Mono.Android/Test/Java.Interop-Tests/Resources/AboutResources.txt b/src/Mono.Android/Test/Java.Interop-Tests/Resources/AboutResources.txt
new file mode 100644
index 00000000000..c2bca974c48
--- /dev/null
+++ b/src/Mono.Android/Test/Java.Interop-Tests/Resources/AboutResources.txt
@@ -0,0 +1,44 @@
+Images, layout descriptions, binary blobs and string dictionaries can be included
+in your application as resource files. Various Android APIs are designed to
+operate on the resource IDs instead of dealing with images, strings or binary blobs
+directly.
+
+For example, a sample Android app that contains a user interface layout (main.axml),
+an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png)
+would keep its resources in the "Resources" directory of the application:
+
+Resources/
+ drawable/
+ icon.png
+
+ layout/
+ main.axml
+
+ values/
+ strings.xml
+
+In order to get the build system to recognize Android resources, set the build action to
+"AndroidResource". The native Android APIs do not operate directly with filenames, but
+instead operate on resource IDs. When you compile an Android application that uses resources,
+the build system will package the resources for distribution and generate a class called "R"
+(this is an Android convention) that contains the tokens for each one of the resources
+included. For example, for the above Resources layout, this is what the R class would expose:
+
+public class R {
+ public class drawable {
+ public const int icon = 0x123;
+ }
+
+ public class layout {
+ public const int main = 0x456;
+ }
+
+ public class strings {
+ public const int first_string = 0xabc;
+ public const int second_string = 0xbcd;
+ }
+}
+
+You would then use R.drawable.icon to reference the drawable/icon.png file, or R.layout.main
+to reference the layout/main.axml file, or R.strings.first_string to reference the first
+string in the dictionary file values/strings.xml.
\ No newline at end of file
diff --git a/src/Mono.Android/Test/Java.Interop-Tests/packages.config b/src/Mono.Android/Test/Java.Interop-Tests/packages.config
new file mode 100644
index 00000000000..1c3a8d1b1f6
--- /dev/null
+++ b/src/Mono.Android/Test/Java.Interop-Tests/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/Mono.Android/Test/Mono.Android-Tests.csproj b/src/Mono.Android/Test/Mono.Android-Tests.csproj
index 0d018ae3ea2..96118c34a18 100644
--- a/src/Mono.Android/Test/Mono.Android-Tests.csproj
+++ b/src/Mono.Android/Test/Mono.Android-Tests.csproj
@@ -60,6 +60,9 @@
+
+
+
@@ -87,6 +90,10 @@
{CB2335CB-0050-4020-8A05-E9614EDAA05E}
TestRunner.NUnit
+
+ {6CB00820-A66B-43E5-8785-ED456C6E9F39}
+ Java.Interop-Tests
+
{8CB5FF58-FF95-43B9-9064-9ACE9525866F}
Mono.Android-Test.Library
diff --git a/src/Mono.Android/Test/Properties/AndroidManifest.xml b/src/Mono.Android/Test/Properties/AndroidManifest.xml
index d15674daf9a..a67c4caa579 100644
--- a/src/Mono.Android/Test/Properties/AndroidManifest.xml
+++ b/src/Mono.Android/Test/Properties/AndroidManifest.xml
@@ -1,7 +1,7 @@
-
+
diff --git a/src/Mono.Android/Test/Xamarin.Android.RuntimeTests/NUnitInstrumentation.cs b/src/Mono.Android/Test/Xamarin.Android.RuntimeTests/NUnitInstrumentation.cs
index 2da4d177c7b..0a58cd6bc81 100644
--- a/src/Mono.Android/Test/Xamarin.Android.RuntimeTests/NUnitInstrumentation.cs
+++ b/src/Mono.Android/Test/Xamarin.Android.RuntimeTests/NUnitInstrumentation.cs
@@ -30,10 +30,13 @@ protected NUnitInstrumentation(IntPtr handle, JniHandleOwnership transfer)
protected override IList GetTestAssemblies()
{
Assembly asm = Assembly.GetExecutingAssembly();
+ Assembly ji = typeof (Java.InteropTests.JavaInterop_Tests_Reference).Assembly;
+
return new List()
{
- new TestAssemblyInfo(asm, asm.Location ?? String.Empty)
+ new TestAssemblyInfo (asm, asm.Location ?? String.Empty),
+ new TestAssemblyInfo (ji, ji.Location ?? String.Empty),
};
}
}
diff --git a/src/Mono.Android/Test/Xamarin.Android.RuntimeTests/TestInstrumentation.cs b/src/Mono.Android/Test/Xamarin.Android.RuntimeTests/TestInstrumentation.cs
index e3dbc895242..1dfae2ed6af 100644
--- a/src/Mono.Android/Test/Xamarin.Android.RuntimeTests/TestInstrumentation.cs
+++ b/src/Mono.Android/Test/Xamarin.Android.RuntimeTests/TestInstrumentation.cs
@@ -21,6 +21,7 @@ public TestInstrumentation (IntPtr handle, JniHandleOwnership transfer)
protected override void AddTests ()
{
AddTest (Assembly.GetExecutingAssembly ());
+ AddTest (typeof (Java.InteropTests.JavaInterop_Tests_Reference).Assembly);
}
}
}
diff --git a/src/Mono.Android/Test/proguard.cfg b/src/Mono.Android/Test/proguard.cfg
new file mode 100644
index 00000000000..cbc69c8bebe
--- /dev/null
+++ b/src/Mono.Android/Test/proguard.cfg
@@ -0,0 +1,3 @@
+# Need to preserve the contents of Mono.Android-Test-classes.jar
+
+-keep class com.xamarin.interop.** { *; (); }
diff --git a/src/Xamarin.Android.Build.Tasks/Linker/PreserveLists/Java.Interop.xml b/src/Xamarin.Android.Build.Tasks/Linker/PreserveLists/Java.Interop.xml
new file mode 100644
index 00000000000..bfb2cfa1802
--- /dev/null
+++ b/src/Xamarin.Android.Build.Tasks/Linker/PreserveLists/Java.Interop.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Xamarin.Android.Build.Tasks/Linker/PreserveLists/Mono.Android.xml b/src/Xamarin.Android.Build.Tasks/Linker/PreserveLists/Mono.Android.xml
index c6da83bffdf..3c4d22fbfe0 100644
--- a/src/Xamarin.Android.Build.Tasks/Linker/PreserveLists/Mono.Android.xml
+++ b/src/Xamarin.Android.Build.Tasks/Linker/PreserveLists/Mono.Android.xml
@@ -47,6 +47,18 @@
-->
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Xamarin.Android.Build.Tasks/Resources/proguard_xamarin.cfg b/src/Xamarin.Android.Build.Tasks/Resources/proguard_xamarin.cfg
index 695f410aa22..4629e018dd5 100644
--- a/src/Xamarin.Android.Build.Tasks/Resources/proguard_xamarin.cfg
+++ b/src/Xamarin.Android.Build.Tasks/Resources/proguard_xamarin.cfg
@@ -3,6 +3,7 @@
-dontobfuscate
-keep class android.support.multidex.MultiDexApplication { (); }
+-keep class com.xamarin.java_interop.** { *; (); }
-keep class mono.MonoRuntimeProvider { *; (...); }
-keep class mono.MonoPackageManager { *; (...); }
-keep class mono.MonoPackageManager_Resources { *; (...); }
diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj
index 104bf1c41f2..75de516c1b7 100644
--- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj
+++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj
@@ -625,6 +625,9 @@
MonoRuntimeProvider.Shared.20.java
+
+ Java.Interop.xml
+
mscorlib.xml
diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.props.in b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.props.in
index c03391c09b3..1277d2b5aac 100644
--- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.props.in
+++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.props.in
@@ -19,6 +19,7 @@
26.1.1
16.1
@BUNDLETOOL_VERSION@
+ <_XamarinAndroidMSBuildDirectory>$(MSBuildThisFileDirectory)
true
diff --git a/src/monodroid/jni/monodroid-glue.cc b/src/monodroid/jni/monodroid-glue.cc
index b7420ccff6e..34874dbb143 100644
--- a/src/monodroid/jni/monodroid-glue.cc
+++ b/src/monodroid/jni/monodroid-glue.cc
@@ -903,6 +903,16 @@ MonodroidRuntime::lookup_bridge_info (MonoDomain *domain, MonoImage *image, cons
info->handle_type = mono_class_get_field_from_name (info->klass, const_cast ("handle_type"));
info->refs_added = mono_class_get_field_from_name (info->klass, const_cast ("refs_added"));
info->weak_handle = mono_class_get_field_from_name (info->klass, const_cast ("weak_handle"));
+ if (info->klass == NULL || info->handle == NULL || info->handle_type == NULL ||
+ info->refs_added == NULL || info->weak_handle == NULL) {
+ log_fatal (LOG_DEFAULT, "The type `%s.%s` is missing required instance fields! handle=%p handle_type=%p refs_added=%p weak_handle=%p",
+ type->_namespace, type->_typename,
+ info->handle,
+ info->handle_type,
+ info->refs_added,
+ info->weak_handle);
+ exit (FATAL_EXIT_MONO_MISSING_SYMBOLS);
+ }
}
void
@@ -932,7 +942,9 @@ MonodroidRuntime::init_android_runtime (MonoDomain *domain, JNIEnv *env, jclass
MonoAssembly *assm = utils.monodroid_load_assembly (domain, "Mono.Android");
MonoImage *image = mono_assembly_get_image (assm);
- for (uint32_t i = 0; i < OSBridge::NUM_GC_BRIDGE_TYPES; ++i) {
+ uint32_t i = 0;
+
+ for ( ; i < OSBridge::NUM_XA_GC_BRIDGE_TYPES; ++i) {
lookup_bridge_info (domain, image, &osBridge.get_java_gc_bridge_type (i), &osBridge.get_java_gc_bridge_info (i));
}
@@ -944,6 +956,13 @@ MonodroidRuntime::init_android_runtime (MonoDomain *domain, JNIEnv *env, jclass
log_fatal (LOG_DEFAULT, "INTERNAL ERROR: Unable to find Android.Runtime.JNIEnv.Initialize!");
exit (FATAL_EXIT_MISSING_INIT);
}
+
+ MonoAssembly *ji_assm = utils.monodroid_load_assembly (domain, "Java.Interop");
+ MonoImage *ji_image = mono_assembly_get_image (ji_assm);
+ for ( ; i < OSBridge::NUM_XA_GC_BRIDGE_TYPES + OSBridge::NUM_JI_GC_BRIDGE_TYPES; ++i) {
+ lookup_bridge_info (domain, ji_image, &osBridge.get_java_gc_bridge_type (i), &osBridge.get_java_gc_bridge_info (i));
+ }
+
/* If running on desktop, we may be swapping in a new Mono.Android image when calling this
* so always make sure we have the freshest handle to the method.
*/
diff --git a/src/monodroid/jni/osbridge.cc b/src/monodroid/jni/osbridge.cc
index b3b72c45d92..dcbe73c131a 100644
--- a/src/monodroid/jni/osbridge.cc
+++ b/src/monodroid/jni/osbridge.cc
@@ -37,17 +37,25 @@ FILE *lref_log;
using namespace xamarin::android;
using namespace xamarin::android::internal;
-const OSBridge::MonoJavaGCBridgeType OSBridge::mono_java_gc_bridge_types[] = {
+const OSBridge::MonoJavaGCBridgeType OSBridge::mono_xa_gc_bridge_types[] = {
{ "Java.Lang", "Object" },
{ "Java.Lang", "Throwable" },
};
+const OSBridge::MonoJavaGCBridgeType OSBridge::mono_ji_gc_bridge_types[] = {
+ { "Java.Interop", "JavaObject" },
+ { "Java.Interop", "JavaException" },
+};
+
const OSBridge::MonoJavaGCBridgeType OSBridge::empty_bridge_type = {
"",
""
};
-const uint32_t OSBridge::NUM_GC_BRIDGE_TYPES = (sizeof (mono_java_gc_bridge_types)/sizeof (mono_java_gc_bridge_types [0]));
+const uint32_t OSBridge::NUM_XA_GC_BRIDGE_TYPES = (sizeof (mono_xa_gc_bridge_types)/sizeof (mono_xa_gc_bridge_types [0]));
+const uint32_t OSBridge::NUM_JI_GC_BRIDGE_TYPES = (sizeof (mono_ji_gc_bridge_types)/sizeof (mono_ji_gc_bridge_types [0]));
+const uint32_t OSBridge::NUM_GC_BRIDGE_TYPES = NUM_XA_GC_BRIDGE_TYPES + NUM_JI_GC_BRIDGE_TYPES;
+
OSBridge::MonoJavaGCBridgeInfo OSBridge::mono_java_gc_bridge_info [NUM_GC_BRIDGE_TYPES];
OSBridge::MonoJavaGCBridgeInfo OSBridge::empty_bridge_info = {
diff --git a/src/monodroid/jni/osbridge.hh b/src/monodroid/jni/osbridge.hh
index 0452314e2a7..3c2e99b5568 100644
--- a/src/monodroid/jni/osbridge.hh
+++ b/src/monodroid/jni/osbridge.hh
@@ -55,11 +55,14 @@ namespace xamarin::android::internal
using MonodroidGCTakeRefFunc = mono_bool (OSBridge::*) (JNIEnv *env, MonoObject *obj);
static const MonoJavaGCBridgeType empty_bridge_type;
- static const MonoJavaGCBridgeType mono_java_gc_bridge_types[];
+ static const MonoJavaGCBridgeType mono_xa_gc_bridge_types[];
+ static const MonoJavaGCBridgeType mono_ji_gc_bridge_types[];
static MonoJavaGCBridgeInfo empty_bridge_info;
static MonoJavaGCBridgeInfo mono_java_gc_bridge_info [];
public:
+ static const uint32_t NUM_XA_GC_BRIDGE_TYPES;
+ static const uint32_t NUM_JI_GC_BRIDGE_TYPES;
static const uint32_t NUM_GC_BRIDGE_TYPES;
public:
@@ -73,10 +76,15 @@ namespace xamarin::android::internal
const MonoJavaGCBridgeType& get_java_gc_bridge_type (uint32_t index)
{
- if (index >= NUM_GC_BRIDGE_TYPES)
- return empty_bridge_type; // Not ideal...
+ if (index < NUM_XA_GC_BRIDGE_TYPES)
+ return mono_xa_gc_bridge_types [index];
+
+ index -= NUM_XA_GC_BRIDGE_TYPES;
+ if (index < NUM_JI_GC_BRIDGE_TYPES)
+ return mono_ji_gc_bridge_types [index];
- return mono_java_gc_bridge_types [index];
+ index -= NUM_JI_GC_BRIDGE_TYPES;
+ return empty_bridge_type; // Not ideal...
}
MonoJavaGCBridgeInfo& get_java_gc_bridge_info (uint32_t index)
diff --git a/tests/Runtime-AppBundle/Mono.Android-TestsAppBundle.csproj b/tests/Runtime-AppBundle/Mono.Android-TestsAppBundle.csproj
index 3122174af9b..793fa8b7d00 100644
--- a/tests/Runtime-AppBundle/Mono.Android-TestsAppBundle.csproj
+++ b/tests/Runtime-AppBundle/Mono.Android-TestsAppBundle.csproj
@@ -46,6 +46,7 @@
4
false
true
+ r8
@@ -64,6 +65,9 @@
+
+
+
Resources\drawable\Icon.png
@@ -118,6 +122,10 @@
{CB2335CB-0050-4020-8A05-E9614EDAA05E}
TestRunner.NUnit
+
+ {6CB00820-A66B-43E5-8785-ED456C6E9F39}
+ Java.Interop-Tests
+
{8CB5FF58-FF95-43B9-9064-9ACE9525866F}
Mono.Android-Test.Library
diff --git a/tests/Runtime-MultiDex/Mono.Android-TestsMultiDex.csproj b/tests/Runtime-MultiDex/Mono.Android-TestsMultiDex.csproj
index 560945d0980..39810986789 100644
--- a/tests/Runtime-MultiDex/Mono.Android-TestsMultiDex.csproj
+++ b/tests/Runtime-MultiDex/Mono.Android-TestsMultiDex.csproj
@@ -45,6 +45,7 @@
4
false
true
+ r8
@@ -63,6 +64,9 @@
+
+
+
@@ -97,6 +101,10 @@
{CB2335CB-0050-4020-8A05-E9614EDAA05E}
TestRunner.NUnit
+
+ {6CB00820-A66B-43E5-8785-ED456C6E9F39}
+ Java.Interop-Tests
+
{8CB5FF58-FF95-43B9-9064-9ACE9525866F}
Mono.Android-Test.Library
diff --git a/tests/TestRunner.Core/TestRunner.Core.csproj b/tests/TestRunner.Core/TestRunner.Core.csproj
index b7627a66dae..6e0b2cdb5a5 100644
--- a/tests/TestRunner.Core/TestRunner.Core.csproj
+++ b/tests/TestRunner.Core/TestRunner.Core.csproj
@@ -8,15 +8,15 @@
Library
Xamarin.Android.UnitTests
TestRunner.Core
- v8.1
+ v9.0
Resources\Resource.designer.cs
Resource
Resources
Assets
- true
+ $(AndroidFrameworkVersion)
true
false
bin\Debug
@@ -26,6 +26,7 @@
None
+ $(AndroidFrameworkVersion)
true
true
bin\Release
diff --git a/tests/TestRunner.NUnit/TestRunner.NUnit.csproj b/tests/TestRunner.NUnit/TestRunner.NUnit.csproj
index 9a162b00004..e85d234a57d 100644
--- a/tests/TestRunner.NUnit/TestRunner.NUnit.csproj
+++ b/tests/TestRunner.NUnit/TestRunner.NUnit.csproj
@@ -8,15 +8,15 @@
Library
Xamarin.Android.UnitTests.NUnit
TestRunner.NUnit
- v8.1
+ v9.0
Resources\Resource.designer.cs
Resource
Resources
Assets
- true
+ $(AndroidFrameworkVersion)
true
false
bin\Debug
@@ -26,6 +26,7 @@
None
+ $(AndroidFrameworkVersion)
true
true
bin\Release