Skip to content
This repository has been archived by the owner on Mar 26, 2020. It is now read-only.

Commit

Permalink
[Android] Fix Djinni initialization crash in multi shared library case (
Browse files Browse the repository at this point in the history
#310)

Fix Djinni initialization crash in multi shared library case on Android (i.e. djinni_support_lib is a shared library used by other shared libraries).

Replaced generic static_registration class with non-templatized helpers in JniClassInitializer, which simplifies the code and avoids the issues of multiple instantiations of the same static data.
  • Loading branch information
Guillaume227 authored and artwyman committed Jun 28, 2017
1 parent bca8b4b commit b55ac10
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 32 deletions.
27 changes: 25 additions & 2 deletions support-lib/jni/djinni_support.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,35 @@ namespace djinni {
// Set only once from JNI_OnLoad before any other JNI calls, so no lock needed.
static JavaVM * g_cachedJVM;

/*static*/
JniClassInitializer::registration_vec & JniClassInitializer::get_vec() {
static JniClassInitializer::registration_vec m;
return m;
}

/*static*/
std::mutex & JniClassInitializer::get_mutex() {
static std::mutex mtx;
return mtx;
}

/*static*/
JniClassInitializer::registration_vec JniClassInitializer::get_all() {
const std::lock_guard<std::mutex> lock(get_mutex());
return get_vec();
}

JniClassInitializer::JniClassInitializer(std::function<void()> init) {
const std::lock_guard<std::mutex> lock(get_mutex());
get_vec().push_back(std::move(init));
}

void jniInit(JavaVM * jvm) {
g_cachedJVM = jvm;

try {
for (const auto & kv : JniClassInitializer::Registration::get_all()) {
kv.second->init();
for (const auto & initializer : JniClassInitializer::get_all()) {
initializer();
}
} catch (const std::exception & e) {
// Default exception handling only, since non-default might not be safe if init
Expand Down
41 changes: 11 additions & 30 deletions support-lib/jni/djinni_support.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
#include <memory>
#include <mutex>
#include <string>
#include <unordered_map>
#include <vector>

#include "../proxy_cache_interface.hpp"
#include "../djinni_common.hpp"
Expand Down Expand Up @@ -165,42 +165,23 @@ void jniThrowAssertionError(JNIEnv * env, const char * file, int line, const cha
} while(false)
#define DJINNI_ASSERT(check, env) DJINNI_ASSERT_MSG(check, env, #check)

/*
* Helper for JniClassInitializer.
*/
template <class Key, class T>
class static_registration {
public:
using registration_map = std::unordered_map<Key, T *>;
static registration_map get_all() {
const std::lock_guard<std::mutex> lock(get_mutex());
return get_map();
}
static_registration(const Key & key, T * obj) : m_key(key) {
const std::lock_guard<std::mutex> lock(get_mutex());
get_map().emplace(key, obj);
}
~static_registration() {
const std::lock_guard<std::mutex> lock(get_mutex());
get_map().erase(m_key);
}
private:
const Key m_key;
static registration_map & get_map() { static registration_map m; return m; }
static std::mutex & get_mutex() { static std::mutex mtx; return mtx; }
};

/*
* Helper for JniClass. (This can't be a subclass because it needs to not be templatized.)
*/
class JniClassInitializer {

using registration_vec = std::vector<std::function<void()>>;
static registration_vec get_all();

private:
using Registration = static_registration<void *, const JniClassInitializer>;
const std::function<void()> init;
const Registration reg;
JniClassInitializer(const std::function<void()> & init) : init(init), reg(this, this) {}

JniClassInitializer(std::function<void()> init);

template <class C> friend class JniClass;
friend void jniInit(JavaVM *);

static registration_vec & get_vec();
static std::mutex & get_mutex();
};

/*
Expand Down

0 comments on commit b55ac10

Please sign in to comment.