Skip to content

Commit 52d7778

Browse files
authored
[Android] Add Java runtime API for registered ops and backends
Differential Revision: D75195745 Pull Request resolved: #11042
1 parent d1808c1 commit 52d7778

File tree

7 files changed

+131
-4
lines changed

7 files changed

+131
-4
lines changed

extension/android/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ set(executorch_DIR ${CMAKE_CURRENT_BINARY_DIR}/../../lib/cmake/ExecuTorch)
6464
find_package(executorch CONFIG REQUIRED)
6565
target_link_options_shared_lib(executorch)
6666

67-
add_library(executorch_jni SHARED jni/jni_layer.cpp jni/log.cpp)
67+
add_library(executorch_jni SHARED jni/jni_layer.cpp jni/log.cpp jni/jni_layer_runtime.cpp)
6868

6969
set(link_libraries)
7070
list(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
package org.pytorch.executorch;
10+
11+
import static org.junit.Assert.assertNotNull;
12+
13+
import androidx.test.ext.junit.runners.AndroidJUnit4;
14+
import org.junit.runner.RunWith;
15+
import org.junit.Test;
16+
17+
/** Unit tests for {@link ExecuTorchRuntime}. */
18+
@RunWith(AndroidJUnit4.class)
19+
public class RuntimeInstrumentationTest {
20+
21+
@Test
22+
public void testRuntimeApi() {
23+
String[] ops = ExecuTorchRuntime.getRegisteredOps();
24+
String[] backends = ExecuTorchRuntime.getRegisteredBackends();
25+
26+
assertNotNull(ops);
27+
assertNotNull(backends);
28+
29+
for (String op : ops) {
30+
assertNotNull(op);
31+
}
32+
33+
for (String backend : backends) {
34+
assertNotNull(backend);
35+
}
36+
}
37+
}

extension/android/executorch_android/src/main/java/org/pytorch/executorch/ExecuTorchRuntime.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
package org.pytorch.executorch;
1010

11+
import com.facebook.jni.annotations.DoNotStrip;
1112
import com.facebook.soloader.nativeloader.NativeLoader;
1213
import com.facebook.soloader.nativeloader.SystemDelegate;
1314

@@ -30,4 +31,12 @@ private ExecuTorchRuntime() {}
3031
public static ExecuTorchRuntime getRuntime() {
3132
return sInstance;
3233
}
34+
35+
/** Get all registered ops. */
36+
@DoNotStrip
37+
public static native String[] getRegisteredOps();
38+
39+
/** Get all registered backends. */
40+
@DoNotStrip
41+
public static native String[] getRegisteredBackends();
3342
}

extension/android/jni/BUCK

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ non_fbcode_target(_kind = executorch_generated_lib,
2828

2929
non_fbcode_target(_kind = fb_android_cxx_library,
3030
name = "executorch_jni",
31-
srcs = ["jni_layer.cpp", "log.cpp"],
31+
srcs = ["jni_layer.cpp", "log.cpp", "jni_layer_runtime.cpp"],
3232
allow_jni_merging = False,
3333
compiler_flags = ET_JNI_COMPILER_FLAGS,
3434
soname = "libexecutorch.$(ext)",
@@ -49,7 +49,7 @@ non_fbcode_target(_kind = fb_android_cxx_library,
4949

5050
non_fbcode_target(_kind = fb_android_cxx_library,
5151
name = "executorch_jni_full",
52-
srcs = ["jni_layer.cpp", "log.cpp"],
52+
srcs = ["jni_layer.cpp", "log.cpp", "jni_layer_runtime.cpp"],
5353
allow_jni_merging = False,
5454
compiler_flags = ET_JNI_COMPILER_FLAGS,
5555
soname = "libexecutorch.$(ext)",
@@ -74,6 +74,7 @@ non_fbcode_target(_kind = fb_android_cxx_library,
7474
srcs = [
7575
"jni_layer.cpp",
7676
"jni_layer_llama.cpp",
77+
"jni_layer_runtime.cpp",
7778
],
7879
allow_jni_merging = False,
7980
compiler_flags = ET_JNI_COMPILER_FLAGS + [
@@ -113,6 +114,10 @@ runtime.export_file(
113114
name = "jni_layer.cpp",
114115
)
115116

117+
runtime.export_file(
118+
name = "jni_layer_runtime.cpp",
119+
)
120+
116121
runtime.cxx_library(
117122
name = "jni_headers",
118123
exported_headers = [

extension/android/jni/jni_layer.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,9 +491,11 @@ extern void register_natives_for_llm();
491491
// No op if we don't build LLM
492492
void register_natives_for_llm() {}
493493
#endif
494+
extern void register_natives_for_runtime();
494495
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) {
495496
return facebook::jni::initialize(vm, [] {
496497
executorch::extension::ExecuTorchJni::registerNatives();
497498
register_natives_for_llm();
499+
register_natives_for_runtime();
498500
});
499501
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
#include <fbjni/fbjni.h>
10+
#include <jni.h>
11+
12+
#include <executorch/runtime/backend/interface.h>
13+
#include <executorch/runtime/kernel/operator_registry.h>
14+
15+
namespace executorch_jni {
16+
namespace runtime = ::executorch::ET_RUNTIME_NAMESPACE;
17+
18+
class AndroidRuntimeJni : public facebook::jni::JavaClass<AndroidRuntimeJni> {
19+
public:
20+
constexpr static const char* kJavaDescriptor =
21+
"Lorg/pytorch/executorch/ExecuTorchRuntime;";
22+
23+
static void registerNatives() {
24+
javaClassStatic()->registerNatives({
25+
makeNativeMethod(
26+
"getRegisteredOps", AndroidRuntimeJni::getRegisteredOps),
27+
makeNativeMethod(
28+
"getRegisteredBackends", AndroidRuntimeJni::getRegisteredBackends),
29+
});
30+
}
31+
32+
// Returns a string array of all registered ops
33+
static facebook::jni::local_ref<facebook::jni::JArrayClass<jstring>>
34+
getRegisteredOps(facebook::jni::alias_ref<jclass>) {
35+
auto kernels = runtime::get_registered_kernels();
36+
auto result = facebook::jni::JArrayClass<jstring>::newArray(kernels.size());
37+
38+
for (size_t i = 0; i < kernels.size(); ++i) {
39+
auto op = facebook::jni::make_jstring(kernels[i].name_);
40+
result->setElement(i, op.get());
41+
}
42+
43+
return result;
44+
}
45+
46+
// Returns a string array of all registered backends
47+
static facebook::jni::local_ref<facebook::jni::JArrayClass<jstring>>
48+
getRegisteredBackends(facebook::jni::alias_ref<jclass>) {
49+
int num_backends = runtime::get_num_registered_backends();
50+
auto result = facebook::jni::JArrayClass<jstring>::newArray(num_backends);
51+
52+
for (int i = 0; i < num_backends; ++i) {
53+
auto name_result = runtime::get_backend_name(i);
54+
const char* name = "";
55+
56+
if (name_result.ok()) {
57+
name = *name_result;
58+
}
59+
60+
auto backend_str = facebook::jni::make_jstring(name);
61+
result->setElement(i, backend_str.get());
62+
}
63+
64+
return result;
65+
}
66+
};
67+
68+
} // namespace executorch_jni
69+
70+
void register_natives_for_runtime() {
71+
executorch_jni::AndroidRuntimeJni::registerNatives();
72+
}

extension/android/jni/selective_jni.buck.bzl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ load("@fbsource//xplat/executorch/backends/xnnpack/third-party:third_party_libs.
44
load("@fbsource//xplat/executorch/extension/android/jni:build_defs.bzl", "ET_JNI_COMPILER_FLAGS")
55

66
def selective_jni_target(name, deps, srcs = [], soname = "libexecutorch.$(ext)"):
7-
non_fbcode_target(_kind = fb_android_cxx_library,
7+
non_fbcode_target(
8+
_kind = fb_android_cxx_library,
89
name = name,
910
srcs = [
1011
"//xplat/executorch/extension/android/jni:jni_layer.cpp",
12+
"//xplat/executorch/extension/android/jni:jni_layer_runtime.cpp",
1113
] + srcs,
1214
allow_jni_merging = False,
1315
compiler_flags = ET_JNI_COMPILER_FLAGS,

0 commit comments

Comments
 (0)