| /* 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 |