The applications of today are getting more and more complex. The complexity is increased by different factors, such as a larger and naturally evolving codebase when adding new features, the need to support multiple platforms, and continually increasing quality requirements. Such applications often include a broad set of excess features that are unused or even unwanted by most users. Furthermore, excessive features unnecessarily increase the size, the startup time, and memory consumption of the application.
In contrast to non-adaptive applications, adaptive applications can alter their behavior based on their context to better fit the users’ needs. The context could involve device capabilities, device location, and the user’s actions. Hence, an adaptive application can only contain the required features in the present context, and then load new features when those are desired.
Dynamically loadable modules and a supporting development approach can enable developers to implement adaptive applications that are better matched to users’ actual needs and context
Responsive and, otherwise adaptive applications, have been more common in the context of the Web, but only a little effort has been made for dynamically loadable modular behavior in the context of native and IoT applications for instance. A year ago, we started experimenting with WebAssembly technology and investigating its feasibility for fostering adaptive application behavior outside the browser’s context. We explored the feasibility of modular WebAssembly applications running on actual devices, capable of retrieving modules on-demand during execution.
In this blog post, we present an experimental system for creating adaptive WebAssembly applications, which involve a mechanism allowing to link modules dynamically and retrieving them on-demand. The implemented dynamic linking mechanism and platform independence offered by the technology are a perfect match enabling to adapt to the execution context as well as the user’s behavior during execution. Our vision of a system for a WebAssembly-based adaptive application has been depicted in the figure below.
Figure 1. The development pipeline.
Enabling adapting with dynamic linking, metadata and repositories
In our approach, an adaptive application is composed of WebAssembly modules that implement different features. The application is able to incrementally retrieve feature modules from online repositories on-demand during execution.
The feature modules are connected by leveraging dynamic linking. A base module exports its memory and table which are used by subsequently loaded modules. Thus, a module can access other, already loaded module data and functionality. Each module is accompanied by a metadata file that describes its dependencies.
There can be several feature modules that implement a specific functionality for different execution contexts requiring adaptation. To achieve this, the environment describes itself through attributes. The correct module is selected by the repository based on required attributes defined in the metadata of a module. As a result, the application is able to adapt to its environment.
The core idea of the implementation
Figure below represents the core implementation and example of its execution. The execution begins by the user starting the WebAssembly application by providing a metadata file to a runtime which is running on a laptop. In the example, the laptop has an integrated camera. Upon starting the application, the module manager is invoked to retrieve the module A described by the metadata. The module A is returned to the initialization function where the binary is compiled using Wasmtime embedding API and instantiated with access to host functions.
Figure 2. Overview of the implementation.
After initializing module A, the user invokes an action in the application to activate the camera. Module A calls dlopen to load a module capable of leveraging camera capabilities. The host function dlopen invokes the module manager library which proceeds to retrieve the dependency. Differently than with the initial module’s metadata, subsequent module metadata files are not preinstalled on the machine. As a result, these need to be retrieved and analyzed before the module’s binary can be fetched.
The module manager proceeds to issue a request containing the environment attributes to retrieve the metadata from a repository specified in the initial metadata file. When the request is received, the repository selects an appropriate module. As shown in the figure, the selection process returns module B that contains functions for operating a laptop camera. Similarly to the host application initialization function, dlopen compiles the binary and instantiates it using global memory and global table and giving it access to the host functions.