| /* 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([[maybe_unused]] jvmtiEnv* env, | 
 |                                              [[maybe_unused]] const char* property, | 
 |                                              [[maybe_unused]] const char* value) { | 
 |   // We do not allow manipulation of any property here. | 
 |   return ERR(NOT_AVAILABLE); | 
 | } | 
 |  | 
 | }  // namespace openjdkjvmti |