diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml
index bcf6f60e8c8..ba4dd90cf55 100644
--- a/.github/workflows/android.yml
+++ b/.github/workflows/android.yml
@@ -9,6 +9,8 @@ on:
paths:
- .ci/docker/**
- .github/workflows/android.yml
+ - build/build_android_library.sh
+ - build/test_android_ci.sh
- install_requirements.sh
- examples/demo-apps/android/**
- extension/android/**
@@ -45,6 +47,8 @@ jobs:
BUILD_TOOL=${{ matrix.build-tool }}
# Setup MacOS dependencies as there is no Docker support on MacOS atm
PYTHON_EXECUTABLE=python bash .ci/scripts/setup-linux.sh "${BUILD_TOOL}"
+ # Build Android library
+ bash build/build_android_library.sh
# Build Android demo app
bash build/test_android_ci.sh
@@ -61,8 +65,8 @@ jobs:
cp cmake-out-android-x86_64/lib/*.a artifacts-to-be-uploaded/x86_64/
cp cmake-out-android-x86_64/extension/android/*.so artifacts-to-be-uploaded/x86_64/
# Copyp AAR to S3
- cp build_aar/executorch.aar artifacts-to-be-uploaded/
- cp build_aar/executorch-llama.aar artifacts-to-be-uploaded/
+ cp executorch.aar artifacts-to-be-uploaded/
+ cp executorch-llama.aar artifacts-to-be-uploaded/
# Upload the app and its test suite to S3 so that they can be downloaded by the test job
upload-artifacts:
diff --git a/build/build_android_library.sh b/build/build_android_library.sh
new file mode 100644
index 00000000000..b224a9876de
--- /dev/null
+++ b/build/build_android_library.sh
@@ -0,0 +1,89 @@
+#!/bin/bash
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD-style license found in the
+# LICENSE file in the root directory of this source tree.
+
+set -ex
+
+build_jar() {
+ pushd extension/android
+ ./gradlew build
+ popd
+ cp extension/android/build/libs/executorch.jar "${BUILD_AAR_DIR}/libs"
+}
+
+build_android_native_library() {
+ ANDROID_ABI="$1"
+ ANDROID_NDK="${ANDROID_NDK:-/opt/ndk}"
+ CMAKE_OUT="cmake-out-android-$1"
+ cmake . -DCMAKE_INSTALL_PREFIX="${CMAKE_OUT}" \
+ -DCMAKE_TOOLCHAIN_FILE="${ANDROID_NDK}/build/cmake/android.toolchain.cmake" \
+ -DANDROID_ABI="${ANDROID_ABI}" \
+ -DANDROID_PLATFORM=android-23 \
+ -DEXECUTORCH_BUILD_XNNPACK=ON \
+ -DEXECUTORCH_BUILD_EXTENSION_DATA_LOADER=ON \
+ -DEXECUTORCH_BUILD_EXTENSION_MODULE=ON \
+ -DEXECUTORCH_BUILD_OPTIMIZED=ON \
+ -DCMAKE_BUILD_TYPE=Release \
+ -B"${CMAKE_OUT}"
+
+ if [ "$(uname)" == "Darwin" ]; then
+ CMAKE_JOBS=$(( $(sysctl -n hw.ncpu) - 1 ))
+ else
+ CMAKE_JOBS=$(( $(nproc) - 1 ))
+ fi
+ cmake --build "${CMAKE_OUT}" -j "${CMAKE_JOBS}" --target install --config Release
+
+ cmake examples/models/llama2 \
+ -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \
+ -DANDROID_ABI="$ANDROID_ABI" \
+ -DANDROID_PLATFORM=android-23 \
+ -DCMAKE_INSTALL_PREFIX="${CMAKE_OUT}" \
+ -DEXECUTORCH_BUILD_XNNPACK=ON \
+ -DCMAKE_BUILD_TYPE=Release \
+ -B"${CMAKE_OUT}"/examples/models/llama2
+
+ cmake --build "${CMAKE_OUT}"/examples/models/llama2 -j "${CMAKE_JOBS}" --config Release
+
+ cmake extension/android \
+ -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK}/build/cmake/android.toolchain.cmake \
+ -DANDROID_ABI="${ANDROID_ABI}" \
+ -DANDROID_PLATFORM=android-23 \
+ -DCMAKE_INSTALL_PREFIX="${CMAKE_OUT}" \
+ -DEXECUTORCH_BUILD_LLAMA_JNI=ON \
+ -DCMAKE_BUILD_TYPE=Release \
+ -B"${CMAKE_OUT}"/extension/android
+
+ cmake --build "${CMAKE_OUT}"/extension/android -j "${CMAKE_JOBS}" --config Release
+
+ cp "${CMAKE_OUT}"/extension/android/*.so "${BUILD_AAR_DIR}/jni/$1/"
+}
+
+build_aar() {
+ echo \ \
+ \ \
+ \ > "${BUILD_AAR_DIR}/AndroidManifest.xml"
+ pushd "${BUILD_AAR_DIR}"
+ # Rename libexecutorch_jni.so to libexecutorch.so for soname consistency
+ # between Java and JNI
+ mv jni/arm64-v8a/libexecutorch_jni.so jni/arm64-v8a/libexecutorch.so
+ mv jni/x86_64/libexecutorch_jni.so jni/x86_64/libexecutorch.so
+ zip -r executorch.aar libs jni/arm64-v8a/libexecutorch.so jni/x86_64/libexecutorch.so AndroidManifest.xml
+
+ rm jni/arm64-v8a/libexecutorch.so jni/x86_64/libexecutorch.so
+ zip -r executorch-llama.aar libs jni/arm64-v8a/libexecutorch_llama_jni.so jni/x86_64/libexecutorch_llama_jni.so AndroidManifest.xml
+ popd
+ cp "${BUILD_AAR_DIR}/executorch-llama.aar" .
+ cp "${BUILD_AAR_DIR}/executorch.aar" .
+}
+
+BUILD_AAR_DIR="$(mktemp -d)"
+export BUILD_AAR_DIR
+mkdir -p "${BUILD_AAR_DIR}/jni/arm64-v8a" "${BUILD_AAR_DIR}/jni/x86_64" "${BUILD_AAR_DIR}/libs"
+build_jar
+build_android_native_library arm64-v8a
+build_android_native_library x86_64
+build_aar
diff --git a/build/test_android_ci.sh b/build/test_android_ci.sh
index 1ae26872891..9ad24e769b7 100755
--- a/build/test_android_ci.sh
+++ b/build/test_android_ci.sh
@@ -18,47 +18,23 @@ export_model() {
cp "${MODEL_NAME}_xnnpack_fp32.pte" "${ASSETS_DIR}"
}
-build_android_native_library() {
- pushd examples/demo-apps/android/LlamaDemo
- CMAKE_OUT="cmake-out-android-$1" ANDROID_NDK=/opt/ndk ANDROID_ABI="$1" ./gradlew setup
- popd
- cp "cmake-out-android-$1"/extension/android/*.so build_aar/jni/$1/
-}
-
build_android_demo_app() {
+ mkdir -p examples/demo-apps/android/ExecuTorchDemo/app/libs
+ cp executorch.aar examples/demo-apps/android/ExecuTorchDemo/app/libs
pushd examples/demo-apps/android/ExecuTorchDemo
ANDROID_HOME=/opt/android/sdk ./gradlew build
popd
}
build_android_llama_demo_app() {
+ mkdir -p examples/demo-apps/android/LlamaDemo/app/libs
+ cp executorch-llama.aar examples/demo-apps/android/LlamaDemo/app/libs
pushd examples/demo-apps/android/LlamaDemo
ANDROID_HOME=/opt/android/sdk ./gradlew build
ANDROID_HOME=/opt/android/sdk ./gradlew assembleAndroidTest
popd
}
-build_aar() {
- cp extension/android/build/libs/executorch.jar build_aar/libs
- echo \ \
- \ \
- \ > build_aar/AndroidManifest.xml
- pushd build_aar
- mv jni/arm64-v8a/libexecutorch_jni.so jni/arm64-v8a/libexecutorch.so
- mv jni/x86_64/libexecutorch_jni.so jni/x86_64/libexecutorch.so
- zip -r executorch.aar libs jni AndroidManifest.xml
-
- rm jni/arm64-v8a/libexecutorch.so jni/x86_64/libexecutorch.so
- zip -r executorch-llama.aar libs jni AndroidManifest.xml
- popd
-}
-
-mkdir -p build_aar/jni/arm64-v8a build_aar/jni/x86_64 build_aar/libs
-
-build_android_native_library arm64-v8a
-build_android_native_library x86_64
export_model
build_android_demo_app
build_android_llama_demo_app
-build_aar
diff --git a/docs/source/android-prebuilt-library.md b/docs/source/android-prebuilt-library.md
new file mode 100644
index 00000000000..7bf6de1c23f
--- /dev/null
+++ b/docs/source/android-prebuilt-library.md
@@ -0,0 +1,37 @@
+# Using Android prebuilt libraries (AAR)
+
+We provide two prebuilt Android libraries (AAR), `executorch.aar` for generic use case (image/audio processing) and `executorch_llama.aar` for LLAMA use case.
+
+## Contents of libraries
+- `executorch.aar`
+ - [Java library](https://github.com/pytorch/executorch/tree/release/0.2/extension/android/src/main/java/org/pytorch/executorch)
+ - JNI contains the JNI binding for [NativePeer.java](https://github.com/pytorch/executorch/blob/release/0.2/extension/android/src/main/java/org/pytorch/executorch/NativePeer.java) and ExecuTorch native library, including core ExecuTorch runtime libraries, XNNPACK backend, Portable kernels, Optimized kernels, and Quantized kernels.
+ - Comes with two ABI variants, arm64-v8a and x86_64.
+- `executorch_llama.aar`
+ - [Java library](https://github.com/pytorch/executorch/tree/release/0.2/extension/android/src/main/java/org/pytorch/executorch) (Note: it contains the same Java classes as the previous Java, but it does not contain the JNI binding for generic Module/NativePeer Java code).
+ - JNI contains the JNI binding for [LlamaModule.java](https://github.com/pytorch/executorch/blob/release/0.2/extension/android/src/main/java/org/pytorch/executorch/LlamaModule.java) and ExecuTorch native library, including core ExecuTorch runtime libraries, XNNPACK backend, Portable kernels, Optimized kernels, Quantized kernels, and LLAMA-specific Custom ops library.
+ - Comes with two ABI variants, arm64-v8a and x86_64.
+
+## Downloading AAR
+[executorch.aar](https://ossci-android.s3.us-west-1.amazonaws.com/executorch/release/0.2.1/executorch.aar) (sha1sum: af7690394fd978603abeff40cf64bd2df0dc793a)
+[executorch_llama.aar](https://ossci-android.s3.us-west-1.amazonaws.com/executorch/release/0.2.1/executorch-llama.aar) (sha1sum: 2973b1c41aa2c2775482d7cc7c803d0f6ca282c1)
+
+## Using prebuilt libraries
+
+To add the Java library to your app, simply download the AAR, and add it to your gradle build rule.
+
+In your app working directory, such as example executorch/examples/demo-apps/android/LlamaDemo,
+```
+mkdir -p app/libs
+curl https://ossci-android.s3.us-west-1.amazonaws.com/executorch/release/0.2.1/executorch-llama.aar -o app/libs/executorch.aar
+```
+
+And include it in gradle:
+```
+# app/build.grardle.kts
+dependencies {
+ implementation(files("libs/executorch-llama.aar"))
+}
+```
+
+Now you can compile your app with the ExecuTorch Android library.
diff --git a/examples/demo-apps/android/LlamaDemo/.gitignore b/examples/demo-apps/android/LlamaDemo/.gitignore
index e7bee2e2b1c..41853c0472c 100644
--- a/examples/demo-apps/android/LlamaDemo/.gitignore
+++ b/examples/demo-apps/android/LlamaDemo/.gitignore
@@ -9,3 +9,4 @@
.cxx
local.properties
*.so
+*.aar
diff --git a/examples/demo-apps/android/LlamaDemo/README.md b/examples/demo-apps/android/LlamaDemo/README.md
index 0c70ec1620a..6ea0674e7ed 100644
--- a/examples/demo-apps/android/LlamaDemo/README.md
+++ b/examples/demo-apps/android/LlamaDemo/README.md
@@ -27,7 +27,33 @@ adb push tokenizer.bin /data/local/tmp/llama
Note: The demo app searches in `/data/local/tmp/llama` for .pte and .bin files as LLAMA model and tokenizer.
-## Build JNI library
+## Build library
+For the demo app to build, we need to build the ExecuTorch AAR library first.
+
+The AAR library contains the required Java package and the corresponding JNI
+library for using ExecuTorch in your Android app.
+
+### Alternative 1: Use prebuilt AAR library (recommended)
+
+1. Open a terminal window and navigate to the root directory of the `executorch`.
+2. Run the following command to download the prebuilt library:
+```bash
+bash examples/demo-apps/android/LlamaDemo/download_prebuilt_lib.sh
+```
+
+The prebuilt AAR library contains the Java library and the JNI binding for
+NativePeer.java and ExecuTorch native library, including core ExecuTorch
+runtime libraries, XNNPACK backend, Portable kernels, Optimized kernels,
+and Quantized kernels. It comes with two ABI variants, arm64-v8a and x86_64.
+
+If you want to use the prebuilt library for your own app, please refer to
+[Using Android prebuilt libraries (AAR)](./android-prebuilt-library.md) for
+tutorial.
+
+If you need to use other dependencies (like tokenizer), please refer to
+Alternative 2: Build from local machine option.
+
+### Alternative 2: Build from local machine
1. Open a terminal window and navigate to the root directory of the `executorch`.
2. Set the following environment variables:
```bash
diff --git a/examples/demo-apps/android/LlamaDemo/app/build.gradle.kts b/examples/demo-apps/android/LlamaDemo/app/build.gradle.kts
index 5cd35a915a5..b2eb262c7de 100644
--- a/examples/demo-apps/android/LlamaDemo/app/build.gradle.kts
+++ b/examples/demo-apps/android/LlamaDemo/app/build.gradle.kts
@@ -56,9 +56,7 @@ dependencies {
implementation("androidx.camera:camera-core:1.3.0-rc02")
implementation("androidx.constraintlayout:constraintlayout:2.2.0-alpha12")
implementation("com.facebook.fbjni:fbjni:0.5.1")
- implementation("org.pytorch.executorch:executorch") {
- exclude("com.facebook.fbjni", "fbjni-java-only")
- }
+ implementation(files("libs/executorch-llama.aar"))
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
@@ -76,3 +74,12 @@ tasks.register("setup") {
}
}
}
+
+tasks.register("download_prebuilt_lib") {
+ doFirst {
+ exec {
+ commandLine("sh", "examples/demo-apps/android/LlamaDemo/download_prebuilt_lib.sh")
+ workingDir("../../../../../")
+ }
+ }
+}
diff --git a/examples/demo-apps/android/LlamaDemo/download_prebuilt_lib.sh b/examples/demo-apps/android/LlamaDemo/download_prebuilt_lib.sh
new file mode 100644
index 00000000000..43e2bcc14d8
--- /dev/null
+++ b/examples/demo-apps/android/LlamaDemo/download_prebuilt_lib.sh
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD-style license found in the
+# LICENSE file in the root directory of this source tree.
+
+set -eu
+
+AAR_URL="https://ossci-android.s3.us-west-1.amazonaws.com/executorch/release/0.2.1/executorch-llama.aar"
+AAR_SHASUM="2973b1c41aa2c2775482d7cc7c803d0f6ca282c1"
+
+LIBS_PATH="$(dirname "$0")/app/libs"
+AAR_PATH="${LIBS_PATH}/executorch-llama.aar"
+
+mkdir -p "$LIBS_PATH"
+
+if [[ ! -f "${AAR_PATH}" || "${AAR_SHASUM}" != $(shasum "${AAR_PATH}" | awk '{print $1}') ]]; then
+ curl "${AAR_URL}" -o "${AAR_PATH}"
+fi
diff --git a/examples/demo-apps/android/LlamaDemo/settings.gradle.kts b/examples/demo-apps/android/LlamaDemo/settings.gradle.kts
index 40adb48f270..ba0e809fd98 100644
--- a/examples/demo-apps/android/LlamaDemo/settings.gradle.kts
+++ b/examples/demo-apps/android/LlamaDemo/settings.gradle.kts
@@ -25,5 +25,3 @@ dependencyResolutionManagement {
rootProject.name = "ExecuTorch Demo"
include(":app")
-
-includeBuild("../../../../extension/android")
diff --git a/examples/demo-apps/android/LlamaDemo/setup.sh b/examples/demo-apps/android/LlamaDemo/setup.sh
index f515aa22cc7..e47a9ad38ef 100644
--- a/examples/demo-apps/android/LlamaDemo/setup.sh
+++ b/examples/demo-apps/android/LlamaDemo/setup.sh
@@ -47,6 +47,16 @@ cmake extension/android \
cmake --build "${CMAKE_OUT}"/extension/android -j "${CMAKE_JOBS}" --config Release
-JNI_LIBS_PATH="examples/demo-apps/android/LlamaDemo/app/src/main/jniLibs"
-mkdir -p "${JNI_LIBS_PATH}/${ANDROID_ABI}"
-cp "${CMAKE_OUT}"/extension/android/libexecutorch_llama_jni.so "${JNI_LIBS_PATH}/${ANDROID_ABI}/"
+BUILD_AAR_DIR="$(mktemp -d)"
+mkdir -p "${BUILD_AAR_DIR}/jni/${ANDROID_ABI}" "${BUILD_AAR_DIR}/libs"
+cp "${CMAKE_OUT}"/extension/android/libexecutorch_llama_jni.so "${BUILD_AAR_DIR}/jni/${ANDROID_ABI}"
+cp extension/android/build/libs/executorch.jar "${BUILD_AAR_DIR}/libs"
+echo \ \
+ \ \
+ \ > "${BUILD_AAR_DIR}/AndroidManifest.xml"
+pushd "${BUILD_AAR_DIR}"
+zip -r executorch-llama.aar libs jni/${ANDROID_ABI} AndroidManifest.xml
+popd
+mkdir -p examples/demo-apps/android/LlamaDemo/app/libs
+mv "${BUILD_AAR_DIR}/executorch-llama.aar" examples/demo-apps/android/LlamaDemo/app/libs