Skip to content

Commit

Permalink
jni: Add EnvoyEngine layer for library development (#158)
Browse files Browse the repository at this point in the history
For an explanation of how to fill out the fields, please see the relevant section
in [PULL_REQUESTS.md](https://github.com/envoyproxy/envoy/blob/master/PULL_REQUESTS.md)

Description: Add EnvoyEngine layer for library development
Risk Level: low
Testing: ci, local
Docs Changes: na
Release Notes: na
[Optional Fixes #Issue]
[Optional Deprecated:]

Signed-off-by: JP Simard <jp@jpsim.com>
  • Loading branch information
Alan Chiu authored and jpsim committed Nov 29, 2022
1 parent 2793409 commit d88ba47
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 133 deletions.
36 changes: 16 additions & 20 deletions mobile/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -36,36 +36,32 @@ aar_with_jni(
visibility = ["//visibility:public"],
)

kt_android_library(
name = "android_lib",
srcs = [
"library/java/io/envoyproxy/envoymobile/Envoy.java",
"library/java/io/envoyproxy/envoymobile/EnvoyEmptyClass.kt",
],
android_library(
name = "envoy_engine_lib",
srcs = ["library/java/io/envoyproxy/envoymobile/EnvoyEngine.java"],
custom_package = "io.envoyproxy.envoymobile",
manifest = "library/EnvoyManifest.xml",
deps = ["java_cc_alias"],
deps = ["//library/common:envoy_jni_interface_lib"],
)

# Work around for transitive dependencies related to not including cc_libraries for kt_jvm_library
# Related to: https://github.com/bazelbuild/rules_kotlin/issues/132
#
# This work around is to use an empty java_library to include the cc_library dependencies needed
# for the kotlin jni layer
android_library(
name = "java_cc_alias",
srcs = ["library/kotlin/io/envoyproxy/envoymobile/EnvoyKotlinEmptyClass.java"],
custom_package = "io.envoyproxy.envoymobile",
manifest = "library/EnvoyManifest.xml",
deps = ["//library/common:envoy_jni_interface_lib"],
)

# Android library drops exported dependencies from dependent rules. The kt_android_library
# internally is just a macro which wraps two rules into one:
# https://github.com/bazelbuild/rules_kotlin/blob/326661e7e705d14e754abc2765837aa61bddf205/kotlin/internal/jvm/android.bzl#L28.
# This causes the sources to be exported and dropped due to it being a transitive dependency.
# To get around this, we have to redeclare the sources from envoy_engine_lib here in order to be pulled into the
# kotlin jar.
kt_android_library(
name = "android_lib_kotlin",
srcs = ["library/kotlin/io/envoyproxy/envoymobile/Envoy.kt"],
name = "android_lib",
srcs = [
"library/java/io/envoyproxy/envoymobile/EnvoyEngine.java",
"library/kotlin/io/envoyproxy/envoymobile/Envoy.kt",
],
custom_package = "io.envoyproxy.envoymobile",
manifest = "library/EnvoyManifest.xml",
deps = ["java_cc_alias"],
deps = ["envoy_engine_lib"],
)

genrule(
Expand Down
14 changes: 7 additions & 7 deletions mobile/library/common/jni_interface.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,21 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
return JNI_VERSION_1_6;
}

extern "C" JNIEXPORT jint JNICALL Java_io_envoyproxy_envoymobile_Envoy_run(JNIEnv* env,
jobject, // this
jstring config) {
extern "C" JNIEXPORT jint JNICALL Java_io_envoyproxy_envoymobile_EnvoyEngine_run(JNIEnv* env,
jobject, // this
jstring config) {
return run_envoy(env->GetStringUTFChars(config, nullptr));
}

extern "C" JNIEXPORT jint JNICALL
Java_io_envoyproxy_envoymobile_Envoy_initialize(JNIEnv* env,
jclass, // class
jobject connectivity_manager) {
Java_io_envoyproxy_envoymobile_EnvoyEngine_initialize(JNIEnv* env,
jclass, // class
jobject connectivity_manager) {
// See note above about c-ares.
return ares_library_init_android(connectivity_manager);
}

extern "C" JNIEXPORT jboolean JNICALL Java_io_envoyproxy_envoymobile_Envoy_isAresInitialized(
extern "C" JNIEXPORT jboolean JNICALL Java_io_envoyproxy_envoymobile_EnvoyEngine_isAresInitialized(
JNIEnv* env,
jclass // class
) {
Expand Down
75 changes: 0 additions & 75 deletions mobile/library/java/io/envoyproxy/envoymobile/Envoy.java

This file was deleted.

This file was deleted.

39 changes: 39 additions & 0 deletions mobile/library/java/io/envoyproxy/envoymobile/EnvoyEngine.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package io.envoyproxy.envoymobile;

import android.content.Context;
import android.net.ConnectivityManager;

public class EnvoyEngine {

// Internal reference to helper object used to load and initialize the native library.
// Volatile to ensure double-checked locking works correctly.
private static volatile EnvoyEngine loader = null;

// Private helper class used by the load method to ensure the native library and its
// dependencies are loaded and initialized at most once.
private EnvoyEngine(Context context) {
System.loadLibrary("envoy_jni");
initialize((ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE));
}

// Load and initialize Envoy and its dependencies, but only once.
public static void load(Context context) {
if (loader != null) {
return;
}

synchronized (EnvoyEngine.class) {
if (loader != null) {
return;
}

loader = new EnvoyEngine(context);
}
}

private static native int initialize(ConnectivityManager connectivityManager);

private static native boolean isAresInitialized();

public static native int run(String config);
}
48 changes: 35 additions & 13 deletions mobile/library/kotlin/io/envoyproxy/envoymobile/Envoy.kt
Original file line number Diff line number Diff line change
@@ -1,25 +1,47 @@
package io.envoyproxy.envoymobile

import android.content.Context
import android.net.ConnectivityManager
import io.envoyproxy.envoymobile.EnvoyEngine

class Envoy {
// Wrapper class that allows for easy calling of Envoy's JNI interface in native Java.
class Envoy(
context: Context,
config: String
) {

fun load() {
System.loadLibrary("envoy_jni")
}
// Dedicated thread for running this instance of Envoy.
private val runner: Thread

// Create a new Envoy instance. The Envoy runner Thread is started as part of instance
// initialization with the configuration provided. If the Envoy native library and its
// dependencies haven't been loaded and initialized yet, this will happen lazily when
// the first instance is created.
init {
// Lazily initialize Envoy and its dependencies, if necessary.
load(context)

fun run(context: Context, config: String) {
val thread = Thread(Runnable {
initialize(context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager)
runEnvoy(config.trim())
runner = Thread(Runnable {
EnvoyEngine.run(config.trim())
})
thread.start()

runner.start()
}

private external fun initialize(connectivityManager: ConnectivityManager): Int
// Returns whether the Envoy instance is currently active and running.
fun isRunning(): Boolean {
val state = runner.state
return state != Thread.State.NEW && state != Thread.State.TERMINATED
}

private external fun isAresInitialized(): Boolean
// Returns whether the Envoy instance is terminated.
fun isTerminated(): Boolean {
return runner.state == Thread.State.TERMINATED
}

private external fun runEnvoy(config: String): Int
companion object {
@JvmStatic
fun load(context: Context) {
EnvoyEngine.load(context)
}
}
}

This file was deleted.

0 comments on commit d88ba47

Please sign in to comment.