Skip to content

Android app integration #547

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

Closed
wants to merge 1 commit into from
Closed
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
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,6 @@
[submodule "examples/third-party/llama"]
path = examples/third-party/llama
url = https://github.com/facebookresearch/llama.git
[submodule "examples/demo-apps/android/jni/third-party/fbjni"]
path = examples/demo-apps/android/jni/third-party/fbjni
url = https://github.com/facebookincubator/fbjni.git
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,11 @@ if(EXECUTORCH_BUILD_EXECUTOR_RUNNER)
target_compile_options(executor_runner PUBLIC ${_common_compile_options})
endif()

# Add Android demo app JNI subdirectory
if(EXECUTORCH_BUILD_ANDROID_DEMO_APP_JNI)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/examples/demo-apps/android/jni)
endif()

option(EXECUTORCH_BUILD_EXTENSION_DATA_LOADER
"Build the extension/data_loader directory" OFF)
if(EXECUTORCH_BUILD_EXTENSION_DATA_LOADER)
Expand Down
5 changes: 5 additions & 0 deletions backends/xnnpack/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -100,4 +100,9 @@ if(NOT CMAKE_TOOLCHAIN_FILE MATCHES ".*iOS\.cmake$")
add_executable(xnn_executor_runner ${_xnn_executor_runner__srcs})
target_link_libraries(xnn_executor_runner ${xnn_executor_runner_libs})
target_compile_options(xnn_executor_runner PUBLIC ${_common_compile_options})

add_library(xnn_executor_runner_lib STATIC ${_xnn_executor_runner__srcs})
target_link_libraries(xnn_executor_runner_lib ${xnn_executor_runner_libs})
target_compile_options(xnn_executor_runner_lib
PUBLIC ${_common_compile_options})
endif()
11 changes: 11 additions & 0 deletions build/cmake_deps.toml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,17 @@ filters = [
".fbs$",
]

[targets.print_evalue]
buck_targets = [
"//extension/evalue_util:print_evalue",
]
filters = [
".cpp$",
]
deps = [
"executorch",
]

[targets.size_test]
buck_targets = [
"//test:size_test",
Expand Down
12 changes: 12 additions & 0 deletions examples/demo-apps/android/ExecuTorchDemo/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
*.iml
.gradle
/local.properties
.idea
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties
*.so

121 changes: 121 additions & 0 deletions examples/demo-apps/android/ExecuTorchDemo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# Android Demo App: ExecuTorch Setup

This is forked from [PyTorch android demo app](https://github.com/pytorch/android-demo-app)

This guide explains how to setup ExecuTorch for Android using a demo app. The app employs a DeepLab v3 model for image segmentation tasks and Inception v3 model for image classification tasks. Models are exported to ExecuTorch using XNNPACK FP32 backend.

## Pre-setup

1. Download [Android Studio and SDK](https://developer.android.com/studio).

2. Install buck2 binary (using MacOS Apple Silicon build as example):
```bash
curl -L -O https://github.com/facebook/buck2/releases/download/2023-07-18/buck2-aarch64-apple-darwin.zst
pip3 install zstd
zstd -cdq buck2-aarch64-apple-darwin.zst > /tmp/buck2 && chmod +x /tmp/buck2
```

3. Install and link [Cmake](cmake.org/download) to a system directory or `$PATH`:

```bash
ln -s /Applications/CMake.app/Contents/bin/cmake /usr/bin/cmake
```

4. Clone ExecuTorch repository and update submodules:

```bash
git clone https://github.com/pytorch/executorch.git
cd executorch
git submodule sync
git submodule update --init
```

5. Verify Python 3.10+ (standard since MacOS 13.5) and `pip3` installation:

```bash
which python3 pip
python3 --version
```

6. Install PyTorch dependencies:

```bash
./install_requirements.sh
```

## Flatbuffers Compiler Setup

Run the following in the `flatbuffers` directory:

```bash
cd third-party/flatbuffers
rm -rf cmake-out && mkdir cmake-out && cd cmake-out
cmake .. && cmake --build . --target flatc
cd ../../..
```

## ExecuTorch Configuration

Configure the libraries for Android:

```bash
rm -rf cmake-out && mkdir cmake-out && cd cmake-out
cmake .. \
-DCMAKE_TOOLCHAIN_FILE=/path/to/ndk/build/cmake/android.toolchain.cmake \
-DANDROID_ABI=arm64-v8a \
-DBUCK2=/tmp/buck2 \
-DFLATC_EXECUTABLE=$(realpath ../third-party/flatbuffers/cmake-out/flatc) \
-DEXECUTORCH_BUILD_ANDROID_DEMO_APP_JNI=ON \
-DEXECUTORCH_BUILD_XNNPACK=ON \
-DEXECUTORCH_BUILD_FLATC=OFF \
-DEXECUTORCH_BUILD_EXTENSION_DATA_LOADER=ON
```

## Building and Copying Libraries

1. Build the libraries:

```bash
cmake --build .
```

2. Copy the libraries to the appropriate location to link against them:

Navigate to the build artifacts directory:

```bash
mkdir -p ../examples/demo-apps/android/ExecuTorchDemo/app/src/main/jniLibs/arm64-v8a
```

Copy the core libraries:

```bash
cp ./examples/demo-apps/android/jni/libexecutorchdemo.so \
../examples/demo-apps/android/ExecuTorchDemo/app/src/main/jniLibs/arm64-v8a
```

Later, this shared library will be loaded by `NativePeer.java` in Java code.

Then return to the `executorch` directory:

```bash
cd ..
```

## Model Download and Bundling

1. Export a DeepLab v3 model and Inception v4 model backed with XNNPACK delegate and bundle it with
the app:

```bash
export FLATC_EXECUTABLE=$(realpath third-party/flatbuffers/cmake-out/flatc)
python3 -m examples.backend.xnnpack_examples --model_name="dl3" --delegate
python3 -m examples.backend.xnnpack_examples --model_name="ic4" --delegate
cp dl3_xnnpack_fp32.pte ic4_xnnpack_fp32.pte examples/android_demo_apps/ExecuTorchDemo/app/src/main/assets/
```

## Final Steps

1. Open the project `examples/android_demo_apps/ExecuTorchDemo` with Android Studio.

2. Run the app (^R)
1 change: 1 addition & 0 deletions examples/demo-apps/android/ExecuTorchDemo/app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
59 changes: 59 additions & 0 deletions examples/demo-apps/android/ExecuTorchDemo/app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
}

android {
namespace = "com.example.executorchdemo"
compileSdk = 34

defaultConfig {
applicationId = "com.example.executorchdemo"
minSdk = 24
targetSdk = 33
versionCode = 1
versionName = "1.0"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables { useSupportLibrary = true }
externalNativeBuild { cmake { cppFlags += "" } }
}

buildTypes {
release {
isMinifyEnabled = false
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions { jvmTarget = "1.8" }
buildFeatures { compose = true }
composeOptions { kotlinCompilerExtensionVersion = "1.4.3" }
packaging { resources { excludes += "/META-INF/{AL2.0,LGPL2.1}" } }
}

dependencies {
implementation("androidx.core:core-ktx:1.9.0")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.1")
implementation("androidx.activity:activity-compose:1.7.0")
implementation(platform("androidx.compose:compose-bom:2023.03.00"))
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.ui:ui-graphics")
implementation("androidx.compose.ui:ui-tooling-preview")
implementation("androidx.compose.material3:material3")
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("androidx.camera:camera-core:1.3.0-rc02")
implementation("androidx.constraintlayout:constraintlayout:2.2.0-alpha12")
implementation("com.facebook.soloader:soloader:0.10.5")
implementation("com.facebook.fbjni:fbjni:0.5.1")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
androidTestImplementation(platform("androidx.compose:compose-bom:2023.03.00"))
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
debugImplementation("androidx.compose.ui:ui-tooling")
debugImplementation("androidx.compose.ui:ui-test-manifest")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />

<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.ExecuTorchDemo"
android:extractNativeLibs="true"
tools:targetApi="31">

<uses-native-library android:name="libexecutorchdemo.so"
android:required="false"/>

<uses-native-library android:name="libcdsprpc.so"
android:required="false"/>

<uses-native-library android:name="libQnnHtp.so"
android:required="false"/>

<uses-native-library android:name="libQnnHtpV69Skel.so"
android:required="false"/>

<uses-native-library android:name="libQnnHtpV69Stub.so"
android:required="false"/>

<uses-native-library android:name="libQnnSystem.so"
android:required="false"/>

<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.ExecuTorchDemo">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".ClassificationActivity"
android:label="@string/app_name"
android:theme="@style/Theme.ExecuTorchDemo">
</activity>

</application>

</manifest>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading