Skip to content

Commit 837ca0d

Browse files
[Microsoft.Android.Sdk.ILLink] fix crash when TZ changes (#7956)
Fixes: #7953 Context: 11f0e1b When a timezone changes in a `Release` config app, it can crash with: [monodroid] Unable to find Android.Runtime.AndroidEnvironment.NotifyTimeZoneChanged()! In commit 11f0e1b, we removed the line: <?xml version="1.0" encoding="utf-8" ?> <linker> <assembly fullname="Mono.Android"> -- <type fullname="Android.Runtime.AndroidEnvironment" /> Unfortunately, `AndroidEnvironment.NotifyTimeZoneChanged()` is called from non-managed code, via: * The `NotifyTimeZoneChanges` broadcast receiver (in `src/java-runtime/java/mono/android/app/NotifyTimeZoneChanges.java`) which calls- * The `Rutime.notifyTimeZoneChanged()` `native` method (in `src/java-runtime/java/mono/android/Runtime.java`), implemented in- * `Java_mono_android_Runtime_notifyTimeZoneChanged()` (in`src/monodroid/jni/timezones.cc`). The managed linker cannot "see" any of these references, so we need to *always* preserve this method, as it is always callable. Update `src/Microsoft.Android.Sdk.ILLink/PreserveLists/Mono.Android.xml` so that `Android.Runtime.AndroidEnvironment.NotifyTimeZoneChanged()` is always preserved. Added a test for this scenario. TODO: we may want to audit all `mono_class_get_method_from_name()` calls and add more tests cases. I also cleaned up the tests a bit with a `getResource()` local function.
1 parent a693bc5 commit 837ca0d

File tree

4 files changed

+42
-20
lines changed

4 files changed

+42
-20
lines changed

src/Microsoft.Android.Sdk.ILLink/PreserveLists/Mono.Android.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
<linker>
33
<assembly fullname="Mono.Android">
44
<type fullname="Android.Runtime.AnnotationAttribute" />
5+
<type fullname="Android.Runtime.AndroidEnvironment">
6+
<method name="NotifyTimeZoneChanged" />
7+
</type>
58
<type fullname="Android.Runtime.IJavaObject" />
69
<type fullname="Android.Runtime.InputStreamAdapter" preserve="methods" />
710
<type fullname="Android.Runtime.InputStreamInvoker" preserve="methods" />

tests/MSBuildDeviceIntegration/Resources/LinkDescTest/MainActivityReplacement.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ protected override void OnCreate(Bundle bundle)
115115
// [Test] Post
116116
Android.Util.Log.Info(TAG, HttpClientTest.Post ());
117117

118+
// [Test] MethodsArePreserved
119+
Android.Util.Log.Info (TAG, PreserveTest.MethodsArePreserved ());
120+
118121
// [Test] TextChanged
119122
Android.Util.Log.Info (TAG, MaterialTextChanged.TextChanged (this));
120123

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System;
2+
using System.Reflection;
3+
4+
public class PreserveTest
5+
{
6+
// [Test]
7+
public static string MethodsArePreserved ()
8+
{
9+
try {
10+
// See src/monodroid/jni/timezones.cc for usage
11+
var androidEnvironment = Type.GetType ("Android.Runtime.AndroidEnvironment, Mono.Android", throwOnError: true);
12+
var notifyTimeZoneChanged = androidEnvironment.GetMethod ("NotifyTimeZoneChanged", BindingFlags.Static | BindingFlags.NonPublic);
13+
if (notifyTimeZoneChanged == null) {
14+
return $"[FAIL] {nameof (PreserveTest)}.{nameof (MethodsArePreserved)} FAILED: {nameof (notifyTimeZoneChanged)} is null)";
15+
}
16+
notifyTimeZoneChanged.Invoke (null, null);
17+
return $"[PASS] {nameof (PreserveTest)}.{nameof (MethodsArePreserved)}";
18+
} catch (Exception ex) {
19+
return $"[FAIL] {nameof (PreserveTest)}.{nameof (MethodsArePreserved)} FAILED: {ex}";
20+
}
21+
}
22+
}

tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -383,22 +383,16 @@ public class LinkModeFullClass {
383383
},
384384
Sources = {
385385
new BuildItem.Source ("Bug21578.cs") {
386-
TextContent = () => {
387-
using (var sr = new StreamReader (typeof (InstallAndRunTests).Assembly.GetManifestResourceStream ("Xamarin.Android.Build.Tests.Resources.LinkDescTest.Bug21578.cs")))
388-
return sr.ReadToEnd ();
389-
},
386+
TextContent = () => getResource("Bug21578")
390387
},
391388
new BuildItem.Source ("Bug35195.cs") {
392-
TextContent = () => {
393-
using (var sr = new StreamReader (typeof (InstallAndRunTests).Assembly.GetManifestResourceStream ("Xamarin.Android.Build.Tests.Resources.LinkDescTest.Bug35195.cs")))
394-
return sr.ReadToEnd ();
395-
},
389+
TextContent = () => getResource("Bug35195")
396390
},
397391
new BuildItem.Source ("HttpClientTest.cs") {
398-
TextContent = () => {
399-
using (var sr = new StreamReader (typeof (InstallAndRunTests).Assembly.GetManifestResourceStream ("Xamarin.Android.Build.Tests.Resources.LinkDescTest.HttpClientTest.cs")))
400-
return sr.ReadToEnd ();
401-
},
392+
TextContent = () => getResource("HttpClientTest")
393+
},
394+
new BuildItem.Source ("PreserveTest.cs") {
395+
TextContent = () => getResource("PreserveTest")
402396
},
403397
},
404398
};
@@ -407,10 +401,7 @@ public class LinkModeFullClass {
407401
// DataContractSerializer is not trimming safe
408402
// https://github.com/dotnet/runtime/issues/45559
409403
lib2.Sources.Add (new BuildItem.Source ("Bug36250.cs") {
410-
TextContent = () => {
411-
using (var sr = new StreamReader (typeof (InstallAndRunTests).Assembly.GetManifestResourceStream ("Xamarin.Android.Build.Tests.Resources.LinkDescTest.Bug36250.cs")))
412-
return sr.ReadToEnd ();
413-
},
404+
TextContent = () => getResource ("Bug36250")
414405
});
415406
}
416407

@@ -433,10 +424,7 @@ public class LinkModeFullClass {
433424
},
434425
Sources = {
435426
new BuildItem.Source ("MaterialTextChanged.cs") {
436-
TextContent = () => {
437-
using (var sr = new StreamReader (typeof (InstallAndRunTests).Assembly.GetManifestResourceStream ("Xamarin.Android.Build.Tests.Resources.LinkDescTest.MaterialTextChanged.cs")))
438-
return sr.ReadToEnd ();
439-
},
427+
TextContent = () => getResource ("MaterialTextChanged")
440428
},
441429
},
442430
OtherBuildItems = {
@@ -500,6 +488,12 @@ public class LinkModeFullClass {
500488
StringAssert.Contains ("[LINKALLPASS]", logcatOutput);
501489
StringAssert.DoesNotContain ("[LINKALLFAIL]", logcatOutput);
502490
}
491+
492+
string getResource (string name)
493+
{
494+
using (var sr = new StreamReader (typeof (InstallAndRunTests).Assembly.GetManifestResourceStream ($"Xamarin.Android.Build.Tests.Resources.LinkDescTest.{name}.cs")))
495+
return sr.ReadToEnd ();
496+
}
503497
}
504498

505499
[Test]

0 commit comments

Comments
 (0)