Commit e88cfbc
authored
[linker] Add AddKeepAlivesStep (#5278)
Context: dotnet/java-interop#719
Context: dotnet/java-interop@1f21f38
Context: https://docs.microsoft.com/archive/blogs/cbrumme/lifetime-gc-keepalive-handle-recycling
We discovered the cause of a latent potential crash within
Xamarin.Android apps:
JNI DETECTED ERROR IN APPLICATION: use of deleted global reference 0x3d86
…
The cause of the "use of deleted global reference" was that the GC
collected an instance after it was provided to Java, but before Java
could keep the instance alive in a manner which would cause our GC
bridge to keep it alive, akin to:
CallIntoJava (new JavaLangObjectSubclass ().Handle);
In the above example code, if the `JavaLangObjectSubclass` instance
is collected by the GC *after* the `.Handle` property is accessed
but *before* `CallIntoJava()` is executed, then the `.Handle` value
will refer to a "deleted global reference" and cause the app crash.
The appropriate fix is to ensure that the GC *won't* collect it,
usually by calling [`GC.KeepAlive()`][0]:
var value = new JavaLangObjectSubclass ();
CallIntoJava (value.Handle);
GC.KeepAlive (value);
An important aspect of the problem is that much of the relevant code
introducing this scenario is within *binding assemblies*:
partial class Activity {
public virtual unsafe Android.App.PendingIntent? CreatePendingResult (
int requestCode,
Android.Content.Intent data,
[global::Android.Runtime.GeneratedEnum] Android.App.PendingIntentFlags flags)
{
const string __id = "createPendingResult.(ILandroid/content/Intent;I)Landroid/app/PendingIntent;";
try {
JniArgumentValue* __args = stackalloc JniArgumentValue [3];
__args [0] = new JniArgumentValue (requestCode);
__args [1] = new JniArgumentValue ((data == null) ? IntPtr.Zero : ((global::Java.Lang.Object) data).Handle);
__args [2] = new JniArgumentValue ((int) flags);
var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, __args);
return global::Java.Lang.Object.GetObject<Android.App.PendingIntent> (__rm.Handle, JniHandleOwnership.TransferLocalRef);
} finally {
}
}
}
Here, the issue is that `data.Handle` is passed into Java code, but
it's possible that `data` may be collected *after* `data.Handle` is
accessed but before
`_members.InstanceMethods.InvokeVirtualObjectMethod()` is invoked.
dotnet/java-interop@1f21f38c introduced a `generator` fix for this
this problem, inserting an appropriate `GC.KeepAlive()`:
partial class Activity {
public virtual unsafe Android.App.PendingIntent? CreatePendingResult (
int requestCode, Android.Content.Intent data,
[global::Android.Runtime.GeneratedEnum] Android.App.PendingIntentFlags flags)
{
const string __id = "createPendingResult.(ILandroid/content/Intent;I)Landroid/app/PendingIntent;";
try {
JniArgumentValue* __args = stackalloc JniArgumentValue [3];
__args [0] = new JniArgumentValue (requestCode);
__args [1] = new JniArgumentValue ((data == null) ? IntPtr.Zero : ((global::Java.Lang.Object) data).Handle);
__args [2] = new JniArgumentValue ((int) flags);
var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, __args);
return global::Java.Lang.Object.GetObject<Android.App.PendingIntent> (__rm.Handle, JniHandleOwnership.TransferLocalRef);
} finally {
GC.KeepAlive (data);
}
}
}
The problem is that a fix within *generator* is meaningless until all
relevant binding assemblies are *also* updated: fixing the issue
within `Mono.Android.dll` only fixes `Mono.Android.dll`!
We don't -- and can't! -- expect the entire ecosystem to rebuild and
republish binding assemblies, which means a `generator` fix isn't a
complete fix!
To help fix the *ecosystem*, update the *linker* to insert appropriate
`GC.KeepAlive()` invocations into marshal methods. This allows fixing
the "problem domain" -- premature instance collection -- without
requiring that the entire ecosystem be rebuilt.
Instead, it "merely" requires that all *applications* be rebuilt.
Add a new `$(AndroidAddKeepAlives)` MSBuild property which controls
whether or not the linker inserts the `GC.KeepAlive()` calls.
`$(AndroidAddKeepAlives)` defaults to True for Release configuration
apps, and is False by default for "fast deployment" Debug builds.
`$(AndroidAddKeepAlives)` can be overridden to explicitly enable or
disable the new linker steps.
The impact on release build of XA forms template (flyout variety) is
cca 137ms on @radekdoulik's machine.
* Disabled:
12079 ms LinkAssemblies 1 calls
* Enabled:
12216 ms LinkAssemblies 1 calls
Co-authored-by: Radek Doulik <[email protected]>
[0]: https://docs.microsoft.com/dotnet/api/system.gc.keepalive1 parent 136353a commit e88cfbc
File tree
13 files changed
+327
-94
lines changed- Documentation
- guides/building-apps
- release-notes
- src
- Microsoft.Android.Sdk.ILLink
- Xamarin.Android.Build.Tasks
- Linker/MonoDroid.Tuner
- Tasks
- Tests/Xamarin.Android.Build.Tests/Tasks
13 files changed
+327
-94
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
50 | 50 | | |
51 | 51 | | |
52 | 52 | | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
53 | 63 | | |
54 | 64 | | |
55 | 65 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
Lines changed: 1 addition & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
28 | 28 | | |
29 | 29 | | |
30 | 30 | | |
| 31 | + | |
31 | 32 | | |
32 | 33 | | |
33 | 34 | | |
| |||
Lines changed: 130 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
Lines changed: 70 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
46 | 46 | | |
47 | 47 | | |
48 | 48 | | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
49 | 119 | | |
50 | 120 | | |
51 | 121 | | |
| |||
Lines changed: 4 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
65 | 65 | | |
66 | 66 | | |
67 | 67 | | |
| 68 | + | |
| 69 | + | |
68 | 70 | | |
69 | 71 | | |
70 | 72 | | |
| |||
118 | 120 | | |
119 | 121 | | |
120 | 122 | | |
| 123 | + | |
| 124 | + | |
121 | 125 | | |
122 | 126 | | |
123 | 127 | | |
| |||
Lines changed: 1 addition & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
22 | 22 | | |
23 | 23 | | |
24 | 24 | | |
| 25 | + | |
25 | 26 | | |
26 | 27 | | |
27 | 28 | | |
| |||
0 commit comments