Skip to content

Android improve prebuilt workflow and provide tutorial #3841

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jun 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .github/workflows/android.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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/**
Expand Down Expand Up @@ -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

Expand All @@ -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:
Expand Down
89 changes: 89 additions & 0 deletions build/build_android_library.sh
Original file line number Diff line number Diff line change
@@ -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 \<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\" \
package=\"org.pytorch.executorch\"\> \
\<uses-sdk android:minSdkVersion=\"19\" /\> \
\</manifest\> > "${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
32 changes: 4 additions & 28 deletions build/test_android_ci.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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 \<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\" \
package=\"org.pytorch.executorch\"\> \
\<uses-sdk android:minSdkVersion=\"19\" /\> \
\</manifest\> > 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
37 changes: 37 additions & 0 deletions docs/source/android-prebuilt-library.md
Original file line number Diff line number Diff line change
@@ -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.
1 change: 1 addition & 0 deletions examples/demo-apps/android/LlamaDemo/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@
.cxx
local.properties
*.so
*.aar
28 changes: 27 additions & 1 deletion examples/demo-apps/android/LlamaDemo/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 10 additions & 3 deletions examples/demo-apps/android/LlamaDemo/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -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("../../../../../")
}
}
}
20 changes: 20 additions & 0 deletions examples/demo-apps/android/LlamaDemo/download_prebuilt_lib.sh
Original file line number Diff line number Diff line change
@@ -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
2 changes: 0 additions & 2 deletions examples/demo-apps/android/LlamaDemo/settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,3 @@ dependencyResolutionManagement {
rootProject.name = "ExecuTorch Demo"

include(":app")

includeBuild("../../../../extension/android")
16 changes: 13 additions & 3 deletions examples/demo-apps/android/LlamaDemo/setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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 \<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\" \
package=\"org.pytorch.executorch\"\> \
\<uses-sdk android:minSdkVersion=\"19\" /\> \
\</manifest\> > "${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
Loading