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/scoped_local_ref.h"
39 #include "nativehelper/scoped_utf_chars.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 
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