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 "ScopedLocalRef.h"
39 #include "ScopedUtfChars.h"
40
41 #include "art_jvmti.h"
42 #include "runtime.h"
43 #include "thread-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
GetSystemProperties(jvmtiEnv * env,jint * count_ptr,char *** property_ptr)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
Copy(jvmtiEnv * env,const char * in,char ** out)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.
DefaultToDot(const std::string & class_path)156 static const char* DefaultToDot(const std::string& class_path) {
157 return class_path.empty() ? "." : class_path.c_str();
158 }
159
160 // Handle kPropertyLibraryPath.
GetLibraryPath(jvmtiEnv * env,char ** value_ptr)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
GetSystemProperty(jvmtiEnv * env,const char * property,char ** value_ptr)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
SetSystemProperty(jvmtiEnv * env ATTRIBUTE_UNUSED,const char * property ATTRIBUTE_UNUSED,const char * value ATTRIBUTE_UNUSED)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