static constexpr size_t kMonitorsInitial = 32; // Arbitrary. static constexpr size_t kMonitorsMax = 4096; // Maximum number of monitors held by JNI code.
jint JNIEnvExt::GetEnvHandler(JavaVMExt* vm, /*out*/void** env, jint version) {
UNUSED(vm); // GetEnv always returns a JNIEnv* for the most current supported JNI version, // and unlike other calls that take a JNI version doesn't care if you supply // JNI_VERSION_1_1, which we don't otherwise support. if (JavaVMExt::IsBadJniVersion(version) && version != JNI_VERSION_1_1) { return JNI_EVERSION;
}
Thread* thread = Thread::Current();
CHECK(thread != nullptr);
*env = thread->GetJniEnv(); return JNI_OK;
}
void JNIEnvExt::SetCheckJniEnabled(bool enabled) {
check_jni_ = enabled;
locals_.SetCheckJniEnabled(enabled);
MutexLock mu(Thread::Current(), *Locks::jni_function_table_lock_);
functions = GetFunctionTable(enabled); // Check whether this is a no-op because of override. if (enabled && JNIEnvExt::table_override_ != nullptr) {
LOG(WARNING) << "Enabling CheckJNI after a JNIEnv function table override is not functional.";
}
}
// Note: the offset code is brittle, as we can't use OFFSETOF_MEMBER or offsetof easily. Thus, there // are tests in jni_internal_test to match the results against the actual values.
// This is encoding the knowledge of the structure and layout of JNIEnv fields. static size_t JNIEnvSize(PointerSize pointer_size) { // A single pointer. returnstatic_cast<size_t>(pointer_size);
}
// Use some defining part of the caller's frame as the identifying mark for the JNI segment. static uintptr_t GetJavaCallFrame(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_) {
NthCallerVisitor zeroth_caller(self, 0, false);
zeroth_caller.WalkStack(); if (zeroth_caller.caller == nullptr) { // No Java code, must be from pure native code. return0;
} elseif (zeroth_caller.GetCurrentQuickFrame() == nullptr) { // Shadow frame = interpreter. Use the actual shadow frame's address.
DCHECK(zeroth_caller.GetCurrentShadowFrame() != nullptr); returnreinterpret_cast<uintptr_t>(zeroth_caller.GetCurrentShadowFrame());
} else { // Quick frame = compiled code. Use the bottom of the frame. returnreinterpret_cast<uintptr_t>(zeroth_caller.GetCurrentQuickFrame());
}
}
static std::string ComputeMonitorDescription(Thread* self,
jobject obj) REQUIRES_SHARED(Locks::mutator_lock_) {
ObjPtr<mirror::Object> o = self->DecodeJObject(obj); if ((o->GetLockWord(false).GetState() == LockWord::kThinLocked) &&
Locks::mutator_lock_->IsExclusiveHeld(self)) { // Getting the identity hashcode here would result in lock inflation and suspension of the // current thread, which isn't safe if this is the only runnable thread. return StringPrintf("<@addr=0x%" PRIxPTR "> (a %s)", reinterpret_cast<intptr_t>(o.Ptr()),
o->PrettyTypeOf().c_str());
} else { // IdentityHashCode can cause thread suspension, which would invalidate o if it moved. So // we get the pretty type before we call IdentityHashCode. const std::string pretty_type(o->PrettyTypeOf()); return StringPrintf("<0x%08x> (a %s)", o->IdentityHashCode(), pretty_type.c_str());
}
}
void JNIEnvExt::CheckMonitorRelease(jobject obj) {
uintptr_t current_frame = GetJavaCallFrame(self_);
std::pair<uintptr_t, jobject> exact_pair = std::make_pair(current_frame, obj); auto it = std::find(locked_objects_.begin(), locked_objects_.end(), exact_pair); bool will_abort = false; if (it != locked_objects_.end()) {
locked_objects_.erase(it);
} else { // Check whether this monitor was locked in another JNI "session."
ObjPtr<mirror::Object> mirror_obj = self_->DecodeJObject(obj); for (std::pair<uintptr_t, jobject>& pair : locked_objects_) { if (self_->DecodeJObject(pair.second) == mirror_obj) {
std::string monitor_descr = ComputeMonitorDescription(self_, pair.second);
vm_->JniAbortF("<JNI MonitorExit>", "Unlocking monitor that wasn't locked here: %s",
monitor_descr.c_str());
will_abort = true; break;
}
}
}
// When we abort, also make sure that any locks from the current "session" are removed from // the monitors table, otherwise we may visit local objects in GC during abort (which won't be // valid anymore). if (will_abort) {
RemoveMonitors(self_, current_frame, &monitors_, &locked_objects_);
}
}
void JNIEnvExt::CheckNoHeldMonitors() { // The locked_objects_ are grouped by their stack frame component, as this enforces structured // locking, and the groups form a stack. So the current frame entries are at the end. Check // whether the vector is empty, and when there are elements, whether the last element belongs // to this call - this signals that there are unlocked monitors. if (!locked_objects_.empty()) {
uintptr_t current_frame = GetJavaCallFrame(self_);
std::pair<uintptr_t, jobject>& pair = locked_objects_[locked_objects_.size() - 1]; if (pair.first == current_frame) {
std::string monitor_descr = ComputeMonitorDescription(self_, pair.second);
vm_->JniAbortF("<JNI End>", "Still holding a locked object on JNI end: %s",
monitor_descr.c_str()); // When we abort, also make sure that any locks from the current "session" are removed from // the monitors table, otherwise we may visit local objects in GC during abort.
RemoveMonitors(self_, current_frame, &monitors_, &locked_objects_);
} elseif (kIsDebugBuild) { // Make sure there are really no other entries and our checking worked as expected. for (std::pair<uintptr_t, jobject>& check_pair : locked_objects_) {
CHECK_NE(check_pair.first, current_frame);
}
}
} // Ensure critical locks aren't held when returning to Java. if (critical_ > 0) {
vm_->JniAbortF("<JNI End>", "Critical lock held when returning to Java on thread %s",
ToStr<Thread>(*self_).c_str());
}
}
// See if we have a runtime. Note: we cannot run other code (like JavaVMExt's CheckJNI install // code), as we'd have to recursively lock the mutex.
Runtime* runtime = Runtime::Current(); if (runtime != nullptr) {
runtime->GetThreadList()->ForEach(ThreadResetFunctionTable, nullptr); // Core Platform API checks rely on stack walking and classifying the caller. If a table // override is installed do not try to guess what semantics should be.
runtime->SetCorePlatformApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kDisabled);
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.