Skip to content

Commit fdbb7f8

Browse files
[Mono.Android] trimmer feature switches replace DotNetRuntimeType (#10296)
Context: #10198 (comment) `ManagedValueManager` is not currently trimmed away in Android apps running on Mono. We can make this happen by: * Remove `DotNetRuntimeType` enum * Introduce `RuntimeFeature.IsMonoRuntime` and `RuntimeFeature.IsCoreClrRuntime` * Set switches by default for each runtime: <ItemGroup> <RuntimeHostConfigurationOption Include="Microsoft.Android.Runtime.RuntimeFeature.IsMonoRuntime" Value="false" Trim="true" /> <RuntimeHostConfigurationOption Include="Microsoft.Android.Runtime.RuntimeFeature.IsCoreClrRuntime" Value="true" Trim="true" /> </ItemGroup> I have not yet seen a need within the code to introduce `RuntimeFeature.IsNativeAotRuntime`, but we could do so in the future. Currently, NativeAOT works via the other two runtime feature switches being `false` and then none of the problematic code paths are hit. * Update `BuildReleaseArm64SimpleDotNet.apkdesc` This fixes the minor app size regression in 1f8f719.
1 parent 1f8f719 commit fdbb7f8

File tree

16 files changed

+113
-122
lines changed

16 files changed

+113
-122
lines changed

src/Mono.Android.Runtime/Mono.Android.Runtime.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,11 @@
5252
<ItemGroup>
5353
<Compile Include="$(IntermediateOutputPath)AssemblyInfo.cs" />
5454
<Compile Include="..\Mono.Android\Android.Runtime\AndroidRuntimeInternal.cs" />
55-
<Compile Include="..\Mono.Android\Android.Runtime\DotNetRuntimeType.cs" />
5655
<Compile Include="..\Mono.Android\Android.Runtime\LogCategories.cs" />
5756
<Compile Include="..\Mono.Android\Android.Runtime\LogLevel.cs" />
5857
<Compile Include="..\Mono.Android\Android.Runtime\RuntimeConstants.cs" />
5958
<Compile Include="..\Mono.Android\Android.Runtime\RuntimeNativeMethods.cs" />
59+
<Compile Include="..\Mono.Android\Microsoft.Android.Runtime\RuntimeFeature.cs" />
6060
<Compile Include="Android.Runtime\AndroidEnvironmentInternal.cs" />
6161
</ItemGroup>
6262

src/Mono.Android/Android.Runtime/AndroidRuntimeInternal.cs

Lines changed: 8 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,10 @@
11
#if INSIDE_MONO_ANDROID_RUNTIME
22
using System;
33
using System.Reflection;
4+
using Microsoft.Android.Runtime;
45

56
namespace Android.Runtime
67
{
7-
// The existence of InternalRuntimeTypeHolder and DotNetRuntimeTypeConverter classes looks weird, but
8-
// we must handle a weird situation. AndroidRuntimeInternal needs to know in its static constructor
9-
// what is the current runtime type, but it cannot query JNIEnvInit.RuntimeType, since that type lives
10-
// in the Mono.Android assembly, while AndroidRuntimeInternal lives in Mono.Android.Runtime and it cannot
11-
// access JNIEnvInit and Mono.Android.Runtime doesn't reference Mono.Android but Mono.Android **does** reference
12-
// Mono.Android.Runtime and has access to its internals.
13-
//
14-
// Mono.Android.Runtime, also, includes several source files from Mono.Android - **both** assemblies
15-
// include the same source files. In case of the DotNetRuntimeType enum, this declares two distinct types - one
16-
// in Mono.Android and another in Mono.Android.Runtime, and so if JNIEnvInit.Initialize were to try to set the
17-
// `DotNetRuntimeType RuntimeType;` field/property in either of the classes below, we'd get a compilation error
18-
// to the effect of it being unable to cast `Android.Runtime.DotNetRuntimeType` to `Android.Runtime.DotNetRuntimeType`,
19-
// which is usually as clear as mud :)
20-
//
21-
// To solve this and not duplicate code, the InternalRuntimeTypeHolder class is introduced which acts as a proxy since
22-
// the AndroidRuntimeInternal static constructor must know the runtime type and JNIEnvInit.Initialize takes care of it by
23-
// calling `SetRuntimeType` below long before AndroidRuntimeInternal cctor is invoked.
24-
public static class InternalRuntimeTypeHolder
25-
{
26-
internal static DotNetRuntimeType RuntimeType = DotNetRuntimeType.Unknown;
27-
28-
internal static void SetRuntimeType (uint runtimeType)
29-
{
30-
RuntimeType = DotNetRuntimeTypeConverter.Convert (runtimeType);
31-
}
32-
}
33-
348
public static class AndroidRuntimeInternal
359
{
3610
internal static readonly Action<Exception> mono_unhandled_exception;
@@ -41,11 +15,13 @@ public static class AndroidRuntimeInternal
4115

4216
static AndroidRuntimeInternal ()
4317
{
44-
mono_unhandled_exception = InternalRuntimeTypeHolder.RuntimeType switch {
45-
DotNetRuntimeType.MonoVM => MonoUnhandledException,
46-
DotNetRuntimeType.CoreCLR => CoreClrUnhandledException,
47-
_ => throw new NotSupportedException ($"Internal error: runtime type {InternalRuntimeTypeHolder.RuntimeType} not supported")
48-
};
18+
if (RuntimeFeature.IsMonoRuntime) {
19+
mono_unhandled_exception = MonoUnhandledException;
20+
} else if (RuntimeFeature.IsCoreClrRuntime) {
21+
mono_unhandled_exception = CoreClrUnhandledException;
22+
} else {
23+
throw new NotSupportedException ("Internal error: unknown runtime not supported");
24+
}
4925
}
5026

5127
static void CoreClrUnhandledException (Exception ex)

src/Mono.Android/Android.Runtime/DotNetRuntimeType.cs

Lines changed: 0 additions & 32 deletions
This file was deleted.

src/Mono.Android/Android.Runtime/JNIEnv.cs

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Diagnostics;
4+
using System.Diagnostics.CodeAnalysis;
45
using System.Globalization;
56
using System.IO;
67
using System.Reflection;
@@ -12,7 +13,7 @@
1213

1314
using Java.Interop;
1415
using Java.Interop.Tools.TypeNameMappings;
15-
using System.Diagnostics.CodeAnalysis;
16+
using Microsoft.Android.Runtime;
1617

1718
namespace Android.Runtime {
1819
public static partial class JNIEnv {
@@ -100,16 +101,12 @@ internal static void PropagateUncaughtException (IntPtr env, IntPtr javaThreadPt
100101
Logger.Log (LogLevel.Info, "MonoDroid", "UNHANDLED EXCEPTION:");
101102
Logger.Log (LogLevel.Info, "MonoDroid", javaException.ToString ());
102103

103-
switch (JNIEnvInit.RuntimeType) {
104-
case DotNetRuntimeType.MonoVM:
105-
MonoDroidUnhandledException (innerException ?? javaException);
106-
break;
107-
case DotNetRuntimeType.CoreCLR:
108-
// TODO: what to do here?
109-
break;
110-
111-
default:
112-
throw new NotSupportedException ($"Internal error: runtime type {JNIEnvInit.RuntimeType} not supported");
104+
if (RuntimeFeature.IsMonoRuntime) {
105+
MonoDroidUnhandledException (innerException ?? javaException);
106+
} else if (RuntimeFeature.IsCoreClrRuntime) {
107+
// TODO: what to do here?
108+
} else {
109+
throw new NotSupportedException ("Internal error: unknown runtime not supported");
113110
}
114111
} catch (Exception e) {
115112
Logger.Log (LogLevel.Error, "monodroid", "Exception thrown while raising AppDomain.UnhandledException event: " + e.ToString ());
@@ -453,11 +450,13 @@ static unsafe IntPtr monovm_typemap_managed_to_java (Type type, byte* mvidptr)
453450

454451
IntPtr ret;
455452
fixed (byte* mvidptr = mvid_data) {
456-
ret = JNIEnvInit.RuntimeType switch {
457-
DotNetRuntimeType.MonoVM => monovm_typemap_managed_to_java (type, mvidptr),
458-
DotNetRuntimeType.CoreCLR => RuntimeNativeMethods.clr_typemap_managed_to_java (type.FullName, (IntPtr)mvidptr),
459-
_ => throw new NotSupportedException ($"Internal error: runtime type {JNIEnvInit.RuntimeType} not supported")
460-
};
453+
if (RuntimeFeature.IsMonoRuntime) {
454+
ret = monovm_typemap_managed_to_java (type, mvidptr);
455+
} else if (RuntimeFeature.IsCoreClrRuntime) {
456+
ret = RuntimeNativeMethods.clr_typemap_managed_to_java (type.FullName, (IntPtr)mvidptr);
457+
} else {
458+
throw new NotSupportedException ("Internal error: unknown runtime not supported");
459+
}
461460
}
462461

463462
if (ret == IntPtr.Zero) {

src/Mono.Android/Android.Runtime/JNIEnvInit.cs

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ internal struct JnienvInitializeArgs {
3434
public bool jniRemappingInUse;
3535
public bool marshalMethodsEnabled;
3636
public IntPtr grefGCUserPeerable;
37-
public uint runtimeType;
3837
public bool managedMarshalMethodsLookupEnabled;
3938
}
4039
#pragma warning restore 0649
@@ -50,8 +49,6 @@ internal struct JnienvInitializeArgs {
5049

5150
internal static JniRuntime? androidRuntime;
5251

53-
public static DotNetRuntimeType RuntimeType { get; private set; } = DotNetRuntimeType.Unknown;
54-
5552
[UnmanagedCallersOnly]
5653
static unsafe void RegisterJniNatives (IntPtr typeName_ptr, int typeName_len, IntPtr jniClass, IntPtr methods_ptr, int methods_len)
5754
{
@@ -91,9 +88,10 @@ internal static void InitializeJniRuntime (JniRuntime runtime)
9188
[UnmanagedCallersOnly]
9289
internal static unsafe void Initialize (JnienvInitializeArgs* args)
9390
{
94-
// This looks weird, see comments in RuntimeTypeInternal.cs
95-
RuntimeType = DotNetRuntimeTypeConverter.Convert (args->runtimeType);
96-
InternalRuntimeTypeHolder.SetRuntimeType (args->runtimeType);
91+
// Should not be allowed
92+
if (RuntimeFeature.IsMonoRuntime && RuntimeFeature.IsCoreClrRuntime) {
93+
throw new NotSupportedException ("Internal error: both RuntimeFeature.IsMonoRuntime and RuntimeFeature.IsCoreClrRuntime are enabled");
94+
}
9795

9896
IntPtr total_timing_sequence = IntPtr.Zero;
9997
IntPtr partial_timing_sequence = IntPtr.Zero;
@@ -114,12 +112,13 @@ internal static unsafe void Initialize (JnienvInitializeArgs* args)
114112
} else {
115113
typeManager = new AndroidTypeManager (args->jniAddNativeMethodRegistrationAttributePresent != 0);
116114
}
117-
valueManager = RuntimeType switch
118-
{
119-
DotNetRuntimeType.MonoVM => new AndroidValueManager(),
120-
DotNetRuntimeType.CoreCLR => ManagedValueManager.GetOrCreateInstance(),
121-
_ => throw new NotSupportedException ($"No value manager for runtime type: {RuntimeType}"),
122-
};
115+
if (RuntimeFeature.IsMonoRuntime) {
116+
valueManager = new AndroidValueManager ();
117+
} else if (RuntimeFeature.IsCoreClrRuntime) {
118+
valueManager = ManagedValueManager.GetOrCreateInstance ();
119+
} else {
120+
throw new NotSupportedException ("Internal error: unknown runtime not supported");
121+
}
123122
androidRuntime = new AndroidRuntime (
124123
args->env,
125124
args->javaVm,

src/Mono.Android/Java.Interop/TypeManager.cs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using Java.Interop.Tools.TypeNameMappings;
99

1010
using Android.Runtime;
11+
using Microsoft.Android.Runtime;
1112

1213
namespace Java.Interop {
1314

@@ -267,11 +268,13 @@ static Type monovm_typemap_java_to_managed (string java_type_name)
267268
return type;
268269
}
269270

270-
type = JNIEnvInit.RuntimeType switch {
271-
DotNetRuntimeType.MonoVM => monovm_typemap_java_to_managed (class_name),
272-
DotNetRuntimeType.CoreCLR => clr_typemap_java_to_managed (class_name),
273-
_ => throw new NotSupportedException ($"Internal error: runtime type {JNIEnvInit.RuntimeType} not supported")
274-
};
271+
if (RuntimeFeature.IsMonoRuntime) {
272+
type = monovm_typemap_java_to_managed (class_name);
273+
} else if (RuntimeFeature.IsCoreClrRuntime) {
274+
type = clr_typemap_java_to_managed (class_name);
275+
} else {
276+
throw new NotSupportedException ("Internal error: unknown runtime not supported");
277+
}
275278

276279
if (type != null) {
277280
TypeManagerMapDictionaries.JniToManaged.Add (class_name, type);

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

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,21 @@ namespace Microsoft.Android.Runtime;
55

66
static class RuntimeFeature
77
{
8+
const bool ManagedTypeMapEnabledByDefault = false;
9+
const bool IsMonoRuntimeEnabledByDefault = true;
10+
const bool IsCoreClrRuntimeEnabledByDefault = false;
11+
812
const string FeatureSwitchPrefix = "Microsoft.Android.Runtime.RuntimeFeature.";
913

1014
[FeatureSwitchDefinition ($"{FeatureSwitchPrefix}{nameof (ManagedTypeMap)}")]
1115
internal static bool ManagedTypeMap { get; } =
12-
AppContext.TryGetSwitch ($"{FeatureSwitchPrefix}{nameof (ManagedTypeMap)}", out bool isEnabled) ? isEnabled : false;
16+
AppContext.TryGetSwitch ($"{FeatureSwitchPrefix}{nameof (ManagedTypeMap)}", out bool isEnabled) ? isEnabled : ManagedTypeMapEnabledByDefault;
17+
18+
[FeatureSwitchDefinition ($"{FeatureSwitchPrefix}{nameof (IsMonoRuntime)}")]
19+
internal static bool IsMonoRuntime { get; } =
20+
AppContext.TryGetSwitch ($"{FeatureSwitchPrefix}{nameof (IsMonoRuntime)}", out bool isEnabled) ? isEnabled : IsMonoRuntimeEnabledByDefault;
21+
22+
[FeatureSwitchDefinition ($"{FeatureSwitchPrefix}{nameof (IsCoreClrRuntime)}")]
23+
internal static bool IsCoreClrRuntime { get; } =
24+
AppContext.TryGetSwitch ($"{FeatureSwitchPrefix}{nameof (IsCoreClrRuntime)}", out bool isEnabled) ? isEnabled : IsCoreClrRuntimeEnabledByDefault;
1325
}

src/Mono.Android/Mono.Android.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,6 @@
220220
<Compile Include="Android.Runtime\BoundExceptionType.cs" />
221221
<Compile Include="Android.Runtime\CharSequence.cs" />
222222
<Compile Include="Android.Runtime\CPUArchitecture.cs" />
223-
<Compile Include="Android.Runtime\DotNetRuntimeType.cs" />
224223
<Compile Include="Android.Runtime\Extensions.cs" />
225224
<Compile Include="Android.Runtime\GeneratedEnumAttribute.cs" />
226225
<Compile Include="Android.Runtime\IJavaObject.cs" />

src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.CoreCLR.targets

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,18 @@ This file contains the CoreCLR-specific MSBuild logic for .NET for Android.
2020
<AllowReadyToRunWithoutRuntimeIdentifier Condition=" '$(PublishReadyToRun)' == 'true' and '$(RuntimeIdentifiers)' != '' ">true</AllowReadyToRunWithoutRuntimeIdentifier>
2121
</PropertyGroup>
2222

23+
<!-- Default feature switches -->
24+
<ItemGroup>
25+
<RuntimeHostConfigurationOption Include="Microsoft.Android.Runtime.RuntimeFeature.IsMonoRuntime"
26+
Value="false"
27+
Trim="true"
28+
/>
29+
<RuntimeHostConfigurationOption Include="Microsoft.Android.Runtime.RuntimeFeature.IsCoreClrRuntime"
30+
Value="true"
31+
Trim="true"
32+
/>
33+
</ItemGroup>
34+
2335
<Target Name="_CLRUseLocalRuntimePacks" AfterTargets="ResolveFrameworkReferences"
2436
Condition=" '$(_CLRLocalRuntimePath)' != '' And '$(_AndroidRuntime)' == 'CoreCLR' ">
2537
<PropertyGroup>
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<!--
2+
***********************************************************************************************
3+
Microsoft.Android.Sdk.MonoVM.targets
4+
5+
This file contains the MonoVM-specific MSBuild logic for .NET for Android.
6+
***********************************************************************************************
7+
-->
8+
<Project>
9+
10+
<!-- Default feature switches -->
11+
<ItemGroup>
12+
<RuntimeHostConfigurationOption Include="Microsoft.Android.Runtime.RuntimeFeature.IsMonoRuntime"
13+
Value="true"
14+
Trim="true"
15+
/>
16+
<RuntimeHostConfigurationOption Include="Microsoft.Android.Runtime.RuntimeFeature.IsCoreClrRuntime"
17+
Value="false"
18+
Trim="true"
19+
/>
20+
</ItemGroup>
21+
22+
</Project>

0 commit comments

Comments
 (0)