Skip to content

Latest commit

 

History

History
142 lines (104 loc) · 7.15 KB

mobile-runtimeconfig-json.md

File metadata and controls

142 lines (104 loc) · 7.15 KB

Mobile runtimeconfig.json host configuration

Motivation

runtimeconfig.json is a file used by .NET 5+ applications to pass arbitrary configuration parameters via the application host to the .NET runtime. On mobile and WebAssembly, we would like to support passing configuration properties from the Mono embedder to the runtime.

To minimize the impact on the app startup time, the design constraints are as follows:

  1. Don’t parse JSON at runtime during application startup
  2. Don’t need to support shared framework configuration parameters
  3. Don't need to support the desktop host environment variables, startup hooks, or other configuration mechanisms that do not make sense on mobile.
  4. This is separate from the key/value set passed to monovm_initialize/coreclr_initialize (ie we will not pass the additional properties via monovm_initialize - just using this new mechanism). Things like the TPA list, additional probing paths, PINVOKE_OVERRIDE, etc will be addressed by an evolution of monovm_initialize - #48416

Design Overview

We break up runtimeconfig.json loading into two parts:

  1. A new MSBuild task called RuntimeConfigParser will run after the runtimeconfig.json is created by the dotnet build process. The task will convert the properties and their values into a binary blob format. The resulting runtimeconfig.bin file will be bundled with the application.
  2. The runtime will expose a new API entrypoint monovm_runtimeconfig_initialize that gets either a path to pass to mono_file_map_open or a pointer to the blob in memory. When called, the runtime will read the binary data and populate the managed AppContext with the properties.

We will only use the runtimeOptions→configProperties json key. Its content is a JSON dictionary with string keys and string/bool/numeric values. We convert the values to strings when we store them in the binary runtimeconfig.bin, which is the same way they are treated by the default host.

The runtime assumes that the properties passed via monovm_initialize and monovm_runtimeconfig_initialize will be different. To ensure this, the provided MSBuild task will be passed a list of property names that the embedder promises it will pass to monovm_initialize. The MSBuild task will check that runtimeconfig.json does not set any of those same properties. If there is a duplicate, error out.

All properties set in either the runtimeconfig.json or set via monovm_initialize will be propagated to the managed AppContext. Mono will also check for properties it supports in the runtime itself and make use of them as appropriate.

Design Details

Encoded file generation

The runtime pack will provide an MSBuild task called RuntimeConfigParserTask to generate the encoded file. The generator checks for duplicate property keys (by comparing the keys in the json file with an input list of properties that the embedder promises to pass to monovm_initialize).

Task Contract:

The task will take 3 input arguments:

  1. The path to the runtimeconfig.json file.
  2. The name of the destination file to be written in the encoded format.
  3. An item list (ITaskItem[]) that is the name of the properties that the embedder will set on monovm_initialize.

The task should:

  1. Parse the given input file and create a dictionary from the configProperties key.
  2. Compare the keys from the input file with the names given in the item list. If there are any duplicates, return an MSBuild Error.
  3. Generate the output file.

Example of the usage of the task:

<UsingTask TaskName="RuntimeConfigParserTask"
           AssemblyFile="$(RuntimeConfigParserTasksAssemblyPath)" />

<Target Name="BundleTestAndroidApp">
 <RuntimeConfigParserTask
     RuntimeConfigFile="$(Path_to_runtimeconfig.json_file)"
     OutputFile="$(Path_to_generated_binary_file)"
     RuntimeConfigReservedProperties="@(runtime_properties_reserved_by_host)">
 </RuntimeConfigParserTask>
</Target>

The encoded runtimeconfig format

The format is:

  1. There will be an (1- to 4-byte) ECMA-335 II.23.2 compressed unsigned integer count = N, indicating the number of key-value pairs.
  2. It will have 2xN ECMA-335 SerString UTF8 strings (that is, each string is preceded by its length stored in the compressed unsigned integer format): Each key followed by its value.

Sample input

{
    "runtimeOptions": {
        "configProperties": {
            "key1": "value1",
            "key2": "value2"
        }
    }
}

Sample output (as hexdump -C bytes)

00000000  02 04 6b 65 79 31 06 76  61 6c 75 65 31 04 6b 65  |..key1.value1.ke|
00000010  79 32 06 76 61 6c 75 65  32                       |y2.value2|
00000019

New embedding API entrypoint

We want at least 2 ways to pass data in: either ask the runtime to open the file, or give it a pointer to the data in memory. Also, we need some way to cleanup.

struct MonovmRuntimeConfigArguments {
  uint32_t kind; // 0 = Path of runtimeconfig.bin file, 1 = pointer to the blob data, >= 2 reserved
  union {
    struct {
      const char *path; // null terminated absolute path
    } name;
    struct {
      const char *data;
      uint32_t data_len;
    } data;
  } runtimeconfig;
};

typedef void (*MonovmRuntimeConfigArgumentsCleanup)(MonovmRuntimeConfigArguments *args, void* user_data);

MONO_API void
monovm_runtimeconfig_initialize (MonovmRuntimeConfigArguments *args, MonovmRuntimeConfigArgumentsCleanup cleanup_fn, void* user_data);

This declaration should live in the unstable header. monovm_runtimeconfig_initialize should be called before monovm_initialize.

Example of the usage of monovm_runtimeconfig_initialize

void
cleanup_runtime_config (MonovmRuntimeConfigArguments *args, void *user_data)
{
    free (args);
    free (user_data); // This may not be needed, depending on if there is anything needs to be freed.
}

int
mono_droid_runtime_init (const char* executable, int managed_argc, char* managed_argv[])
{
  
  ......

  MonovmRuntimeConfigArguments *arg = (MonovmRuntimeConfigArguments *)malloc (sizeof (MonovmRuntimeConfigArguments));
  arg->kind = 0;
  arg->runtimeconfig.name.path = "path_to_generated_binary_file";
  monovm_runtimeconfig_initialize (arg, cleanup_runtime_config, NULL);

  monovm_initialize(......);
  ......

}

Register and install runtime properties

monovm_runtimeconfig_initialize will register the type MonovmRuntimeConfigArguments variable with the runtime. If given the path of the runtimeconfig.bin file, the runtime will read the binary data from the file, otherwise, it will parse the binary data from memory. The properties will be combined with the ones registered by monovm_initialize and used to initialize System.AppContext.

Cleanup function

The MonovmRuntimeConfigArguments* will be stored in the runtime between monovm_runtimeconfig_initialize and mono_jit_init_version. The embedder should not dispose of the arguments after calling monovm_runtimeconfig_initialize. Instead the runtime will call the cleanup_fn that is passed to monovm_runtimeconfig_initialize at soon after it has initialized the managed property list in System.AppContext (which happens as part of mono_jit_init_version).