Skip to content

Commit c87888a

Browse files
[Android][CoreCLR] Add runtimeconfig.json support for test host (#117980)
* Add placeholders for setting AppContext keys and values * For CoreCLR, add runtimeconfig.json parsing and set AppContext keys and values by replacing the template placeholders * Setting the env variables is now redundant * Enable newly fixed tests * Enable the test * Add a null check instead of using the null-forgiving operator * Refactoring: rename method and variables and add comments * Rename variable
1 parent dc6ac3a commit c87888a

File tree

5 files changed

+73
-25
lines changed

5 files changed

+73
-25
lines changed

src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/DisabledFileLockingTests/DisabledFileLockingSwitchTests.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ namespace System.IO.Tests
99
public class DisabledFileLockingSwitchTests
1010
{
1111
[Fact]
12-
[ActiveIssue("https://github.com/dotnet/runtime/issues/114951", typeof(PlatformDetection), nameof(PlatformDetection.IsSingleFile))]
1312
public static void ConfigSwitchIsHonored()
1413
{
1514
Assert.Equal(OperatingSystem.IsWindows(), PlatformDetection.IsFileLockingEnabled);

src/libraries/tests.proj

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -228,9 +228,6 @@
228228
<!-- https://github.com/dotnet/runtime/issues/117045 -->
229229
<ProjectExclusions Include="$(MSBuildThisFileDirectory)System.Net.Http\tests\FunctionalTests\System.Net.Http.Functional.Tests.csproj" />
230230
<!-- https://github.com/dotnet/runtime/issues/114951 -->
231-
<ProjectExclusions Include="$(MSBuildThisFileDirectory)System.Diagnostics.DiagnosticSource\tests\TestWithConfigSwitches\System.Diagnostics.DiagnosticSource.Switches.Tests.csproj" />
232-
<ProjectExclusions Include="$(MSBuildThisFileDirectory)System.Runtime\tests\System.Runtime.Tests\InvariantTimezone\System.Runtime.InvariantTimezone.Tests.csproj" />
233-
<ProjectExclusions Include="$(MSBuildThisFileDirectory)System.Runtime\tests\System.Text.Encoding.Tests\System.Text.Encoding.Tests.csproj" />
234231
<!-- https://github.com/dotnet/runtime/issues/62547 -->
235232
<ProjectExclusions Include="$(MSBuildThisFileDirectory)System.Security.Cryptography\tests\System.Security.Cryptography.Tests.csproj" />
236233
<!-- https://github.com/dotnet/runtime/issues/72908 -->

src/mono/msbuild/android/build/AndroidBuild.props

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -40,16 +40,6 @@
4040
<_CommonTargetsDir Condition="'$(_CommonTargetsDir)' == ''">$([MSBuild]::NormalizeDirectory($(MSBuildThisFileDirectory), '..', '..', 'common'))</_CommonTargetsDir>
4141
</PropertyGroup>
4242

43-
<!-- This ItemGroup defines Android environment variables that are used for .NET feature switches. -->
44-
<ItemGroup>
45-
<AndroidEnv Condition="'$(InvariantGlobalization)' == 'true'" Include="DOTNET_SYSTEM_GLOBALIZATION_INVARIANT">
46-
<Value>true</Value>
47-
</AndroidEnv>
48-
<AndroidEnv Condition="'$(PredefinedCulturesOnly)' == 'false'" Include="DOTNET_SYSTEM_GLOBALIZATION_PREDEFINED_CULTURES_ONLY">
49-
<Value>false</Value>
50-
</AndroidEnv>
51-
</ItemGroup>
52-
5343
<Import Condition="'$(UseNativeAOTRuntime)' != 'true' and '$(UseMonoRuntime)' == 'true'" Project="$(_CommonTargetsDir)CommonMobileBuild.props" />
5444
<Import Condition="'$(UseNativeAOTRuntime)' != 'true' and '$(UseMonoRuntime)' == 'true'" Project="$(_CommonTargetsDir)RuntimeComponentManifest.targets" />
5545
<Import Condition="'$(UseNativeAOTRuntime)' != 'true' and ('$(UseMonoRuntime)' == 'true' and '$(RunAOTCompilation)' == 'true')" Project="$(_CommonTargetsDir)MonoAOTCompiler.props" />

src/tasks/AndroidAppBuilder/ApkBuilder.cs

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System.IO.Compression;
88
using System.Linq;
99
using System.Text;
10+
using System.Text.Json;
1011
using System.Text.RegularExpressions;
1112
using Microsoft.Android.Build;
1213
using Microsoft.Build.Framework;
@@ -381,7 +382,13 @@ public ApkBuilder(TaskLoggingHelper logger)
381382
cmakeLists = cmakeLists.Replace("%Defines%", defines.ToString());
382383

383384
File.WriteAllText(Path.Combine(OutputDir, "CMakeLists.txt"), cmakeLists);
384-
File.WriteAllText(Path.Combine(OutputDir, monodroidSource), Utils.GetEmbeddedResource(monodroidSource));
385+
386+
string monodroidContent = Utils.GetEmbeddedResource(monodroidSource);
387+
if (IsCoreCLR)
388+
{
389+
monodroidContent = RenderMonodroidCoreClrTemplate(monodroidContent);
390+
}
391+
File.WriteAllText(Path.Combine(OutputDir, monodroidSource), monodroidContent);
385392

386393
AndroidProject project = new AndroidProject("monodroid", runtimeIdentifier, AndroidNdk, logger);
387394
project.GenerateCMake(OutputDir, MinApiLevel, StripDebugSymbols);
@@ -639,4 +646,66 @@ private static string NormalizePathToUnix(string path)
639646

640647
[GeneratedRegex(@"\.(\d)")]
641648
private static partial Regex DotNumberRegex();
649+
650+
private string RenderMonodroidCoreClrTemplate(string monodroidContent)
651+
{
652+
// At the moment, we only set the AppContext properties, so it's all done here for simplicity.
653+
// If we need to add more rendering logic, we can refactor this method later.
654+
var appContextKeys = new StringBuilder();
655+
appContextKeys.AppendLine(" appctx_keys[0] = \"RUNTIME_IDENTIFIER\";");
656+
appContextKeys.AppendLine(" appctx_keys[1] = \"APP_CONTEXT_BASE_DIRECTORY\";");
657+
appContextKeys.AppendLine(" appctx_keys[2] = \"HOST_RUNTIME_CONTRACT\";");
658+
659+
var appContextValues = new StringBuilder();
660+
appContextValues.AppendLine(" appctx_values[0] = ANDROID_RUNTIME_IDENTIFIER;");
661+
appContextValues.AppendLine(" appctx_values[1] = g_bundle_path;");
662+
appContextValues.AppendLine();
663+
appContextValues.AppendLine(" char contract_str[19];"); // 0x + 16 hex digits + '\0'
664+
appContextValues.AppendLine(" snprintf(contract_str, 19, \"0x%zx\", (size_t)(&g_host_contract));");
665+
appContextValues.AppendLine(" appctx_values[2] = contract_str;");
666+
appContextValues.AppendLine();
667+
668+
// Parse runtime config properties and add them to the AppContext keys and values.
669+
Dictionary<string, string> configProperties = ParseRuntimeConfigProperties();
670+
int hardwiredAppContextProperties = 3; // For the hardwired AppContext keys and values above.
671+
int i = 0;
672+
foreach ((string key, string value) in configProperties)
673+
{
674+
appContextKeys.AppendLine($" appctx_keys[{i + hardwiredAppContextProperties}] = \"{key}\";");
675+
appContextValues.AppendLine($" appctx_values[{i + hardwiredAppContextProperties}] = \"{value}\";");
676+
i++;
677+
}
678+
679+
// Replace the template placeholders.
680+
string updatedContent = monodroidContent.Replace("%AppContextPropertyCount%", (configProperties.Count + hardwiredAppContextProperties).ToString())
681+
.Replace("%AppContextKeys%", appContextKeys.ToString().TrimEnd())
682+
.Replace("%AppContextValues%", appContextValues.ToString().TrimEnd());
683+
return updatedContent;
684+
}
685+
686+
private Dictionary<string, string> ParseRuntimeConfigProperties()
687+
{
688+
var configProperties = new Dictionary<string, string>();
689+
string runtimeConfigPath = Path.Combine(AppDir ?? throw new InvalidOperationException("AppDir is not set"), $"{ProjectName}.runtimeconfig.json");
690+
691+
try
692+
{
693+
string jsonContent = File.ReadAllText(runtimeConfigPath);
694+
using JsonDocument doc = JsonDocument.Parse(jsonContent);
695+
JsonElement root = doc.RootElement;
696+
if (root.TryGetProperty("runtimeOptions", out JsonElement runtimeOptions) && runtimeOptions.TryGetProperty("configProperties", out JsonElement propertiesJson))
697+
{
698+
foreach (JsonProperty property in propertiesJson.EnumerateObject())
699+
{
700+
configProperties[property.Name] = property.Value.ToString();
701+
}
702+
}
703+
}
704+
catch (Exception ex)
705+
{
706+
logger.LogMessage(MessageImportance.High, $"Error while parsing runtime config at {runtimeConfigPath}: {ex.Message}");
707+
}
708+
709+
return configProperties;
710+
}
642711
}

src/tasks/AndroidAppBuilder/Templates/monodroid-coreclr.c

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ mono_droid_execute_assembly (const char* executable_path, void* coreclr_handle,
177177
return rv;
178178
}
179179

180-
#define PROPERTY_COUNT 3
180+
#define PROPERTY_COUNT %AppContextPropertyCount%
181181

182182
static int
183183
mono_droid_runtime_init (const char* executable)
@@ -202,17 +202,10 @@ mono_droid_runtime_init (const char* executable)
202202
g_host_contract.external_assembly_probe = &external_assembly_probe;
203203

204204
const char* appctx_keys[PROPERTY_COUNT];
205-
appctx_keys[0] = "RUNTIME_IDENTIFIER";
206-
appctx_keys[1] = "APP_CONTEXT_BASE_DIRECTORY";
207-
appctx_keys[2] = "HOST_RUNTIME_CONTRACT";
205+
%AppContextKeys%
208206

209207
const char* appctx_values[PROPERTY_COUNT];
210-
appctx_values[0] = ANDROID_RUNTIME_IDENTIFIER;
211-
appctx_values[1] = g_bundle_path;
212-
213-
char contract_str[19]; // 0x + 16 hex digits + '\0'
214-
snprintf(contract_str, 19, "0x%zx", (size_t)(&g_host_contract));
215-
appctx_values[2] = contract_str;
208+
%AppContextValues%
216209

217210
LOG_INFO ("Calling coreclr_initialize");
218211
int rv = coreclr_initialize (

0 commit comments

Comments
 (0)