WASM to Dalvik/Art Compiler for Android

4 months ago 6

The experimental Chicory Android compiler is currently available through the GitHub Package Registry.

In your settings.gradle.kts:

repositories { maven { url = uri("https://maven.pkg.github.com/dylibso/chicory-compiler-android") credentials { username = project.findProperty("gpr.user") as String? ?: System.getenv("USERNAME") password = project.findProperty("gpr.key") as String? ?: System.getenv("TOKEN") } } }

where USERNAME is your GitHub username, and TOKEN is a Classic Token. You can configure them in your gradle.properties or set the USERNAME and TOKEN environment variables.

Then add the dependency to your build.gradle.kts:

dependencies { implementation("com.dylibso.chicory:android-aot:0.0.1") }

Configure Maven. Create a settings.xml file alongside your pom.xml or just add to your ~/.m2/settings.xml:

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd"> <activeProfiles> <activeProfile>github</activeProfile> </activeProfiles> <profiles> <profile> <id>github</id> <repositories> <repository> <id>central</id> <url>https://repo.maven.apache.org/maven2</url> </repository> <repository> <id>github</id> <url>https://maven.pkg.github.com/dylibso/chicory-compiler-android</url> <snapshots> <enabled>true</enabled> </snapshots> </repository> </repositories> </profile> </profiles> <servers> <server> <id>github</id> <username>USERNAME</username> <password>TOKEN</password> </server> </servers> </settings>

where USERNAME is your GitHub username, and TOKEN is a Classic Token.

Now you can depend on the package in your pom.xml:

<dependencies> <dependency> <groupId>com.dylibso.chicory</groupId> <artifactId>android-aot</artifactId> <version>0.0.1</version> </dependency> </dependencies>

If you are using a local settings.xml, just run mvn -s settings.xml <command>.

Using the Android Chicory Compiler

Once you have the com.dylibso.chicory:android-aot dependency in your classpath, you only need to plug the MachineFactory.

import com.dylibso.chicory.compiler.MachineFactoryCompiler; import com.dylibso.chicory.wasm.Parser; import com.dylibso.chicory.wasm.WasmModule; import com.dylibso.chicory.experimental.android.aot.AotAndroidMachine; var module = Parser.parse(new File("your.wasm")); var instance = Instance.builder(module). withMachineFactory(AotAndroidMachine::new). build();

Because of the memory and stack limitations on the main Android thread, we strongly advise to initialize and invoke the instance on its own thread, with a generous amount of stack memory:

Runnable r = () -> instance.call(...); Thread t = new Thread( new ThreadGroup("chicory"), r, "chicory-thread", 8 * 1024 * 1024) )

Using the Android Chicory Compiler with Extism

The Extism Chicory SDK supports the Android compiler extension since version 0.2.0. In this case, you will write:

var path = Path.of("https://github.com/extism/plugins/releases/download/v1.1.1/count_vowels.wasm"); var wasm = ManifestWasm.fromFilePath(path).build(); var manifest = Manifest.ofWasms(wasm) .withOptions(new Manifest.Options() .withMachineFactory(AotAndroidMachine::new)).build(); var plugin = Plugin.ofManifest(manifest).build();

Because of the memory and stack limitations on the main Android thread, we strongly advise to initialize and invoke the plugin on its own thread, with a generous amount of stack memory:

Runnable r = () -> plugin.call(...); Thread t = new Thread( new ThreadGroup("chicory"), r, "chicory-thread", 8 * 1024 * 1024) )

Using the Android Chicory Compiler with mcpx4j

The mcpx4j library to run mcp.run tools on-device, is built on Extism and it also supports the Android AOT compiler. In this case, you will write something like:

val mcpx = // Configure the MCP.RUN Session Mcpx.forApiKey(BuildConfig.mcpRunKey) .withServletOptions( McpxServletOptions.builder() .withMachineFactory{ AotAndroidMachine(it) } // Setup an HTTP client compatible with Android // on the Chicory runtime .withChicoryHttpConfig(AndroidHttpConfig.get()) // Configure an alternative, Android-specific logger .withChicoryLogger(AndroidLogger("mcpx4j-runtime")) .build()) // Configure also the MCPX4J HTTP client to use // the Android-compatible implementation .withHttpClientAdapter(HttpUrlConnectionClientAdapter()) .withProfile(BuildConfig.profile) .build()

Because of the memory and stack limitations on the main Android thread, we strongly advise to initialize and invoke the plugin on its own thread, with a generous amount of stack memory; for instance:

val service = Executors.newSingleThreadExecutor { Thread(ThreadGroup("chicory"), it, "chicory-thread", 8 * 1024 * 1024) } val call: Callable<String> = Callable { tool.call(input) } val res: String = service.submit(call).get()
Read Entire Article