[android] Wrap IREE core libraries as an Android Native App (#3108)
This commit adds necessary scaffolding to create an Android
application that executes a single IREE module as a native activity.
Specifically, it adds a new shared libary, libiree_run_module_app.so,
which implements android_main to connect with Android system with
native app glue. A script is provided to package the shared libary,
VM module and its invocation information, and all other necessary
APK componets into an Android APK file.
Along the way, create subdirectory for utility targets in tools/.
This allows us to have a better source file organization. It also
allows other directories to depend on those utility targets.
diff --git a/iree/modules/check/BUILD b/iree/modules/check/BUILD
index ef7e64d..cfaedff 100644
--- a/iree/modules/check/BUILD
+++ b/iree/modules/check/BUILD
@@ -63,7 +63,7 @@
"//iree/base:tracing",
"//iree/modules/hal",
"//iree/testing:gtest",
- "//iree/tools:vm_util",
+ "//iree/tools/utils:vm_util",
"//iree/vm:bytecode_module",
] + PLATFORM_VULKAN_DEPS + IREE_DRIVER_MODULES,
)
diff --git a/iree/modules/check/CMakeLists.txt b/iree/modules/check/CMakeLists.txt
index 84a23d0..56dea0e 100644
--- a/iree/modules/check/CMakeLists.txt
+++ b/iree/modules/check/CMakeLists.txt
@@ -58,7 +58,7 @@
iree::base::tracing
iree::modules::hal
iree::testing::gtest
- iree::tools::vm_util
+ iree::tools::utils::vm_util
iree::vm::bytecode_module
${IREE_HAL_DRIVER_MODULES}
TESTONLY
diff --git a/iree/modules/check/iree-check-module-main.cc b/iree/modules/check/iree-check-module-main.cc
index f8b406d..842ee92 100644
--- a/iree/modules/check/iree-check-module-main.cc
+++ b/iree/modules/check/iree-check-module-main.cc
@@ -27,7 +27,7 @@
#include "iree/modules/hal/hal_module.h"
#include "iree/testing/gtest.h"
#include "iree/testing/status_matchers.h"
-#include "iree/tools/vm_util.h"
+#include "iree/tools/utils/vm_util.h"
#include "iree/vm/bytecode_module.h"
// On Windows stdin defaults to text mode and will get weird line ending
diff --git a/iree/tools/BUILD b/iree/tools/BUILD
index 9ccc7bf..3349695 100644
--- a/iree/tools/BUILD
+++ b/iree/tools/BUILD
@@ -38,7 +38,6 @@
testonly = True,
srcs = ["iree-benchmark-module-main.cc"],
deps = [
- ":vm_util",
"@com_google_absl//absl/flags:flag",
"@com_google_absl//absl/flags:parse",
"@com_google_absl//absl/flags:usage",
@@ -49,6 +48,7 @@
"//iree/base:status",
"//iree/base:tracing",
"//iree/modules/hal",
+ "//iree/tools/utils:vm_util",
"//iree/vm",
"//iree/vm:bytecode_module",
] + PLATFORM_VULKAN_DEPS + IREE_DRIVER_MODULES,
@@ -243,7 +243,6 @@
":init_mlir_passes_and_dialects",
":init_targets",
":init_xla_dialects",
- ":vm_util",
"@com_google_absl//absl/flags:flag",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/types:span",
@@ -257,6 +256,7 @@
"//iree/compiler/Dialect/VM/Transforms",
"//iree/hal:api",
"//iree/modules/hal",
+ "//iree/tools/utils:vm_util",
"//iree/vm",
"//iree/vm:bytecode_module",
"@llvm-project//llvm:Support",
@@ -274,7 +274,6 @@
name = "iree-run-module",
srcs = ["iree-run-module-main.cc"],
deps = [
- ":vm_util",
"@com_google_absl//absl/flags:flag",
"@com_google_absl//absl/strings",
"//iree/base:file_io",
@@ -282,6 +281,7 @@
"//iree/base:status",
"//iree/base:tracing",
"//iree/modules/hal",
+ "//iree/tools/utils:vm_util",
"//iree/vm",
"//iree/vm:bytecode_module",
] + PLATFORM_VULKAN_DEPS + IREE_DRIVER_MODULES,
@@ -337,38 +337,3 @@
data = ["@llvm-project//llvm:FileCheck"],
tags = ["hostonly"],
)
-
-# TODO(b/146898896): Refactor these into more coherent packages.
-cc_library(
- name = "vm_util",
- srcs = ["vm_util.cc"],
- hdrs = ["vm_util.h"],
- deps = [
- "//iree/base:file_io",
- "//iree/base:signature_mangle",
- "//iree/base:status",
- "//iree/hal:api",
- "//iree/modules/hal",
- "//iree/vm",
- "//iree/vm:bytecode_module",
- "//iree/vm:ref_cc",
- "@com_google_absl//absl/strings",
- "@com_google_absl//absl/types:span",
- ],
-)
-
-cc_test(
- name = "vm_util_test",
- srcs = ["vm_util_test.cc"],
- deps = [
- ":vm_util",
- "//iree/base:api",
- "//iree/hal:api",
- "//iree/hal/vmla:vmla_driver_module",
- "//iree/modules/hal",
- "//iree/testing:gtest",
- "//iree/testing:gtest_main",
- "//iree/vm",
- "@com_google_absl//absl/strings",
- ],
-)
diff --git a/iree/tools/CMakeLists.txt b/iree/tools/CMakeLists.txt
index 9d73449..d21908c 100644
--- a/iree/tools/CMakeLists.txt
+++ b/iree/tools/CMakeLists.txt
@@ -14,6 +14,12 @@
# bazel_to_cmake: DO NOT EDIT (Special logic is used throughout this file)
+# This need to come first so targets in the android/ directory can depend on it.
+# TODO(#3317): this seems to indicate an issue somewhere regarding dynamic
+# library dependency management.
+add_subdirectory(utils)
+
+add_subdirectory(android)
add_subdirectory(test)
# Enable compiler targets based on options.
@@ -57,7 +63,6 @@
SRCS
"iree-benchmark-module-main.cc"
DEPS
- ::vm_util
absl::flags
absl::flags_parse
absl::flags_usage
@@ -68,6 +73,7 @@
iree::base::status
iree::base::tracing
iree::modules::hal
+ iree::tools::utils::vm_util
iree::vm
iree::vm::bytecode_module
${IREE_HAL_DRIVER_MODULES}
@@ -97,7 +103,6 @@
SRCS
"iree-run-module-main.cc"
DEPS
- ::vm_util
absl::flags
absl::strings
iree::base::file_io
@@ -105,6 +110,7 @@
iree::base::status
iree::base::tracing
iree::modules::hal
+ iree::tools::utils::vm_util
iree::vm
iree::vm::bytecode_module
${IREE_HAL_DRIVER_MODULES}
@@ -329,7 +335,6 @@
::init_mlir_passes_and_dialects
::init_targets
::init_xla_dialects
- ::vm_util
LLVMSupport
MLIRIR
MLIRParser
@@ -352,6 +357,7 @@
iree::compiler::Translation::IREEVM
iree::hal::api
iree::modules::hal
+ iree::tools::utils::vm_util
iree::vm
iree::vm::bytecode_module
${IREE_HAL_DRIVER_MODULES}
@@ -374,43 +380,6 @@
)
endif()
-iree_cc_library(
- NAME
- vm_util
- HDRS
- "vm_util.h"
- SRCS
- "vm_util.cc"
- DEPS
- absl::span
- absl::strings
- iree::base::file_io
- iree::base::signature_mangle
- iree::base::status
- iree::hal::api
- iree::modules::hal
- iree::vm
- iree::vm::bytecode_module
- iree::vm::ref_cc
- PUBLIC
-)
-
-iree_cc_test(
- NAME
- vm_util_test
- SRCS
- "vm_util_test.cc"
- DEPS
- ::vm_util
- iree::base::api
- iree::hal::api
- iree::hal::vmla::vmla_driver_module
- iree::modules::hal
- iree::testing::gtest
- iree::testing::gtest_main
- iree::vm
-)
-
if(${IREE_ENABLE_MLIR})
add_custom_target(IreeFileCheck ALL
COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_SOURCE_DIR}/IreeFileCheck.sh IreeFileCheck
diff --git a/iree/tools/android/CMakeLists.txt b/iree/tools/android/CMakeLists.txt
new file mode 100644
index 0000000..c2f9124
--- /dev/null
+++ b/iree/tools/android/CMakeLists.txt
@@ -0,0 +1,16 @@
+# Copyright 2020 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+iree_add_all_subdirs()
+
diff --git a/iree/tools/android/run_module_app/AndroidManifest.xml.template b/iree/tools/android/run_module_app/AndroidManifest.xml.template
new file mode 100644
index 0000000..ffa8028
--- /dev/null
+++ b/iree/tools/android/run_module_app/AndroidManifest.xml.template
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ android:versionCode="1"
+ android:versionName="1.0"
+ package="com.google.iree.run_module">
+ <!-- Vulkan 1.1 is introduced in Android 9 (API level 28) so we can support
+ that as a minimum. -->
+ <uses-sdk android:minSdkVersion="28"
+ android:targetSdkVersion="${IREE_ANDROID_API_LEVEL}" />
+
+ <application android:label="@string/app_name"
+ android:debuggable="true"
+ android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
+ <!-- The convenience NativeActivity allows us to purely use native code
+ and the NDK for the app. -->
+ <activity android:name="android.app.NativeActivity"
+ android:label="@string/app_name"
+ android:configChanges="orientation|keyboardHidden">
+ <!-- Specify the shared library to load for NativeActivity. -->
+ <meta-data android:name="android.app.lib_name"
+ android:value="iree_run_module_app" />
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/iree/tools/android/run_module_app/CMakeLists.txt b/iree/tools/android/run_module_app/CMakeLists.txt
new file mode 100644
index 0000000..42c2f23
--- /dev/null
+++ b/iree/tools/android/run_module_app/CMakeLists.txt
@@ -0,0 +1,54 @@
+# Copyright 2020 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+if (NOT ANDROID)
+ return()
+endif()
+
+set(NATIVE_APP_GLUE_DIR "${ANDROID_NDK}/sources/android/native_app_glue")
+
+iree_cc_library(
+ NAME
+ android_native_app_glue
+ SRCS
+ "${NATIVE_APP_GLUE_DIR}/android_native_app_glue.c"
+)
+
+# Export ANativeActivity_onCreate().
+# See https://github.com/android-ndk/ndk/issues/381.
+set(CMAKE_SHARED_LINKER_FLAGS
+ "${CMAKE_SHARED_LINKER_FLAGS} -u ANativeActivity_onCreate")
+
+iree_cc_library(
+ NAME
+ iree_run_module_app
+ SRCS
+ src/main.cc
+ INCLUDES
+ ${NATIVE_APP_GLUE_DIR}
+ DEPS
+ ::android_native_app_glue
+ absl::strings
+ iree::base::initializer
+ iree::base::status
+ iree::modules::hal
+ iree::tools::utils::vm_util
+ iree::vm
+ ${IREE_HAL_DRIVER_MODULES}
+ LINKOPTS
+ android
+ log
+ SHARED
+ WHOLEARCHIVE
+)
diff --git a/iree/tools/android/run_module_app/README.md b/iree/tools/android/run_module_app/README.md
new file mode 100644
index 0000000..afba41d
--- /dev/null
+++ b/iree/tools/android/run_module_app/README.md
@@ -0,0 +1,61 @@
+# Android App to Run an IREE Bytecode Module
+
+This directory contains configuration to create an Android application that
+executes a single IREE module as a native activity.
+
+Note that this app is **purely** for benchmarking/profiling IREE itself.
+This is not the expected integration path for a real Android application,
+for which we expect to provide proper Java API and build support.
+
+## Native Activity
+
+The app uses Android [`NativeActivity`][native-activity] to bridge IREE core
+libraries together with the Android system. Native activity allows one to
+implement an Android Activity purely in C/C++. There are
+[tutorials][native-activity-tutorial] and [examples][native-activity-example]
+one can follow to learn about Native Activity.
+
+## Android Studio
+
+This app does not contain Gradle configurations. The reason is that we need
+to package both IREE native libraries and a specific VM module invocation
+into the app. The procedure cannot be automated much by Android Studio; rather
+one might need to copy files from different places, rename them, and wire up
+the build. It's inconvenient. For a developer tool we would like to avoid
+such friction and thus improve velocity. So a script,
+[`build_apk.sh`](./build_apk.sh), is provided to automate the process.
+
+But the script itself requires an Android SDK/NDK installation structure that
+matches Android Studio. So it's easier to just install Android Studio to
+manage Android SDK/NDK. The script will use proper tools in Android SDK/NDK
+to build and package the final APK file.
+
+## Build the APK
+
+In general, we need to
+
+1. Build the `iree_run_module_app` shared library following normal C++ build
+ process.
+1. Package the shared library together with an IREE VM FlatBuffer, its entry
+ function, input buffers, and the HAL driver into an Android app, following
+ a certain directory hierarchy. Specifically,
+ 1. Generate `AndroidManifest.xml` from the
+ [template](./AndroidManifest.xml.template) by providing the proper target
+ Android API level.
+ 1. Copy the VM FlatBuffer as `assets/module.vmfb`, write the entry function
+ input buffers, and HAL driver into `assets/entry_function.txt`,
+ `assets/inputs.txt`, and `assets/driver.txt`, respectively.
+ 1. Copy the shared libary under `lib/<android-abi>/`.
+ 1. Compile resources under [`res/`](./res) directory into an Android DEX
+ file.
+ 1. Package all of the above into an APK file.
+ 1. Properly align and sign the APK file.
+
+## Run on Android
+
+When started on Android, the app will read the contents in `assets` to get the
+VM FlatBuffer and invocation information and run it.
+
+[native-activity]: https://developer.android.com/reference/android/app/NativeActivity
+[native-activity-example]: https://github.com/android/ndk-samples/tree/master/native-activity
+[native-activity-tutorial]: https://medium.com/androiddevelopers/getting-started-with-c-and-android-native-activities-2213b402ffff
diff --git a/iree/tools/android/run_module_app/build_apk.sh b/iree/tools/android/run_module_app/build_apk.sh
new file mode 100755
index 0000000..8b83684
--- /dev/null
+++ b/iree/tools/android/run_module_app/build_apk.sh
@@ -0,0 +1,280 @@
+#!/bin/bash
+# Copyright 2020 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -e
+
+#########################
+# Script input parameters
+#########################
+
+echo "=== A script for building iree-run-module apk ==="
+echo "This script wraps iree-run-module together with a"
+echo "specific IREE VM module and invocation information."
+echo ""
+echo "At a minimum, it expects the following env vars:"
+echo "* ANDROID_SDK_ROOT"
+echo "* ANDROID_NDK_ROOT"
+echo "* ANDROID_SDK_BUILD_TOOLS_VERSION"
+echo "See the script for details and more controls."
+echo "===-------------------------------------------==="
+echo ""
+
+print_usage_and_exit() {
+ echo "Usage: $0 <artifact-directory> "
+ echo " --driver <driver>"
+ echo " --module_file <input-module-file> "
+ echo " --entry_function <entry-function> "
+ echo " --inputs_file <input-buffer-file> "
+ exit 1
+}
+
+while (( "$#" )); do
+ case "$1" in
+ --driver)
+ if [[ -n "$2" ]] && [[ ${2:0:1} != "-" ]]; then
+ IREE_DRIVER=$2
+ shift 2
+ else
+ echo "Error: missing argument for $1" >&2
+ print_usage_and_exit
+ fi
+ ;;
+ --module_file)
+ if [[ -n "$2" ]] && [[ ${2:0:1} != "-" ]]; then
+ IREE_INPUT_MODULE_FILE=$(readlink -f $2)
+ shift 2
+ else
+ echo "Error: missing argument for $1" >&2
+ print_usage_and_exit
+ fi
+ ;;
+ --entry_function)
+ if [[ -n "$2" ]] && [[ ${2:0:1} != "-" ]]; then
+ IREE_ENTRY_FUNCTION=$2
+ shift 2
+ else
+ echo "Error: missing argument for $1" >&2
+ print_usage_and_exit
+ fi
+ ;;
+ --inputs_file)
+ if [[ -n "$2" ]] && [[ ${2:0:1} != "-" ]]; then
+ IREE_INPUT_BUFFER_FILE=$(readlink -f $2)
+ shift 2
+ else
+ echo "Error: missing argument for $1" >&2
+ print_usage_and_exit
+ fi
+ ;;
+ -*|--*=) # Unsupported flags
+ echo "Error: Unsupported flag $1" >&2
+ exit 1
+ ;;
+ *) # Positional arguments
+ if [[ -z "${IREE_ARTIFACT_ROOT+x}" ]]; then
+ IREE_ARTIFACT_ROOT=$(readlink -f $1)
+ else
+ echo "Error: <artifact-directory> already set to ${IREE_ARTIFACT_ROOT}" >&2
+ print_usage_and_exit
+ fi
+ shift
+ ;;
+ esac
+done
+
+if [[ -z "${IREE_ARTIFACT_ROOT}" ]] || [[ -z "${IREE_INPUT_MODULE_FILE}" ]] || \
+ [[ -z "${IREE_ENTRY_FUNCTION}" ]] || [[ -z "${IREE_INPUT_BUFFER_FILE}" ]] || \
+ [[ -z "${IREE_DRIVER}" ]]; then
+ echo "Error: missing necessary parameters" >&2
+ print_usage_and_exit
+fi
+
+#################################
+# IREE Android app configurations
+#################################
+
+# The final Android APK name; default to "iree-run-module.apk".
+IREE_APK_NAME="${IREE_APK_NAME:-iree-run-module}"
+# The CMAKE build type for compiling IREE. default to Release.
+IREE_BUILD_TYPE="${IREE_BUILD_TYPE:-Release}"
+# The target Android API level; default to Android 10 (API level 29).
+IREE_ANDROID_API_LEVEL="${IREE_ANDROID_API_LEVEL:-29}"
+# The target Android platform ABI; default to arm64-v8a.
+IREE_ANDROID_ABI="${IREE_ANDROID_ABI:-arm64-v8a}"
+
+################################
+# Android SDK/NDK configurations
+################################
+
+# Android SDK root; must be provided as environment variable.
+# By default Android Studio uses
+# * $HOME/Android/Sdk for Linux.
+# * $HOME/Library/Android/sdk for macOS.
+# * $%LOCALAPPDATA%\Android\sdk for Windows.
+ANDROID_SDK_ROOT="${ANDROID_SDK_ROOT:?environment variable not set}"
+# Android NDK root; must be provided as environment variable.
+ANDROID_NDK_ROOT="${ANDROID_NDK_ROOT:?environment variable not set}"
+# Android SDK build tools version; must be provided as environment variable.
+ANDROID_SDK_BUILD_TOOLS_VERSION="${ANDROID_SDK_BUILD_TOOLS_VERSION?environment variable not set}"
+# Key store for signing apk files; default to Android debug keystore created
+# by Android Studio.
+ANDROID_KEYSTORE="${ANDROID_KEYSTORE:-${HOME}/.android/debug.keystore}"
+
+######################
+# IREE build toolchain
+######################
+
+CMAKE_BIN="${CMAKE_BIN:-$(which cmake)}"
+NINJA_BIN="${NINJA_BIN:-$(which ninja)}"
+CC_BIN="${CC_BIN:-$(which clang)}"
+CXX_BIN="${CXX_BIN:-$(which clang++)}"
+JAVAC_BIN="${JAVAC_BIN:-$(which javac)}"
+
+##################################
+# IREE source/artifact directories
+##################################
+
+# IREE project source root.
+IREE_SOURCE_ROOT="$(git rev-parse --show-toplevel)"
+# iree-run-module Android app source root.
+IREE_NATIVE_APP_SOURCE_ROOT="${IREE_SOURCE_ROOT?}/iree/tools/android/run_module_app"
+
+# Directory for IREE native code intermediate intermediate artifacts.
+IREE_NATIVE_LIB_BUILD_DIR="${IREE_ARTIFACT_ROOT?}/iree/${IREE_BUILD_TYPE?}"
+# Directory for holding APK parts.
+IREE_APK_PARTS_DIR="${IREE_ARTIFACT_ROOT?}/parts"
+# Directory for IREE native libraries.
+IREE_NATIVE_LIB_DIR="${IREE_APK_PARTS_DIR?}/libs/lib/${IREE_ANDROID_ABI?}"
+# Directory for Android app assets.
+IREE_ASSET_DIR="${IREE_APK_PARTS_DIR?}/assets"
+# Directory for Android app R.class.
+IREE_RESOURCE_GEN_DIR="${IREE_APK_PARTS_DIR?}/rclass"
+
+#########################
+# Android build toolchain
+#########################
+
+ANDROID_SDK_BUILD_TOOLS_DIR="${ANDROID_SDK_ROOT?}/build-tools/${ANDROID_SDK_BUILD_TOOLS_VERSION?}"
+ANDROID_SDK_PLATFORMS_DIR="${ANDROID_SDK_ROOT?}/platforms/android-${IREE_ANDROID_API_LEVEL?}"
+
+AAPT_BIN="${ANDROID_SDK_BUILD_TOOLS_DIR?}/aapt"
+DX_BIN="${ANDROID_SDK_BUILD_TOOLS_DIR?}/dx"
+ZIPALIGN_BIN="${ANDROID_SDK_BUILD_TOOLS_DIR?}/zipalign"
+APKSIGNER_BIN="${ANDROID_SDK_BUILD_TOOLS_DIR?}/apksigner"
+
+AAPT_ADD="${AAPT_BIN?} add"
+# Link in the Android framework classes and disable compression for IREE
+# bytecode modules. This allows us to mmap the file directly.
+AAPT_PACK="${AAPT_BIN?} package -f -I ${ANDROID_SDK_PLATFORMS_DIR?}/android.jar -0 vmfb"
+DX="${DX_BIN?} --dex"
+ZIPALIGN="${ZIPALIGN_BIN?} -f -p 4"
+APKSIGN="${APKSIGNER_BIN?} sign"
+JAVAC="${JAVAC_BIN?} -classpath ${ANDROID_SDK_PLATFORMS_DIR?}/android.jar -sourcepath ${IREE_RESOURCE_GEN_DIR?} -d ${IREE_APK_PARTS_DIR?}"
+
+#############################
+# Build IREE native libraries
+#############################
+
+mkdir -p "${IREE_NATIVE_LIB_BUILD_DIR?}"
+
+echo ">>> Building IREE native libraries <<<"
+
+IREE_NATIVE_LIB_NAME=iree_tools_android_run_module_app_iree_run_module_app
+
+pushd "${IREE_NATIVE_LIB_BUILD_DIR?}"
+"${CMAKE_BIN?}" "${IREE_SOURCE_ROOT?}" -G Ninja \
+ -DCMAKE_BUILD_TYPE="${IREE_BUILD_TYPE?}" \
+ -DCMAKE_TOOLCHAIN_FILE="${ANDROID_NDK_ROOT?}/build/cmake/android.toolchain.cmake" \
+ -DANDROID_ABI="${IREE_ANDROID_ABI?}" \
+ -DANDROID_PLATFORM="android-${IREE_ANDROID_API_LEVEL?}" \
+ -DIREE_HOST_C_COMPILER="${CC_BIN?}" \
+ -DIREE_HOST_CXX_COMPILER="${CXX_BIN?}" \
+ -DIREE_BUILD_COMPILER=OFF \
+ -DIREE_BUILD_TESTS=OFF \
+ -DIREE_BUILD_SAMPLES=OFF
+"${NINJA_BIN?}" "${IREE_NATIVE_LIB_NAME?}"
+popd
+
+#####################
+# Package Android app
+#####################
+
+# Clean artifacts from previous runs.
+rm -rf "${IREE_ARTIFACT_ROOT?}/${IREE_APK_NAME?}.apk" "${IREE_APK_PARTS_DIR?}"
+
+echo ">>> Generating AndroidManifest.xml <<<"
+
+# Create an AndroidManifest.xml with proper target SDK version.
+mkdir -p "${IREE_APK_PARTS_DIR?}"
+IREE_ANDROID_API_LEVEL="${IREE_ANDROID_API_LEVEL?}" envsubst \
+ < "${IREE_NATIVE_APP_SOURCE_ROOT?}/AndroidManifest.xml.template" \
+ > "${IREE_APK_PARTS_DIR?}/AndroidManifest.xml"
+
+echo ">>> Preparing shared libraries and vm module information <<<"
+
+# Find the compiled iree_run_module_app shared library and symlink it to a
+# known location for packaging.
+mkdir -p "${IREE_NATIVE_LIB_DIR?}"
+IREE_NATIVE_LIB=$(find ${IREE_NATIVE_LIB_BUILD_DIR?} -name "lib${IREE_NATIVE_LIB_NAME?}.so")
+# Note: the target link name must match with
+# run_module_app/AndroidManifest.xml.template.
+ln -sf "${IREE_NATIVE_LIB?}" "${IREE_NATIVE_LIB_DIR?}/libiree_run_module_app.so"
+
+# Copy the VM FlatBuffer and iree-run-module invocation related information
+# over as assets.
+mkdir -p "${IREE_ASSET_DIR?}"
+# Note: the following files must match with run_module_app/src/main.cc.
+cp "${IREE_INPUT_MODULE_FILE?}" "${IREE_ASSET_DIR?}/module.vmfb"
+cp "${IREE_INPUT_BUFFER_FILE?}" "${IREE_ASSET_DIR?}/inputs.txt"
+echo -n "${IREE_ENTRY_FUNCTION?}" > "${IREE_ASSET_DIR?}/entry_function.txt"
+echo -n "${IREE_DRIVER?}" > "${IREE_ASSET_DIR?}/driver.txt"
+
+echo ">>> Compiling app resources <<<"
+
+# Generate the R.java for resources.
+mkdir -p "${IREE_RESOURCE_GEN_DIR?}"
+${AAPT_PACK?} --non-constant-id -m \
+ -M "${IREE_APK_PARTS_DIR?}/AndroidManifest.xml" \
+ -S "${IREE_NATIVE_APP_SOURCE_ROOT?}/res" \
+ -J "${IREE_RESOURCE_GEN_DIR?}" \
+ --generate-dependencies
+
+# Compile the R.java and create classes.dex out of it for Android.
+echo "Using javac: '${JAVAC_BIN?}'"
+${JAVAC?} "${IREE_RESOURCE_GEN_DIR?}"/com/google/iree/run_module/*.java
+${DX?} --output="${IREE_APK_PARTS_DIR?}/classes.dex" "${IREE_APK_PARTS_DIR?}"
+
+echo ">>> Packaging apk file <<<"
+
+# Package assets and shared libraries into an apk file.
+${AAPT_PACK?} -m \
+ -M "${IREE_APK_PARTS_DIR?}/AndroidManifest.xml" \
+ -S "${IREE_NATIVE_APP_SOURCE_ROOT?}/res" \
+ -A "${IREE_APK_PARTS_DIR?}/assets" \
+ -F "${IREE_APK_PARTS_DIR?}/${IREE_APK_NAME?}.unaligned.apk" \
+ --shared-lib "${IREE_APK_PARTS_DIR?}/libs"
+
+pushd "${IREE_APK_PARTS_DIR?}"
+# Also package the resources into the apk file.
+${AAPT_ADD?} "${IREE_APK_NAME?}.unaligned.apk" classes.dex
+echo ">>> Aligning apk file <<<"
+${ZIPALIGN?} "${IREE_APK_NAME?}.unaligned.apk" "${IREE_APK_NAME?}.apk"
+echo ">>> Signing apk file <<<"
+echo "NOTE: if you are using the Android Studio's debug keystore, the password is 'android'."
+${APKSIGN?} --ks "${ANDROID_KEYSTORE?}" --min-sdk-version 28 "${IREE_APK_NAME?}.apk"
+mv "${IREE_APK_NAME?}.apk" "${IREE_ARTIFACT_ROOT?}"
+popd
+
+echo ">>> Done: '${IREE_ARTIFACT_ROOT?}/${IREE_APK_NAME?}.apk' <<<"
diff --git a/iree/tools/android/run_module_app/res/values/strings.xml b/iree/tools/android/run_module_app/res/values/strings.xml
new file mode 100644
index 0000000..bab2d9b
--- /dev/null
+++ b/iree/tools/android/run_module_app/res/values/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="app_name">IREE Run Module</string>
+</resources>
diff --git a/iree/tools/android/run_module_app/src/main.cc b/iree/tools/android/run_module_app/src/main.cc
new file mode 100644
index 0000000..7250ab3
--- /dev/null
+++ b/iree/tools/android/run_module_app/src/main.cc
@@ -0,0 +1,216 @@
+// Copyright 2020 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <android/log.h>
+#include <android_native_app_glue.h>
+
+#include <chrono>
+#include <thread>
+
+#include "absl/strings/str_split.h"
+#include "absl/strings/string_view.h"
+#include "iree/base/initializer.h"
+#include "iree/base/status.h"
+#include "iree/modules/hal/hal_module.h"
+#include "iree/tools/utils/vm_util.h"
+#include "iree/vm/api.h"
+
+namespace iree {
+namespace {
+
+const char* kAppTag = "iree-run-module";
+#define LOGI(...) \
+ ((void)__android_log_print(ANDROID_LOG_INFO, kAppTag, __VA_ARGS__))
+#define LOGE(...) \
+ ((void)__android_log_print(ANDROID_LOG_ERROR, kAppTag, __VA_ARGS__))
+
+const char kModuleFileName[] = "module.vmfb";
+const char kEntryFunctionFileName[] = "entry_function.txt";
+const char kInputsFileName[] = "inputs.txt";
+const char kDriverFileName[] = "driver.txt";
+
+// A struct containing information regarding one IREE VM module invocation.
+struct IreeModuleInvocation {
+ std::string module;
+ std::string entry_function;
+ std::string inputs;
+ std::string driver;
+};
+
+// A class for loading IREE module invocation information from Android apk asset
+// files.
+class ModuleLoader {
+ public:
+ explicit ModuleLoader(android_app* app) : app_context_(app) {}
+ ~ModuleLoader() = default;
+
+ StatusOr<IreeModuleInvocation> LoadModuleInvocation() {
+ IreeModuleInvocation invocation = {};
+ IREE_ASSIGN_OR_RETURN(invocation.module, ReadFileAsset(kModuleFileName));
+ IREE_ASSIGN_OR_RETURN(invocation.entry_function,
+ ReadFileAsset(kEntryFunctionFileName));
+ IREE_ASSIGN_OR_RETURN(invocation.inputs, ReadFileAsset(kInputsFileName));
+ IREE_ASSIGN_OR_RETURN(invocation.driver, ReadFileAsset(kDriverFileName));
+ return invocation;
+ }
+
+ private:
+ // Reads the given asset file and returns its contents.
+ StatusOr<std::string> ReadFileAsset(const char* file_name) {
+ AAssetManager* asset_manager = app_context_->activity->assetManager;
+ AAsset* asset =
+ AAssetManager_open(asset_manager, file_name, AASSET_MODE_BUFFER);
+ if (!asset) {
+ return InvalidArgumentErrorBuilder(IREE_LOC)
+ << "failed to open file '" << kModuleFileName << "' in assets";
+ }
+
+ size_t size_in_bytes = AAsset_getLength(asset);
+ std::string contents;
+ contents.resize(size_in_bytes);
+
+ AAsset_read(asset, const_cast<char*>(contents.data()), size_in_bytes);
+ AAsset_close(asset);
+
+ return contents;
+ }
+
+ android_app* app_context_;
+};
+
+Status RunModule(const IreeModuleInvocation& invocation) {
+ IREE_RETURN_IF_ERROR(iree_hal_module_register_types())
+ << "registering HAL types";
+ iree_vm_instance_t* instance = nullptr;
+ IREE_RETURN_IF_ERROR(
+ iree_vm_instance_create(iree_allocator_system(), &instance))
+ << "creating instance";
+
+ iree_vm_module_t* input_module = nullptr;
+ IREE_RETURN_IF_ERROR(LoadBytecodeModule(invocation.module, &input_module));
+
+ iree_hal_device_t* device = nullptr;
+ IREE_RETURN_IF_ERROR(CreateDevice(invocation.driver, &device));
+ iree_vm_module_t* hal_module = nullptr;
+ IREE_RETURN_IF_ERROR(CreateHalModule(device, &hal_module));
+
+ iree_vm_context_t* context = nullptr;
+ // Order matters. The input module will likely be dependent on the hal module.
+ std::array<iree_vm_module_t*, 2> modules = {hal_module, input_module};
+ IREE_RETURN_IF_ERROR(iree_vm_context_create_with_modules(
+ instance, modules.data(), modules.size(), iree_allocator_system(),
+ &context))
+ << "creating context";
+
+ const std::string& function_name = invocation.entry_function;
+ iree_vm_function_t function;
+ IREE_RETURN_IF_ERROR(input_module->lookup_function(
+ input_module->self, IREE_VM_FUNCTION_LINKAGE_EXPORT,
+ iree_string_view_t{function_name.data(), function_name.size()},
+ &function))
+ << "looking up function '" << function_name << "'";
+
+ IREE_RETURN_IF_ERROR(ValidateFunctionAbi(function));
+ IREE_ASSIGN_OR_RETURN(auto input_descs, ParseInputSignature(function));
+
+ absl::InlinedVector<absl::string_view, 4> input_views(
+ absl::StrSplit(invocation.inputs, '\n', absl::SkipEmpty()));
+ IREE_ASSIGN_OR_RETURN(
+ auto inputs,
+ ParseToVariantList(input_descs, iree_hal_device_allocator(device),
+ input_views));
+
+ IREE_ASSIGN_OR_RETURN(auto output_descs, ParseOutputSignature(function));
+ vm::ref<iree_vm_list_t> outputs;
+ IREE_RETURN_IF_ERROR(iree_vm_list_create(/*element_type=*/nullptr,
+ output_descs.size(),
+ iree_allocator_system(), &outputs));
+
+ LOGI("Execute @%s", function_name.c_str());
+ IREE_RETURN_IF_ERROR(iree_vm_invoke(context, function, /*policy=*/nullptr,
+ inputs.get(), outputs.get(),
+ iree_allocator_system()))
+ << "invoking function " << function_name;
+
+ std::ostringstream oss;
+ IREE_RETURN_IF_ERROR(PrintVariantList(output_descs, outputs.get(), &oss))
+ << "printing results";
+ LOGI("Execution Result:");
+ LOGI("%s", oss.str().c_str());
+
+ inputs.reset();
+ outputs.reset();
+ iree_vm_module_release(hal_module);
+ iree_vm_module_release(input_module);
+ iree_hal_device_release(device);
+ iree_vm_context_release(context);
+ iree_vm_instance_release(instance);
+ return OkStatus();
+}
+
+void RunModuleAppMain(android_app* app) {
+ // Sleep for 2 seconds to allow tools like AGI to perform the necessary
+ // initialization.
+ // TODO(antiagainst): This can be improved by rendering some UI button to
+ // trigger the workload.
+ std::this_thread::sleep_for(std::chrono::seconds(2));
+
+ IREE_RUN_MODULE_INITIALIZERS();
+
+ ModuleLoader loader(app);
+ StatusOr<IreeModuleInvocation> invocation = loader.LoadModuleInvocation();
+ if (invocation.ok()) {
+ LOGI("entry function: '%s'", invocation->entry_function.c_str());
+ LOGI("inputs:\n%s", invocation->inputs.c_str());
+ LOGI("driver: '%s'", invocation->driver.c_str());
+ auto status = RunModule(invocation.value());
+ if (!status.ok()) LOGE("%s", status.ToString().c_str());
+ } else {
+ LOGE("failed to load module invocation: %s",
+ invocation.status().ToString().c_str());
+ }
+}
+
+void HandleAndroidAppCommand(android_app* app, int32_t cmd) {
+ switch (cmd) {
+ case APP_CMD_INIT_WINDOW:
+ RunModuleAppMain(app);
+ break;
+ default:
+ break;
+ }
+}
+
+} // namespace
+} // namespace iree
+
+#define NATIVE_EXPORT extern "C" __attribute__((visibility("default")))
+
+// The main entry point of a native application using android_native_app_glue.
+// It runs in its own thread with its own event loop.
+NATIVE_EXPORT void android_main(struct android_app* app) {
+ // Set the callback to process system events.
+ app->onAppCmd = iree::HandleAndroidAppCommand;
+
+ int events;
+ android_poll_source* source;
+
+ // Main loop for processing events.
+ while (app->destroyRequested == 0) {
+ if (ALooper_pollAll(/*timeoutMillis=*/1, /*outFd=*/nullptr, &events,
+ (void**)&source) >= 0) {
+ if (source != nullptr) source->process(app, source);
+ }
+ }
+}
diff --git a/iree/tools/iree-benchmark-module-main.cc b/iree/tools/iree-benchmark-module-main.cc
index 0c260be..ba71a0f 100644
--- a/iree/tools/iree-benchmark-module-main.cc
+++ b/iree/tools/iree-benchmark-module-main.cc
@@ -22,7 +22,7 @@
#include "iree/base/status.h"
#include "iree/base/tracing.h"
#include "iree/modules/hal/hal_module.h"
-#include "iree/tools/vm_util.h"
+#include "iree/tools/utils/vm_util.h"
#include "iree/vm/api.h"
#include "iree/vm/bytecode_module.h"
diff --git a/iree/tools/iree-run-mlir-main.cc b/iree/tools/iree-run-mlir-main.cc
index 6812a52..5f69f2d 100644
--- a/iree/tools/iree-run-mlir-main.cc
+++ b/iree/tools/iree-run-mlir-main.cc
@@ -62,7 +62,7 @@
#include "iree/tools/init_mlir_dialects.h"
#include "iree/tools/init_targets.h"
#include "iree/tools/init_xla_dialects.h"
-#include "iree/tools/vm_util.h"
+#include "iree/tools/utils/vm_util.h"
#include "iree/vm/api.h"
#include "iree/vm/bytecode_module.h"
#include "llvm/ADT/StringRef.h"
diff --git a/iree/tools/iree-run-module-main.cc b/iree/tools/iree-run-module-main.cc
index 73d3362..cefbf58 100644
--- a/iree/tools/iree-run-module-main.cc
+++ b/iree/tools/iree-run-module-main.cc
@@ -21,7 +21,7 @@
#include "iree/base/status.h"
#include "iree/base/tracing.h"
#include "iree/modules/hal/hal_module.h"
-#include "iree/tools/vm_util.h"
+#include "iree/tools/utils/vm_util.h"
#include "iree/vm/api.h"
#include "iree/vm/bytecode_module.h"
diff --git a/iree/tools/utils/BUILD b/iree/tools/utils/BUILD
new file mode 100644
index 0000000..4aa8c6b
--- /dev/null
+++ b/iree/tools/utils/BUILD
@@ -0,0 +1,54 @@
+# Copyright 2020 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+package(
+ default_visibility = ["//visibility:public"],
+ features = ["layering_check"],
+ licenses = ["notice"], # Apache 2.0
+)
+
+# TODO(b/146898896): Refactor these into more coherent packages.
+cc_library(
+ name = "vm_util",
+ srcs = ["vm_util.cc"],
+ hdrs = ["vm_util.h"],
+ deps = [
+ "//iree/base:file_io",
+ "//iree/base:signature_mangle",
+ "//iree/base:status",
+ "//iree/hal:api",
+ "//iree/modules/hal",
+ "//iree/vm",
+ "//iree/vm:bytecode_module",
+ "//iree/vm:ref_cc",
+ "@com_google_absl//absl/strings",
+ "@com_google_absl//absl/types:span",
+ ],
+)
+
+cc_test(
+ name = "vm_util_test",
+ srcs = ["vm_util_test.cc"],
+ deps = [
+ ":vm_util",
+ "//iree/base:api",
+ "//iree/hal:api",
+ "//iree/hal/vmla:vmla_driver_module",
+ "//iree/modules/hal",
+ "//iree/testing:gtest",
+ "//iree/testing:gtest_main",
+ "//iree/vm",
+ "@com_google_absl//absl/strings",
+ ],
+)
diff --git a/iree/tools/utils/CMakeLists.txt b/iree/tools/utils/CMakeLists.txt
new file mode 100644
index 0000000..b0a9f7b
--- /dev/null
+++ b/iree/tools/utils/CMakeLists.txt
@@ -0,0 +1,53 @@
+# Copyright 2020 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+iree_add_all_subdirs()
+
+iree_cc_library(
+ NAME
+ vm_util
+ HDRS
+ "vm_util.h"
+ SRCS
+ "vm_util.cc"
+ DEPS
+ absl::span
+ absl::strings
+ iree::base::file_io
+ iree::base::signature_mangle
+ iree::base::status
+ iree::hal::api
+ iree::modules::hal
+ iree::vm
+ iree::vm::bytecode_module
+ iree::vm::ref_cc
+ PUBLIC
+)
+
+iree_cc_test(
+ NAME
+ vm_util_test
+ SRCS
+ "vm_util_test.cc"
+ DEPS
+ ::vm_util
+ absl::strings
+ iree::base::api
+ iree::hal::api
+ iree::hal::vmla::vmla_driver_module
+ iree::modules::hal
+ iree::testing::gtest
+ iree::testing::gtest_main
+ iree::vm
+)
diff --git a/iree/tools/vm_util.cc b/iree/tools/utils/vm_util.cc
similarity index 99%
rename from iree/tools/vm_util.cc
rename to iree/tools/utils/vm_util.cc
index abb99b7..78b006d 100644
--- a/iree/tools/vm_util.cc
+++ b/iree/tools/utils/vm_util.cc
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "iree/tools/vm_util.h"
+#include "iree/tools/utils/vm_util.h"
#include <ostream>
diff --git a/iree/tools/vm_util.h b/iree/tools/utils/vm_util.h
similarity index 96%
rename from iree/tools/vm_util.h
rename to iree/tools/utils/vm_util.h
index 695c40d..8aa49dc 100644
--- a/iree/tools/vm_util.h
+++ b/iree/tools/utils/vm_util.h
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#ifndef IREE_TOOLS_VM_UTIL_H_
-#define IREE_TOOLS_VM_UTIL_H_
+#ifndef IREE_TOOLS_UTILS_VM_UTIL_H_
+#define IREE_TOOLS_UTILS_VM_UTIL_H_
#include <iostream>
#include <ostream>
@@ -96,4 +96,4 @@
} // namespace iree
-#endif // IREE_TOOLS_VM_UTIL_H_
+#endif // IREE_TOOLS_UTILS_VM_UTIL_H_
diff --git a/iree/tools/vm_util_test.cc b/iree/tools/utils/vm_util_test.cc
similarity index 98%
rename from iree/tools/vm_util_test.cc
rename to iree/tools/utils/vm_util_test.cc
index 1b59f73..17f924b 100644
--- a/iree/tools/vm_util_test.cc
+++ b/iree/tools/utils/vm_util_test.cc
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "iree/tools/vm_util.h"
+#include "iree/tools/utils/vm_util.h"
#include <sstream>