237 lines
8.5 KiB
C++
237 lines
8.5 KiB
C++
/* Copyright (C) 2017 The Android Open Source Project
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This file implements interfaces from the file jvmti.h. This implementation
|
|
* is licensed under the same terms as the file jvmti.h. The
|
|
* copyright and license information for the file jvmti.h follows.
|
|
*
|
|
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation. Oracle designates this
|
|
* particular file as subject to the "Classpath" exception as provided
|
|
* by Oracle in the LICENSE file that accompanied this code.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*/
|
|
|
|
#include "ti_properties.h"
|
|
|
|
#include <string.h>
|
|
#include <vector>
|
|
|
|
#include "jni.h"
|
|
#include "nativehelper/scoped_local_ref.h"
|
|
#include "nativehelper/scoped_utf_chars.h"
|
|
|
|
#include "art_jvmti.h"
|
|
#include "runtime.h"
|
|
#include "thread-current-inl.h"
|
|
#include "ti_phase.h"
|
|
#include "well_known_classes.h"
|
|
|
|
namespace openjdkjvmti {
|
|
|
|
// Hardcoded properties. Tests ensure that these are consistent with libcore's view, as seen
|
|
// in System.java and AndroidHardcodedSystemProperties.java.
|
|
static constexpr const char* kProperties[][2] = {
|
|
// Recommended by the spec.
|
|
{ "java.vm.vendor", "The Android Project" },
|
|
{ "java.vm.version", "2.1.0" }, // This is Runtime::GetVersion().
|
|
{ "java.vm.name", "Dalvik" },
|
|
// Android does not provide java.vm.info.
|
|
//
|
|
// These are other values provided by AndroidHardcodedSystemProperties.
|
|
{ "java.class.version", "50.0" },
|
|
{ "java.version", "0" },
|
|
{ "java.compiler", "" },
|
|
{ "java.ext.dirs", "" },
|
|
|
|
{ "java.specification.name", "Dalvik Core Library" },
|
|
{ "java.specification.vendor", "The Android Project" },
|
|
{ "java.specification.version", "0.9" },
|
|
|
|
{ "java.vendor", "The Android Project" },
|
|
{ "java.vendor.url", "http://www.android.com/" },
|
|
{ "java.vm.name", "Dalvik" },
|
|
{ "java.vm.specification.name", "Dalvik Virtual Machine Specification" },
|
|
{ "java.vm.specification.vendor", "The Android Project" },
|
|
{ "java.vm.specification.version", "0.9" },
|
|
{ "java.vm.vendor", "The Android Project" },
|
|
|
|
{ "java.vm.vendor.url", "http://www.android.com/" },
|
|
|
|
{ "java.net.preferIPv6Addresses", "false" },
|
|
|
|
{ "file.encoding", "UTF-8" },
|
|
|
|
{ "file.separator", "/" },
|
|
{ "line.separator", "\n" },
|
|
{ "path.separator", ":" },
|
|
|
|
{ "os.name", "Linux" },
|
|
};
|
|
static constexpr size_t kPropertiesSize = arraysize(kProperties);
|
|
static constexpr const char* kPropertyLibraryPath = "java.library.path";
|
|
static constexpr const char* kPropertyClassPath = "java.class.path";
|
|
|
|
jvmtiError PropertiesUtil::GetSystemProperties(jvmtiEnv* env,
|
|
jint* count_ptr,
|
|
char*** property_ptr) {
|
|
if (count_ptr == nullptr || property_ptr == nullptr) {
|
|
return ERR(NULL_POINTER);
|
|
}
|
|
jvmtiError array_alloc_result;
|
|
JvmtiUniquePtr<char*[]> array_data_ptr = AllocJvmtiUniquePtr<char*[]>(env,
|
|
kPropertiesSize + 2,
|
|
&array_alloc_result);
|
|
if (array_data_ptr == nullptr) {
|
|
return array_alloc_result;
|
|
}
|
|
|
|
std::vector<JvmtiUniquePtr<char[]>> property_copies;
|
|
|
|
{
|
|
jvmtiError libpath_result;
|
|
JvmtiUniquePtr<char[]> libpath_data = CopyString(env, kPropertyLibraryPath, &libpath_result);
|
|
if (libpath_data == nullptr) {
|
|
return libpath_result;
|
|
}
|
|
array_data_ptr.get()[0] = libpath_data.get();
|
|
property_copies.push_back(std::move(libpath_data));
|
|
}
|
|
|
|
{
|
|
jvmtiError classpath_result;
|
|
JvmtiUniquePtr<char[]> classpath_data = CopyString(env, kPropertyClassPath, &classpath_result);
|
|
if (classpath_data == nullptr) {
|
|
return classpath_result;
|
|
}
|
|
array_data_ptr.get()[1] = classpath_data.get();
|
|
property_copies.push_back(std::move(classpath_data));
|
|
}
|
|
|
|
for (size_t i = 0; i != kPropertiesSize; ++i) {
|
|
jvmtiError data_result;
|
|
JvmtiUniquePtr<char[]> data = CopyString(env, kProperties[i][0], &data_result);
|
|
if (data == nullptr) {
|
|
return data_result;
|
|
}
|
|
array_data_ptr.get()[i + 2] = data.get();
|
|
property_copies.push_back(std::move(data));
|
|
}
|
|
|
|
// Everything is OK, release the data.
|
|
*count_ptr = kPropertiesSize + 2;
|
|
*property_ptr = array_data_ptr.release();
|
|
for (auto& uptr : property_copies) {
|
|
uptr.release();
|
|
}
|
|
|
|
return ERR(NONE);
|
|
}
|
|
|
|
static jvmtiError Copy(jvmtiEnv* env, const char* in, char** out) {
|
|
jvmtiError result;
|
|
JvmtiUniquePtr<char[]> data = CopyString(env, in, &result);
|
|
*out = data.release();
|
|
return result;
|
|
}
|
|
|
|
// See dalvik_system_VMRuntime.cpp.
|
|
static const char* DefaultToDot(const std::string& class_path) {
|
|
return class_path.empty() ? "." : class_path.c_str();
|
|
}
|
|
|
|
// Handle kPropertyLibraryPath.
|
|
static jvmtiError GetLibraryPath(jvmtiEnv* env, char** value_ptr) {
|
|
const std::vector<std::string>& runtime_props = art::Runtime::Current()->GetProperties();
|
|
for (const std::string& prop_assignment : runtime_props) {
|
|
size_t assign_pos = prop_assignment.find('=');
|
|
if (assign_pos != std::string::npos && assign_pos > 0) {
|
|
if (prop_assignment.substr(0, assign_pos) == kPropertyLibraryPath) {
|
|
return Copy(env, prop_assignment.substr(assign_pos + 1).c_str(), value_ptr);
|
|
}
|
|
}
|
|
}
|
|
if (!PhaseUtil::IsLivePhase()) {
|
|
return ERR(NOT_AVAILABLE);
|
|
}
|
|
// We expect this call to be rare. So don't optimize.
|
|
DCHECK(art::Thread::Current() != nullptr);
|
|
JNIEnv* jni_env = art::Thread::Current()->GetJniEnv();
|
|
jmethodID get_prop = jni_env->GetStaticMethodID(art::WellKnownClasses::java_lang_System,
|
|
"getProperty",
|
|
"(Ljava/lang/String;)Ljava/lang/String;");
|
|
CHECK(get_prop != nullptr);
|
|
|
|
ScopedLocalRef<jobject> input_str(jni_env, jni_env->NewStringUTF(kPropertyLibraryPath));
|
|
if (input_str.get() == nullptr) {
|
|
jni_env->ExceptionClear();
|
|
return ERR(OUT_OF_MEMORY);
|
|
}
|
|
|
|
ScopedLocalRef<jobject> prop_res(
|
|
jni_env, jni_env->CallStaticObjectMethod(art::WellKnownClasses::java_lang_System,
|
|
get_prop,
|
|
input_str.get()));
|
|
if (jni_env->ExceptionCheck() == JNI_TRUE) {
|
|
jni_env->ExceptionClear();
|
|
return ERR(INTERNAL);
|
|
}
|
|
if (prop_res.get() == nullptr) {
|
|
*value_ptr = nullptr;
|
|
return ERR(NONE);
|
|
}
|
|
|
|
ScopedUtfChars chars(jni_env, reinterpret_cast<jstring>(prop_res.get()));
|
|
return Copy(env, chars.c_str(), value_ptr);
|
|
}
|
|
|
|
jvmtiError PropertiesUtil::GetSystemProperty(jvmtiEnv* env,
|
|
const char* property,
|
|
char** value_ptr) {
|
|
if (property == nullptr || value_ptr == nullptr) {
|
|
return ERR(NULL_POINTER);
|
|
}
|
|
|
|
if (strcmp(property, kPropertyLibraryPath) == 0) {
|
|
return GetLibraryPath(env, value_ptr);
|
|
}
|
|
|
|
if (strcmp(property, kPropertyClassPath) == 0) {
|
|
return Copy(env, DefaultToDot(art::Runtime::Current()->GetClassPathString()), value_ptr);
|
|
}
|
|
|
|
for (size_t i = 0; i != kPropertiesSize; ++i) {
|
|
if (strcmp(property, kProperties[i][0]) == 0) {
|
|
return Copy(env, kProperties[i][1], value_ptr);
|
|
}
|
|
}
|
|
|
|
return ERR(NOT_AVAILABLE);
|
|
}
|
|
|
|
jvmtiError PropertiesUtil::SetSystemProperty(jvmtiEnv* env ATTRIBUTE_UNUSED,
|
|
const char* property ATTRIBUTE_UNUSED,
|
|
const char* value ATTRIBUTE_UNUSED) {
|
|
// We do not allow manipulation of any property here.
|
|
return ERR(NOT_AVAILABLE);
|
|
}
|
|
|
|
} // namespace openjdkjvmti
|