Skip to content

Commit c61d178

Browse files
[Mono.Android] call new Java "GC Bridge" APIs
Context: dotnet/runtime#114184 Context: https://github.com/jonathanpeppers/BridgeSandbox So far, I: * Built dotnet/runtime, I built this branch: https://github.com/jonathanpeppers/runtime/tree/gcbridge_impl * Put the relevant arm64 packs in `packages/` folder and configured a `NuGet.config` to use them. * Setup a `UpdateRuntimePacks` target in the `Mono.Android.csproj` to use the 10.0.0-dev packs. * Make use of the new `JavaMarshal.CreateReferenceTrackingHandle()` API * This is WIP there are still more APIs.
1 parent 199efa8 commit c61d178

File tree

7 files changed

+72
-24
lines changed

7 files changed

+72
-24
lines changed

.gitattributes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,5 @@ Makefile eol=lf
3535
*.wixproj eol=crlf
3636
*.wxs eol=crlf
3737
*.rtf eol=crlf
38+
39+
packages/* filter=lfs diff=lfs merge=lfs -text

Documentation/workflow/DevelopmentTips.md

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -450,13 +450,26 @@ A second (better) way is to add this MSBuild target to your Android
450450
`.csproj` file:
451451

452452
```xml
453-
<Target Name="UpdateMonoRuntimePacks" BeforeTargets="ProcessFrameworkReferences">
453+
<Target Name="UpdateKnownPacks" BeforeTargets="ProcessFrameworkReferences">
454+
<PropertyGroup>
455+
<!-- This could be a version I built myself -->
456+
<_Version>10.0.0-dev</_Version>
457+
</PropertyGroup>
454458
<ItemGroup>
455-
<KnownRuntimePack
456-
Update="Microsoft.NETCore.App"
457-
Condition=" '%(KnownRuntimePack.TargetFramework)' == 'net6.0' "
458-
LatestRuntimeFrameworkVersion="6.0.0-preview.7.21364.3"
459-
/>
459+
<!-- For runtime packs only -->
460+
<KnownRuntimePack
461+
Update="Microsoft.NETCore.App"
462+
Condition=" '%(KnownRuntimePack.TargetFramework)' == 'net10.0' "
463+
LatestRuntimeFrameworkVersion="$(_Version)"
464+
/>
465+
<!-- For new .NET APIs -->
466+
<KnownFrameworkReference
467+
Update="Microsoft.NETCore.App"
468+
Condition=" '%(KnownFrameworkReference.TargetFramework)' == 'net10.0' "
469+
DefaultRuntimeFrameworkVersion="$(_Version)"
470+
LatestRuntimeFrameworkVersion="$(_Version)"
471+
TargetingPackVersion="$(_Version)"
472+
/>
460473
</ItemGroup>
461474
</Target>
462475
```

NuGet.config

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
<!-- End: Package sources from dotnet-android -->
88
<!--End: Package sources managed by Dependency Flow automation. Do not edit the sources above.-->
99
<!-- ensure only the sources defined below are used -->
10+
<add key="local-packages" value="packages" />
1011
<add key="dotnet-public" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public/nuget/v3/index.json" protocolVersion="3" />
1112
<add key="dotnet-eng" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json" protocolVersion="3" />
1213
<!-- This is for packages needed by debugger-libs -->
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
version https://git-lfs.github.com/spec/v1
2+
oid sha256:d23f78cb9dec82f9ed64e0b9b803fe533d2628d63e1af54685ff8827b1d799bb
3+
size 5313525
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
version https://git-lfs.github.com/spec/v1
2+
oid sha256:7c6e9746aaf2b91c7009d940eeda588129f4be8fc864ca6259dc6e5845abe48f
3+
size 215347082

src/Mono.Android/Microsoft.Android.Runtime/ManagedValueManager.cs

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using System.Reflection;
1111
using System.Runtime.CompilerServices;
1212
using System.Runtime.InteropServices;
13+
using System.Runtime.InteropServices.Java;
1314
using System.Threading;
1415
using Android.Runtime;
1516
using Java.Interop;
@@ -20,7 +21,7 @@ class ManagedValueManager : JniRuntime.JniValueManager
2021
{
2122
const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors;
2223

23-
Dictionary<int, List<IJavaPeerable>>? RegisteredInstances = new Dictionary<int, List<IJavaPeerable>>();
24+
Dictionary<int, List<GCHandle>>? RegisteredInstances = new();
2425

2526
internal ManagedValueManager ()
2627
{
@@ -35,7 +36,7 @@ public override void CollectPeers ()
3536
if (RegisteredInstances == null)
3637
throw new ObjectDisposedException (nameof (ManagedValueManager));
3738

38-
var peers = new List<IJavaPeerable> ();
39+
var peers = new List<GCHandle> ();
3940

4041
lock (RegisteredInstances) {
4142
foreach (var ps in RegisteredInstances.Values) {
@@ -48,7 +49,8 @@ public override void CollectPeers ()
4849
List<Exception>? exceptions = null;
4950
foreach (var peer in peers) {
5051
try {
51-
peer.Dispose ();
52+
if (peer.Target is IDisposable disposable)
53+
disposable.Dispose ();
5254
}
5355
catch (Exception e) {
5456
exceptions = exceptions ?? new List<Exception> ();
@@ -74,33 +76,35 @@ public override void AddPeer (IJavaPeerable value)
7476
}
7577
int key = value.JniIdentityHashCode;
7678
lock (RegisteredInstances) {
77-
List<IJavaPeerable>? peers;
79+
List<GCHandle>? peers;
7880
if (!RegisteredInstances.TryGetValue (key, out peers)) {
79-
peers = new List<IJavaPeerable> () {
80-
value,
81+
peers = new List<GCHandle> () {
82+
JavaMarshal.CreateReferenceTrackingHandle (value, value.PeerReference.Handle)
8183
};
8284
RegisteredInstances.Add (key, peers);
8385
return;
8486
}
8587

8688
for (int i = peers.Count - 1; i >= 0; i--) {
8789
var p = peers [i];
88-
if (!JniEnvironment.Types.IsSameObject (p.PeerReference, value.PeerReference))
90+
if (p.Target is not IJavaPeerable peer)
91+
continue;
92+
if (!JniEnvironment.Types.IsSameObject (peer.PeerReference, value.PeerReference))
8993
continue;
9094
if (Replaceable (p)) {
91-
peers [i] = value;
95+
peers [i] = JavaMarshal.CreateReferenceTrackingHandle (value, value.PeerReference.Handle);
9296
} else {
93-
WarnNotReplacing (key, value, p);
97+
WarnNotReplacing (key, value, peer);
9498
}
9599
return;
96100
}
97-
peers.Add (value);
101+
peers.Add (JavaMarshal.CreateReferenceTrackingHandle (value, value.PeerReference.Handle));
98102
}
99103
}
100104

101-
static bool Replaceable (IJavaPeerable peer)
105+
static bool Replaceable (GCHandle handle)
102106
{
103-
if (peer == null)
107+
if (handle.Target is not IJavaPeerable peer)
104108
return true;
105109
return peer.JniManagedPeerState.HasFlag (JniManagedPeerStates.Replaceable);
106110
}
@@ -132,14 +136,14 @@ void WarnNotReplacing (int key, IJavaPeerable ignoreValue, IJavaPeerable keepVal
132136
int key = GetJniIdentityHashCode (reference);
133137

134138
lock (RegisteredInstances) {
135-
List<IJavaPeerable>? peers;
139+
List<GCHandle>? peers;
136140
if (!RegisteredInstances.TryGetValue (key, out peers))
137141
return null;
138142

139143
for (int i = peers.Count - 1; i >= 0; i--) {
140144
var p = peers [i];
141-
if (JniEnvironment.Types.IsSameObject (reference, p.PeerReference))
142-
return p;
145+
if (p.Target is IJavaPeerable peer && JniEnvironment.Types.IsSameObject (reference, peer.PeerReference))
146+
return peer;
143147
}
144148
if (peers.Count == 0)
145149
RegisteredInstances.Remove (key);
@@ -157,13 +161,13 @@ public override void RemovePeer (IJavaPeerable value)
157161

158162
int key = value.JniIdentityHashCode;
159163
lock (RegisteredInstances) {
160-
List<IJavaPeerable>? peers;
164+
List<GCHandle>? peers;
161165
if (!RegisteredInstances.TryGetValue (key, out peers))
162166
return;
163167

164168
for (int i = peers.Count - 1; i >= 0; i--) {
165169
var p = peers [i];
166-
if (object.ReferenceEquals (value, p)) {
170+
if (object.ReferenceEquals (value, p.Target)) {
167171
peers.RemoveAt (i);
168172
}
169173
}
@@ -251,7 +255,9 @@ public override List<JniSurfacedPeerInfo> GetSurfacedPeers ()
251255
var peers = new List<JniSurfacedPeerInfo> (RegisteredInstances.Count);
252256
foreach (var e in RegisteredInstances) {
253257
foreach (var p in e.Value) {
254-
peers.Add (new JniSurfacedPeerInfo (e.Key, new WeakReference<IJavaPeerable> (p)));
258+
if (p.Target is not IJavaPeerable peer)
259+
continue;
260+
peers.Add (new JniSurfacedPeerInfo (e.Key, new WeakReference<IJavaPeerable> (peer)));
255261
}
256262
}
257263
return peers;

src/Mono.Android/Mono.Android.csproj

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,26 @@
2525
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
2626
</PropertyGroup>
2727

28+
<!-- Use version in local packages folder -->
29+
<Target Name="UpdateRuntimePacks" BeforeTargets="ProcessFrameworkReferences">
30+
<PropertyGroup>
31+
<_Version>10.0.0-dev</_Version>
32+
</PropertyGroup>
33+
<ItemGroup>
34+
<KnownFrameworkReference Update="Microsoft.NETCore.App"
35+
Condition=" '%(KnownFrameworkReference.TargetFramework)' == 'net10.0' "
36+
DefaultRuntimeFrameworkVersion="$(_Version)"
37+
LatestRuntimeFrameworkVersion="$(_Version)"
38+
TargetingPackVersion="$(_Version)"
39+
/>
40+
<KnownRuntimePack
41+
Update="Microsoft.NETCore.App"
42+
Condition=" '%(KnownRuntimePack.TargetFramework)' == 'net10.0' "
43+
LatestRuntimeFrameworkVersion="$(_Version)"
44+
/>
45+
</ItemGroup>
46+
</Target>
47+
2848
<PropertyGroup>
2949
<IsUnstableVersion Condition=" '$(AndroidApiLevel)' &gt; '$(AndroidLatestStableApiLevel)' ">true</IsUnstableVersion>
3050
<DefineConstants Condition=" '$(IsUnstableVersion)' == 'True' ">$(DefineConstants);ANDROID_UNSTABLE</DefineConstants>

0 commit comments

Comments
 (0)