1 /* Copyright (C) 2017 The Android Open Source Project 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * 4 * This file implements interfaces from the file jvmti.h. This implementation 5 * is licensed under the same terms as the file jvmti.h. The 6 * copyright and license information for the file jvmti.h follows. 7 * 8 * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. 9 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 10 * 11 * This code is free software; you can redistribute it and/or modify it 12 * under the terms of the GNU General Public License version 2 only, as 13 * published by the Free Software Foundation. Oracle designates this 14 * particular file as subject to the "Classpath" exception as provided 15 * by Oracle in the LICENSE file that accompanied this code. 16 * 17 * This code is distributed in the hope that it will be useful, but WITHOUT 18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 20 * version 2 for more details (a copy is included in the LICENSE file that 21 * accompanied this code). 22 * 23 * You should have received a copy of the GNU General Public License version 24 * 2 along with this work; if not, write to the Free Software Foundation, 25 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 26 * 27 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 28 * or visit www.oracle.com if you need additional information or have any 29 * questions. 30 */ 31 32 #include "ti_properties.h" 33 34 #include <string.h> 35 #include <vector> 36 37 #include "jni.h" 38 #include "nativehelper/ScopedLocalRef.h" 39 #include "nativehelper/ScopedUtfChars.h" 40 41 #include "art_jvmti.h" 42 #include "runtime.h" 43 #include "thread-current-inl.h" 44 #include "ti_phase.h" 45 #include "well_known_classes.h" 46 47 namespace openjdkjvmti { 48 49 // Hardcoded properties. Tests ensure that these are consistent with libcore's view, as seen 50 // in System.java and AndroidHardcodedSystemProperties.java. 51 static constexpr const char* kProperties[][2] = { 52 // Recommended by the spec. 53 { "java.vm.vendor", "The Android Project" }, 54 { "java.vm.version", "2.1.0" }, // This is Runtime::GetVersion(). 55 { "java.vm.name", "Dalvik" }, 56 // Android does not provide java.vm.info. 57 // 58 // These are other values provided by AndroidHardcodedSystemProperties. 59 { "java.class.version", "50.0" }, 60 { "java.version", "0" }, 61 { "java.compiler", "" }, 62 { "java.ext.dirs", "" }, 63 64 { "java.specification.name", "Dalvik Core Library" }, 65 { "java.specification.vendor", "The Android Project" }, 66 { "java.specification.version", "0.9" }, 67 68 { "java.vendor", "The Android Project" }, 69 { "java.vendor.url", "http://www.android.com/" }, 70 { "java.vm.name", "Dalvik" }, 71 { "java.vm.specification.name", "Dalvik Virtual Machine Specification" }, 72 { "java.vm.specification.vendor", "The Android Project" }, 73 { "java.vm.specification.version", "0.9" }, 74 { "java.vm.vendor", "The Android Project" }, 75 76 { "java.vm.vendor.url", "http://www.android.com/" }, 77 78 { "java.net.preferIPv6Addresses", "false" }, 79 80 { "file.encoding", "UTF-8" }, 81 82 { "file.separator", "/" }, 83 { "line.separator", "\n" }, 84 { "path.separator", ":" }, 85 86 { "os.name", "Linux" }, 87 }; 88 static constexpr size_t kPropertiesSize = arraysize(kProperties); 89 static constexpr const char* kPropertyLibraryPath = "java.library.path"; 90 static constexpr const char* kPropertyClassPath = "java.class.path"; 91 92 jvmtiError PropertiesUtil::GetSystemProperties(jvmtiEnv* env, 93 jint* count_ptr, 94 char*** property_ptr) { 95 if (count_ptr == nullptr || property_ptr == nullptr) { 96 return ERR(NULL_POINTER); 97 } 98 jvmtiError array_alloc_result; 99 JvmtiUniquePtr<char*[]> array_data_ptr = AllocJvmtiUniquePtr<char*[]>(env, 100 kPropertiesSize + 2, 101 &array_alloc_result); 102 if (array_data_ptr == nullptr) { 103 return array_alloc_result; 104 } 105 106 std::vector<JvmtiUniquePtr<char[]>> property_copies; 107 108 { 109 jvmtiError libpath_result; 110 JvmtiUniquePtr<char[]> libpath_data = CopyString(env, kPropertyLibraryPath, &libpath_result); 111 if (libpath_data == nullptr) { 112 return libpath_result; 113 } 114 array_data_ptr.get()[0] = libpath_data.get(); 115 property_copies.push_back(std::move(libpath_data)); 116 } 117 118 { 119 jvmtiError classpath_result; 120 JvmtiUniquePtr<char[]> classpath_data = CopyString(env, kPropertyClassPath, &classpath_result); 121 if (classpath_data == nullptr) { 122 return classpath_result; 123 } 124 array_data_ptr.get()[1] = classpath_data.get(); 125 property_copies.push_back(std::move(classpath_data)); 126 } 127 128 for (size_t i = 0; i != kPropertiesSize; ++i) { 129 jvmtiError data_result; 130 JvmtiUniquePtr<char[]> data = CopyString(env, kProperties[i][0], &data_result); 131 if (data == nullptr) { 132 return data_result; 133 } 134 array_data_ptr.get()[i + 2] = data.get(); 135 property_copies.push_back(std::move(data)); 136 } 137 138 // Everything is OK, release the data. 139 *count_ptr = kPropertiesSize + 2; 140 *property_ptr = array_data_ptr.release(); 141 for (auto& uptr : property_copies) { 142 uptr.release(); 143 } 144 145 return ERR(NONE); 146 } 147 148 static jvmtiError Copy(jvmtiEnv* env, const char* in, char** out) { 149 jvmtiError result; 150 JvmtiUniquePtr<char[]> data = CopyString(env, in, &result); 151 *out = data.release(); 152 return result; 153 } 154 155 // See dalvik_system_VMRuntime.cpp. 156 static const char* DefaultToDot(const std::string& class_path) { 157 return class_path.empty() ? "." : class_path.c_str(); 158 } 159 160 // Handle kPropertyLibraryPath. 161 static jvmtiError GetLibraryPath(jvmtiEnv* env, char** value_ptr) { 162 const std::vector<std::string>& runtime_props = art::Runtime::Current()->GetProperties(); 163 for (const std::string& prop_assignment : runtime_props) { 164 size_t assign_pos = prop_assignment.find('='); 165 if (assign_pos != std::string::npos && assign_pos > 0) { 166 if (prop_assignment.substr(0, assign_pos) == kPropertyLibraryPath) { 167 return Copy(env, prop_assignment.substr(assign_pos + 1).c_str(), value_ptr); 168 } 169 } 170 } 171 if (!PhaseUtil::IsLivePhase()) { 172 return ERR(NOT_AVAILABLE); 173 } 174 // We expect this call to be rare. So don't optimize. 175 DCHECK(art::Thread::Current() != nullptr); 176 JNIEnv* jni_env = art::Thread::Current()->GetJniEnv(); 177 jmethodID get_prop = jni_env->GetStaticMethodID(art::WellKnownClasses::java_lang_System, 178 "getProperty", 179 "(Ljava/lang/String;)Ljava/lang/String;"); 180 CHECK(get_prop != nullptr); 181 182 ScopedLocalRef<jobject> input_str(jni_env, jni_env->NewStringUTF(kPropertyLibraryPath)); 183 if (input_str.get() == nullptr) { 184 jni_env->ExceptionClear(); 185 return ERR(OUT_OF_MEMORY); 186 } 187 188 ScopedLocalRef<jobject> prop_res( 189 jni_env, jni_env->CallStaticObjectMethod(art::WellKnownClasses::java_lang_System, 190 get_prop, 191 input_str.get())); 192 if (jni_env->ExceptionCheck() == JNI_TRUE) { 193 jni_env->ExceptionClear(); 194 return ERR(INTERNAL); 195 } 196 if (prop_res.get() == nullptr) { 197 *value_ptr = nullptr; 198 return ERR(NONE); 199 } 200 201 ScopedUtfChars chars(jni_env, reinterpret_cast<jstring>(prop_res.get())); 202 return Copy(env, chars.c_str(), value_ptr); 203 } 204 205 jvmtiError PropertiesUtil::GetSystemProperty(jvmtiEnv* env, 206 const char* property, 207 char** value_ptr) { 208 if (property == nullptr || value_ptr == nullptr) { 209 return ERR(NULL_POINTER); 210 } 211 212 if (strcmp(property, kPropertyLibraryPath) == 0) { 213 return GetLibraryPath(env, value_ptr); 214 } 215 216 if (strcmp(property, kPropertyClassPath) == 0) { 217 return Copy(env, DefaultToDot(art::Runtime::Current()->GetClassPathString()), value_ptr); 218 } 219 220 for (size_t i = 0; i != kPropertiesSize; ++i) { 221 if (strcmp(property, kProperties[i][0]) == 0) { 222 return Copy(env, kProperties[i][1], value_ptr); 223 } 224 } 225 226 return ERR(NOT_AVAILABLE); 227 } 228 229 jvmtiError PropertiesUtil::SetSystemProperty(jvmtiEnv* env ATTRIBUTE_UNUSED, 230 const char* property ATTRIBUTE_UNUSED, 231 const char* value ATTRIBUTE_UNUSED) { 232 // We do not allow manipulation of any property here. 233 return ERR(NOT_AVAILABLE); 234 } 235 236 } // namespace openjdkjvmti 237