staticvoid Update() REQUIRES_SHARED(art::Locks::mutator_lock_) { if (gSystemOnloadSegments.empty()) { return;
}
// In the on-load phase we have to modify java.class.path to influence the system classloader. // As this is an unmodifiable system property, we have to access the "defaults" field.
art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
DCHECK(class_linker != nullptr);
art::Thread* self = art::Thread::Current();
// This is an allocation. Do this late to avoid the need for handles.
ScopedLocalRef<jobject> cp_jobj(self->GetJniEnv(), nullptr);
{
art::ObjPtr<art::mirror::Object> cp_key =
art::mirror::String::AllocFromModifiedUtf8(self, "java.class.path"); if (cp_key == nullptr) {
self->AssertPendingOOMException();
self->ClearException(); return;
}
cp_jobj.reset(self->GetJniEnv()->AddLocalReference<jobject>(cp_key));
}
// OK, now get the current value.
std::string str_value;
{
ScopedLocalRef<jobject> old_value(self->GetJniEnv(),
self->GetJniEnv()->CallObjectMethod(
defaults_jobj.get(),
art::jni::EncodeArtMethod(get_property),
cp_jobj.get()));
DCHECK(old_value.get() != nullptr);
// Update the value by appending the new segments. for (const std::string& segment : gSystemOnloadSegments) { if (!str_value.empty()) {
str_value += ":";
}
str_value += segment;
}
gSystemOnloadSegments.clear();
// Create the new value object.
ScopedLocalRef<jobject> new_val_jobj(self->GetJniEnv(), nullptr);
{
art::ObjPtr<art::mirror::Object> new_value =
art::mirror::String::AllocFromModifiedUtf8(self, str_value.c_str()); if (new_value == nullptr) {
self->AssertPendingOOMException();
self->ClearException(); return;
}
// Write to the defaults.
ScopedLocalRef<jobject> res_obj(self->GetJniEnv(),
self->GetJniEnv()->CallObjectMethod(defaults_jobj.get(),
art::jni::EncodeArtMethod(set_property),
cp_jobj.get(),
new_val_jobj.get())); if (self->IsExceptionPending()) {
self->ClearException(); return;
}
}
struct SearchCallback : public art::RuntimePhaseCallback { void NextRuntimePhase(RuntimePhase phase) override REQUIRES_SHARED(art::Locks::mutator_lock_) { if (phase == RuntimePhase::kStart) { // It's time to update the system properties.
Update();
}
}
};
// TODO We really should try to support doing this during the ON_LOAD phase. if (phase != jvmtiPhase::JVMTI_PHASE_LIVE) {
JVMTI_LOG(INFO, jvmti_env) << "Cannot add buffers to classpath during ON_LOAD phase to "
<< "prevent file-descriptor leaking."; return ERR(WRONG_PHASE);
}
// We have java APIs for adding files to the classpath, we might as well use them. It simplifies a // lot of code as well.
// Create a memfd
art::File file(art::memfd_create("JVMTI InMemory Added dex file", 0), /*check-usage*/true); if (file.Fd() < 0) { char* reason = strerror(errno);
JVMTI_LOG(ERROR, jvmti_env) << "Unable to create memfd due to " << reason; if (file.FlushClose() < 0) {
PLOG(WARNING) << "Failed to close file!";
} return ERR(INTERNAL);
} // Fill it with the buffer. if (!file.WriteFully(dex_bytes, dex_bytes_length) || file.Flush() != 0) {
JVMTI_LOG(ERROR, jvmti_env) << "Failed to write to memfd!"; if (file.FlushClose() < 0) {
PLOG(WARNING) << "Failed to close file!";
} return ERR(INTERNAL);
} // Get the filename in procfs.
std::ostringstream oss;
oss << "/proc/self/fd/" << file.Fd();
std::string seg(oss.str()); // Use common code.
jvmtiError result = AddToDexClassLoader(jvmti_env, classloader, seg.c_str()); // We have either loaded the dex file and have a new MemMap pointing to the same pages or loading // has failed and the memory isn't needed anymore. Either way we can close the memfd we created // and return. if (file.Close() != 0) {
JVMTI_LOG(WARNING, jvmti_env) << "Failed to close memfd!";
} return result;
}
// TODO We really should try to support doing this during the ON_LOAD phase. if (phase != jvmtiPhase::JVMTI_PHASE_LIVE) {
JVMTI_LOG(INFO, jvmti_env) << "Cannot add to classpath of arbitrary classloaders during "
<< "ON_LOAD phase."; return ERR(WRONG_PHASE);
}
// We'll use BaseDexClassLoader.addDexPath, as it takes care of array resizing etc. As a downside, // exceptions are swallowed.
art::Thread* self = art::Thread::Current();
art::ScopedObjectAccess soa(self);
art::StackHandleScope<2u> hs(self);
art::Handle<art::mirror::ClassLoader> class_loader =
hs.NewHandle(soa.Decode<art::mirror::ClassLoader>(classloader)); if (!class_loader->InstanceOf(art::WellKnownClasses::dalvik_system_BaseDexClassLoader.Get())) {
JVMTI_LOG(ERROR, jvmti_env) << "Unable to add " << segment << " to non BaseDexClassLoader!"; return ERR(CLASS_LOADER_UNSUPPORTED);
}
if (phase == jvmtiPhase::JVMTI_PHASE_ONLOAD) { // We could try and see whether it is a valid path. We could also try to allocate Java // objects to avoid later OOME.
gSystemOnloadSegments.push_back(segment); return ERR(NONE);
} elseif (phase != jvmtiPhase::JVMTI_PHASE_LIVE) { return ERR(WRONG_PHASE);
}
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.