Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use runtimconfig.template.json file for Android functional test for JIT #50612

Merged
merged 8 commits into from
Apr 6, 2021
14 changes: 14 additions & 0 deletions eng/testing/tests.mobile.targets
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@
<UsingTask Condition="'$(TargetOS)' == 'Android'"
TaskName="AndroidAppBuilderTask"
AssemblyFile="$(AndroidAppBuilderTasksAssemblyPath)" />
<UsingTask Condition="'$(TargetOS)' == 'Android'"
TaskName="RuntimeConfigParserTask"
AssemblyFile="$(RuntimeConfigParserTasksAssemblyPath)" />

<Target Condition="'$(TargetOS)' == 'Android'" Name="BundleTestAndroidApp">
<Error Condition="!Exists('$(MicrosoftNetCoreAppRuntimePackRidDir)')" Text="MicrosoftNetCoreAppRuntimePackRidDir=$(MicrosoftNetCoreAppRuntimePackRidDir) doesn't exist" />
Expand All @@ -82,12 +85,16 @@
<AndroidAbi Condition="'$(TargetArchitecture)' == 'x86'">x86</AndroidAbi>

<MainLibraryFileName Condition="'$(MainLibraryFileName)' == ''">AndroidTestRunner.dll</MainLibraryFileName>
<RuntimeConfigFilePath>$(PublishDir)$(AssemblyName).runtimeconfig.json</RuntimeConfigFilePath>
<ParsedRuntimeConfigFilePath>$(PublishDir)runtimeconfig.bin</ParsedRuntimeConfigFilePath>
</PropertyGroup>
<ItemGroup Condition="'$(RunAOTCompilation)' == 'true'">
<AotInputAssemblies Include="$(PublishDir)\*.dll">
<AotArguments>@(MonoAOTCompilerDefaultAotArguments, ';')</AotArguments>
<ProcessArguments>@(MonoAOTCompilerDefaultProcessArguments, ';')</ProcessArguments>
</AotInputAssemblies>
<RuntimeConfigReservedProperties Include="RUNTIME_IDENTIFIER"/>
<RuntimeConfigReservedProperties Include="APP_CONTEXT_BASE_DIRECTORY"/>
</ItemGroup>

<WriteLinesToFile File="$(PublishDir)xunit-excludes.txt" Lines="$(XunitExcludesTxtFileContent)" Overwrite="true" />
Expand All @@ -96,6 +103,13 @@
Condition="'$(RunAOTCompilation)' == 'true'"/>
<RemoveDir Directories="$(BundleDir)" />

<!-- Parse runtimeconfig.template.json file -->
<RuntimeConfigParserTask
RuntimeConfigFile="$(RuntimeConfigFilePath)"
OutputFile="$(ParsedRuntimeConfigFilePath)"
RuntimeConfigReservedProperties="@(RuntimeConfigReservedProperties)">
</RuntimeConfigParserTask>

<MonoAOTCompiler Condition="'$(RunAOTCompilation)' == 'true'"
CompilerBinaryPath="$(MicrosoftNetCoreAppRuntimePackNativeDir)cross\$(PackageRID)\mono-aot-cross"
OutputDir="$(_MobileIntermediateOutputPath)"
Expand Down
25 changes: 25 additions & 0 deletions src/tasks/AndroidAppBuilder/Templates/monodroid.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ static char *executable;
#error Unknown architecture
#endif

#define RUNTIMECONFIG_BIN_FILE "runtimeconfig.bin"

static MonoAssembly*
mono_droid_load_assembly (const char *name, const char *culture)
{
Expand Down Expand Up @@ -193,6 +195,13 @@ log_callback (const char *log_domain, const char *log_level, const char *message
void register_aot_modules (void);
#endif

void
cleanup_runtime_config (MonovmRuntimeConfigArguments *args, void *user_data)
{
free (args);
free (user_data);
}

int
mono_droid_runtime_init (const char* executable, int managed_argc, char* managed_argv[])
{
Expand All @@ -216,6 +225,22 @@ mono_droid_runtime_init (const char* executable, int managed_argc, char* managed
appctx_values[0] = ANDROID_RUNTIME_IDENTIFIER;
appctx_values[1] = bundle_path;

char* file_name = RUNTIMECONFIG_BIN_FILE;
fanyang-mono marked this conversation as resolved.
Show resolved Hide resolved
int str_len = strlen (bundle_path) + strlen (file_name) + 1;
char* file_path = (char *) malloc (sizeof (char) * (str_len + 1));
fanyang-mono marked this conversation as resolved.
Show resolved Hide resolved
int res1 = snprintf (file_path, str_len, "%s/%s", bundle_path, file_name);
fanyang-mono marked this conversation as resolved.
Show resolved Hide resolved
struct stat buffer;

LOG_INFO ("file_path: %s\n", file_path);
assert (res1 > 0);

if (stat (file_path, &buffer) == 0) {
MonovmRuntimeConfigArguments *arg = (MonovmRuntimeConfigArguments *) malloc (sizeof (MonovmRuntimeConfigArguments));
fanyang-mono marked this conversation as resolved.
Show resolved Hide resolved
arg->kind = 0;
arg->runtimeconfig.name.path = file_path;
fanyang-mono marked this conversation as resolved.
Show resolved Hide resolved
monovm_runtimeconfig_initialize (arg, cleanup_runtime_config, file_path);
}

monovm_initialize(2, appctx_keys, appctx_values);

mono_debug_init (MONO_DEBUG_FORMAT_MONO);
Expand Down
68 changes: 62 additions & 6 deletions src/tasks/RuntimeConfigParser/RuntimeConfigParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public class RuntimeConfigParserTask : Task
/// <summary>
/// List of properties reserved for the host.
/// </summary>
public ITaskItem[] ReservedProperties { get; set; } = Array.Empty<ITaskItem>();
public ITaskItem[] RuntimeConfigReservedProperties { get; set; } = Array.Empty<ITaskItem>();

public override bool Execute()
{
Expand All @@ -43,14 +43,15 @@ public override bool Execute()

Dictionary<string, string> configProperties = ConvertInputToDictionary(RuntimeConfigFile);

if (ReservedProperties.Length != 0)
if (RuntimeConfigReservedProperties.Length != 0)
{
CheckDuplicateProperties(configProperties, ReservedProperties);
CheckDuplicateProperties(configProperties, RuntimeConfigReservedProperties);
}

var blobBuilder = new BlobBuilder();
ConvertDictionaryToBlob(configProperties, blobBuilder);

Directory.CreateDirectory(Path.GetDirectoryName(OutputFile!)!);
using var stream = File.OpenWrite(OutputFile);
blobBuilder.WriteContentTo(stream);

Expand All @@ -63,6 +64,10 @@ private Dictionary<string, string> ConvertInputToDictionary(string inputFilePath
var options = new JsonSerializerOptions {
AllowTrailingCommas = true,
ReadCommentHandling = JsonCommentHandling.Skip,
Converters =
{
new StringConverter()
}
};

var jsonString = File.ReadAllText(inputFilePath);
Expand All @@ -72,8 +77,16 @@ private Dictionary<string, string> ConvertInputToDictionary(string inputFilePath
{
throw new ArgumentException("Wasn't able to parse the json file successfully.");
}
if (parsedJson.RuntimeOptions == null)
{
throw new ArgumentException("Key runtimeOptions wasn't found in the json file.");
}
if (parsedJson.RuntimeOptions.ConfigProperties == null)
{
throw new ArgumentException("Key runtimeOptions->configProperties wasn't found in the json file.");
}

return parsedJson.ConfigProperties;
return parsedJson.RuntimeOptions.ConfigProperties;
}

/// Just write the dictionary out to a blob as a count followed by
Expand Down Expand Up @@ -102,12 +115,55 @@ private void CheckDuplicateProperties(IReadOnlyDictionary<string, string> proper
}
}

public class Root
public class RuntimeOption
{
// the configProperties key
[JsonPropertyName("configProperties")]
public Dictionary<string, string> ConfigProperties { get; set; } = new Dictionary<string, string>();
// everything other than configProperties
[JsonExtensionData]
public Dictionary<string, object> ExtensionData { get; set; } = new Dictionary<string, object>();
public Dictionary<string, object> ExtensionDataSub { get; set; } = new Dictionary<string, object>();
}

public class Root
{
// the runtimeOptions key
[JsonPropertyName("runtimeOptions")]
public RuntimeOption RuntimeOptions { get; set; } = new RuntimeOption();
// everything other than runtimeOptions
[JsonExtensionData]
public Dictionary<string, object> ExtensionDataRoot { get; set; } = new Dictionary<string, object>();
}

public class StringConverter : JsonConverter<string>
{
public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
switch (reader.TokenType)
{
case JsonTokenType.Number:
var stringValueInt = reader.GetInt32();
return stringValueInt.ToString();
case JsonTokenType.True:
return "true";
case JsonTokenType.False:
return "false";
case JsonTokenType.String:
var stringValue = reader.GetString();
if (stringValue != null)
{
return stringValue;
}
break;
default:
throw new System.Text.Json.JsonException();
}

throw new System.Text.Json.JsonException();
}

public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
{
writer.WriteStringValue(value);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ public class Program
public static int Main(string[] args)
{
Console.WriteLine("Hello, Android!"); // logcat
return 42;
int result = ((string)AppContext.GetData("test_runtimeconfig_json")).Equals("25") ? 42 : 1;
fanyang-mono marked this conversation as resolved.
Show resolved Hide resolved
return result;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"configProperties": {
"abc": "4",
"test_runtimeconfig_json": "25"
}
}