Call WasmEdge functions from an NDK native app

In this section, we will demonstrate how to build an Android native application using C and the Android SDK. The native application uses the WasmEdge C SDK to embed the WasmEdge Runtime, and call WASM functions through WasmEdge.

Prerequisite

Android

Currently, WasmEdge only supports the arm64-v8a architecture on Android devices. You need an arm64-v8a Android simulator or a physical device with developer options turned on. WasmEdge requires Android 6.0 and above.

Android development CLI

In Ubuntu Linux, you can use the apt-get command to install Android debugging and testing tool adb. Using the adb shell command on the Ubuntu dev machine, you can open a CLI shell to execute commands on the connected Android device.

sudo apt-get install adb

Android NDK

To compile programs with the wasmedge-tensorflow c api, you need to install the Android NDK. In this example, we use the latest LTS version (r23b).

Review of source code

The test.c uses the wasmedge-tensorflow c api to run a WebAssembly function. The WebAssembly file birds_v1.wasm is compiled from Rust source code and explained here.

#include <wasmedge/wasmedge.h>
#include <wasmedge/wasmedge-image.h>
#include <wasmedge/wasmedge-tensorflowlite.h>

#include <stdio.h>

int main(int argc, char *argv[]) {
  /*
   * argv[0]: ./a.out
   * argv[1]: WASM file
   * argv[2]: tflite model file
   * argv[3]: image file
   * Usage: ./a.out birds_v1.wasm lite-model_aiy_vision_classifier_birds_V1_3.tflite bird.jpg
   */

  /* Create the VM context. */
  WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate();
  WasmEdge_ConfigureAddHostRegistration(ConfCxt, WasmEdge_HostRegistration_Wasi);
  WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(ConfCxt, NULL);
  WasmEdge_ConfigureDelete(ConfCxt);
  
  /* Create the image and TFLite import objects. */
  WasmEdge_ImportObjectContext *ImageImpObj = WasmEdge_Image_ImportObjectCreate();
  WasmEdge_ImportObjectContext *TFLiteImpObj = WasmEdge_TensorflowLite_ImportObjectCreate();
  WasmEdge_ImportObjectContext *TFDummyImpObj = WasmEdge_Tensorflow_ImportObjectCreateDummy();

  /* Register into VM. */
  WasmEdge_VMRegisterModuleFromImport(VMCxt, ImageImpObj);
  WasmEdge_VMRegisterModuleFromImport(VMCxt, TFLiteImpObj);
  WasmEdge_VMRegisterModuleFromImport(VMCxt, TFDummyImpObj);

  /* Init WASI. */
  const char *Preopens[] = {".:."};
  const char *Args[] = {argv[1], argv[2], argv[3]};
  WasmEdge_ImportObjectContext *WASIImpObj = WasmEdge_VMGetImportModuleContext(VMCxt, WasmEdge_HostRegistration_Wasi);
  WasmEdge_ImportObjectInitWASI(WASIImpObj, Args, 3, NULL, 0, Preopens, 1);

  /* Run WASM file. */
  WasmEdge_String FuncName = WasmEdge_StringCreateByCString("_start");
  WasmEdge_Result Res = WasmEdge_VMRunWasmFromFile(VMCxt, argv[1], FuncName, NULL, 0, NULL, 0);
  WasmEdge_StringDelete(FuncName);

  /* Check the result. */
  if (!WasmEdge_ResultOK(Res)) {
    printf("Run WASM failed: %s\n", WasmEdge_ResultGetMessage(Res));
    return -1;
  }

  WasmEdge_ImportObjectDelete(ImageImpObj);
  WasmEdge_ImportObjectDelete(TFLiteImpObj);
  WasmEdge_ImportObjectDelete(TFDummyImpObj);
  WasmEdge_VMDelete(VMCxt);
  return 0;
}

Build

Install dependencies

Use the following commands to download WasmEdge for Android on your Ubuntu dev machine.

wget https://github.com/WasmEdge/WasmEdge/releases/download/0.10.0-alpha.1/WasmEdge-0.10.0-alpha.1-android_aarch64.tar.gz
wget https://github.com/second-state/WasmEdge-image/releases/download/0.10.0-alpha.1/WasmEdge-image-0.10.0-alpha.1-android_aarch64.tar.gz
wget https://github.com/second-state/WasmEdge-tensorflow/releases/download/0.10.0-alpha.1/WasmEdge-tensorflowlite-0.10.0-alpha.1-android_aarch64.tar.gz
wget https://github.com/second-state/WasmEdge-tensorflow-deps/releases/download/0.10.0-alpha.1/WasmEdge-tensorflow-deps-TFLite-0.10.0-alpha.1-android_aarch64.tar.gz
tar -zxf WasmEdge-0.10.0-alpha.1-android_aarch64.tar.gz
tar -zxf WasmEdge-image-0.10.0-alpha.1-android_aarch64.tar.gz -C WasmEdge-0.10.0-alpha.1-Android/
tar -zxf WasmEdge-tensorflowlite-0.10.0-alpha.1-android_aarch64.tar.gz -C WasmEdge-0.10.0-alpha.1-Android/
tar -zxf WasmEdge-tensorflow-deps-TFLite-0.10.0-alpha.1-android_aarch64.tar.gz -C WasmEdge-0.10.0-alpha.1-Android/lib/

Compile

The following command compiles the C program to a.out on your Ubunu dev machine.

(/path/to/ndk)/toolchains/llvm/prebuilt/(HostPlatform)/bin/aarch64-linux-(AndroidApiVersion)-clang test.c -I./WasmEdge-0.10.0-alpha.1-Android/include -L./WasmEdge-0.10.0-alpha.1-Android/lib -lwasmedge-image_c -lwasmedge-tensorflowlite_c -ltensorflowlite_c -lwasmedge_c

Run

Push files onto Android

Install the compiled program, Tensorflow Lite model file, test image file, as well as WasmEdge shared library files for Android, onto the Android device using adb from your Ubuntu dev machine.

adb push a.out /data/local/tmp
adb push birds_v1.wasm /data/local/tmp
adb push lite-model_aiy_vision_classifier_birds_V1_3.tflite /data/local/tmp
adb push bird.jpg /data/local/tmp
adb push ./WasmEdge-0.10.0-alpha.1-Android/lib /data/local/tmp

Run the example

Now you can run the compiled C program on the Android device via a remote shell command. Run adb shell from your Ubuntu dev machine.

$ adb shell
sirius:/ $ cd /data/local/tmp
sirius:/data/local/tmp $ export LD_LIBRARY_PATH=/data/local/tmp/lib:$LD_LIBRARY_PATH
sirius:/data/local/tmp $ ./a.out birds_v1.wasm lite-model_aiy_vision_classifier_birds_V1_3.tflite bird.jpg
INFO: Initialized TensorFlow Lite runtime.
166 : 0.84705883