66#else
77 // UNIX Dependencies
88# include < dlfcn.h>
9+ # include < unistd.h>
10+ # include < tuple>
911#endif
1012
1113// External Dependencies
@@ -24,6 +26,10 @@ namespace jni
2426 static std::atomic_bool isVm (false );
2527 static JavaVM* javaVm = nullptr ;
2628
29+ static bool isAttached (JavaVM *vm) {
30+ JNIEnv *env = nullptr ;
31+ return vm->GetEnv ((void **)&env, JNI_VERSION_1_2) == JNI_OK;
32+ }
2733 /* *
2834 Maintains the lifecycle of a JNIEnv.
2935 */
@@ -57,7 +63,7 @@ namespace jni
5763 if (vm == nullptr )
5864 throw InitializationException (" JNI not initialized" );
5965
60- if (vm-> GetEnv (( void **)&_env, JNI_VERSION_1_2) != JNI_OK )
66+ if (! isAttached (vm) )
6167 {
6268#ifdef __ANDROID__
6369 if (vm->AttachCurrentThread (&_env, nullptr ) != 0 )
@@ -150,8 +156,17 @@ namespace jni
150156 {
151157 static thread_local ScopedEnv env;
152158
159+ if (env.get () != nullptr && !isAttached (javaVm))
160+ {
161+ // we got detached, so clear it.
162+ // will be re-populated from static javaVm below.
163+ env = ScopedEnv{};
164+ }
165+
153166 if (env.get () == nullptr )
167+ {
154168 env.init (javaVm);
169+ }
155170
156171 return env.get ();
157172 }
@@ -1270,7 +1285,57 @@ namespace jni
12701285
12711286 typedef jint (JNICALL *CreateVm_t)(JavaVM**, void **, void *);
12721287
1288+ #ifndef _WIN32
1289+ static bool fileExists (const std::string& filePath)
1290+ {
1291+ return access (filePath.c_str (), F_OK) != -1 ;
1292+ }
1293+
1294+ template <size_t N>
1295+ static ssize_t readlink_safe (const char *pathname, char (&output)[N]) {
1296+ auto len = readlink (pathname, output, N - 1 );
1297+ if (len > 0 ) {
1298+ output[len] = ' \0 ' ;
1299+ }
1300+ return len;
1301+ }
12731302
1303+ static std::pair<ssize_t , std::string>
1304+ readlink_as_string (const char *pathname) {
1305+ char buf[2048 ] = {};
1306+ auto len = readlink_safe (pathname, buf);
1307+ if (len <= 0 ) {
1308+ return {len, {}};
1309+ }
1310+ return {len, std::string{buf, static_cast <size_t >(len)}};
1311+ }
1312+ static std::string readlink_deep (const char *pathname) {
1313+ std::string prev{pathname};
1314+ ssize_t len = 0 ;
1315+ std::string next;
1316+ while (true ) {
1317+ std::tie (len, next) = readlink_as_string (prev.c_str ());
1318+ if (!next.empty ()) {
1319+ prev = next;
1320+ } else {
1321+ return prev;
1322+ }
1323+ }
1324+ }
1325+
1326+ static std::string drop_path_components (const std::string & path, size_t num_components) {
1327+ size_t pos = std::string::npos;
1328+ size_t slash_pos = std::string::npos;
1329+ for (size_t i = 0 ; i < num_components; ++i) {
1330+ slash_pos = path.find_last_of (' /' , pos);
1331+ if (slash_pos == std::string::npos || slash_pos == 0 ) {
1332+ return {};
1333+ }
1334+ pos = slash_pos - 1 ;
1335+ }
1336+ return std::string{path.c_str (), slash_pos};
1337+ }
1338+ #endif
12741339 static std::string detectJvmPath ()
12751340 {
12761341 std::string result;
@@ -1321,7 +1386,7 @@ namespace jni
13211386 javaHome + " \\ bin\\ server\\ jvm.dll"
13221387 };
13231388
1324- for (auto i : options)
1389+ for (auto const & i : options)
13251390 if (fileExists (i))
13261391 return i;
13271392 }
@@ -1338,6 +1403,28 @@ namespace jni
13381403 #endif
13391404 result = libJvmPath;
13401405 } else {
1406+ std::string path = readlink_deep (" /usr/bin/java" );
1407+ if (!path.empty ()) {
1408+ // drop bin and java
1409+ auto javaHome = drop_path_components (path, 2 );
1410+ if (!javaHome.empty ()) {
1411+ std::string options[] = {
1412+ javaHome + " /jre/lib/amd64/server/libjvm.so" ,
1413+ javaHome + " /jre/lib/amd64/client/libjvm.so" ,
1414+ javaHome + " /jre/lib/server/libjvm.so" ,
1415+ javaHome + " /jre/lib/client/libjvm.so" ,
1416+ javaHome + " /lib/server/libjvm.so" ,
1417+ javaHome + " /lib/client/libjvm.so" ,
1418+ };
1419+
1420+ for (auto const &i : options) {
1421+ fprintf (stderr, " trying %s\n " , i.c_str ());
1422+ if (fileExists (i)) {
1423+ return i;
1424+ }
1425+ }
1426+ }
1427+ }
13411428 // Best guess so far.
13421429 result = " /usr/lib/jvm/default-java/jre/lib/amd64/server/libjvm.so" ;
13431430 }
@@ -1388,6 +1475,7 @@ namespace jni
13881475 }
13891476
13901477#else
1478+ fprintf (stderr, " opening %s\n " , path.c_str ());
13911479
13921480 void * lib = ::dlopen (path.c_str (), RTLD_NOW | RTLD_GLOBAL);
13931481
0 commit comments