(*icu_cleanup_fn)();
Runtime::Current()->GetHeap()->VerifyHeap(); // Check for heap corruption after the test
-
- // Manually closing the JNI libraries.
- // Runtime does not support repeatedly doing JNI->CreateVM, thus we need to manually clean up the
- // dynamic linking loader so that gtests would not fail.
- // Bug: 25785594
- if (runtime_->IsStarted()) {
- {
- // We retrieve the handle by calling dlopen on the library. To close it, we need to call
- // dlclose twice, the first time to undo our dlopen and the second time to actually unload it.
- // See man dlopen.
- void* handle = dlopen("libjavacore.so", RTLD_LAZY);
- dlclose(handle);
- CHECK_EQ(0, dlclose(handle));
- }
- {
- void* handle = dlopen("libopenjdkd.so", RTLD_LAZY);
- dlclose(handle);
- CHECK_EQ(0, dlclose(handle));
- }
- }
}
static std::string GetDexFileName(const std::string& jar_prefix, bool host) {
if (self != nullptr) {
self->GetJniEnv()->DeleteWeakGlobalRef(class_loader_);
}
+
+ if (!needs_native_bridge_) {
+ android::CloseNativeLibrary(handle_);
+ }
}
jweak GetClassLoader() const {
REQUIRES(!Locks::jni_libraries_lock_)
SHARED_REQUIRES(Locks::mutator_lock_) {
ScopedObjectAccessUnchecked soa(Thread::Current());
- typedef void (*JNI_OnUnloadFn)(JavaVM*, void*);
- std::vector<JNI_OnUnloadFn> unload_functions;
+ std::vector<SharedLibrary*> unload_libraries;
{
MutexLock mu(soa.Self(), *Locks::jni_libraries_lock_);
for (auto it = libraries_.begin(); it != libraries_.end(); ) {
// the native libraries of the boot class loader.
if (class_loader != nullptr &&
soa.Self()->IsJWeakCleared(class_loader)) {
- void* const sym = library->FindSymbol("JNI_OnUnload", nullptr);
- if (sym == nullptr) {
- VLOG(jni) << "[No JNI_OnUnload found in \"" << library->GetPath() << "\"]";
- } else {
- VLOG(jni) << "[JNI_OnUnload found for \"" << library->GetPath() << "\"]";
- JNI_OnUnloadFn jni_on_unload = reinterpret_cast<JNI_OnUnloadFn>(sym);
- unload_functions.push_back(jni_on_unload);
- }
- delete library;
+ unload_libraries.push_back(library);
it = libraries_.erase(it);
} else {
++it;
}
}
// Do this without holding the jni libraries lock to prevent possible deadlocks.
- for (JNI_OnUnloadFn fn : unload_functions) {
- VLOG(jni) << "Calling JNI_OnUnload";
- (*fn)(soa.Vm(), nullptr);
+ typedef void (*JNI_OnUnloadFn)(JavaVM*, void*);
+ for (auto library : unload_libraries) {
+ void* const sym = library->FindSymbol("JNI_OnUnload", nullptr);
+ if (sym == nullptr) {
+ VLOG(jni) << "[No JNI_OnUnload found in \"" << library->GetPath() << "\"]";
+ } else {
+ VLOG(jni) << "[JNI_OnUnload found for \"" << library->GetPath() << "\"]: Calling...";
+ JNI_OnUnloadFn jni_on_unload = reinterpret_cast<JNI_OnUnloadFn>(sym);
+ jni_on_unload(soa.Vm(), nullptr);
+ }
+ delete library;
}
}
namespace {
static volatile std::atomic<bool> vm_was_shutdown(false);
+static const int kThreadCount = 4;
+
+static std::atomic<int> barrier_count(kThreadCount + 1);
+
+static void JniThreadBarrierWait() {
+ barrier_count--;
+ while (barrier_count.load() != 0) {
+ usleep(1000);
+ }
+}
extern "C" JNIEXPORT void JNICALL Java_Main_waitAndCallIntoJniEnv(JNIEnv* env, jclass) {
+ // Wait for all threads to enter JNI together.
+ JniThreadBarrierWait();
// Wait until the runtime is shutdown.
while (!vm_was_shutdown.load()) {
usleep(1000);
// NO_RETURN does not work with extern "C" for target builds.
extern "C" JNIEXPORT void JNICALL Java_Main_destroyJavaVMAndExit(JNIEnv* env, jclass) {
+ // Wait for all threads to enter JNI together.
+ JniThreadBarrierWait();
// Fake up the managed stack so we can detach.
Thread* const self = Thread::Current();
self->SetTopOfStack(nullptr);