diff options
| -rw-r--r-- | runtime/openjdkjvmti/Android.bp | 1 | ||||
| -rw-r--r-- | runtime/openjdkjvmti/OpenjdkJvmTi.cc | 7 | ||||
| -rw-r--r-- | runtime/openjdkjvmti/art_jvmti.h | 5 | ||||
| -rw-r--r-- | runtime/openjdkjvmti/ti_properties.cc | 192 | ||||
| -rw-r--r-- | runtime/openjdkjvmti/ti_properties.h | 51 | ||||
| -rw-r--r-- | test/910-methods/methods.cc | 34 | ||||
| -rwxr-xr-x | test/922-properties/build | 17 | ||||
| -rw-r--r-- | test/922-properties/expected.txt | 59 | ||||
| -rw-r--r-- | test/922-properties/info.txt | 1 | ||||
| -rw-r--r-- | test/922-properties/properties.cc | 107 | ||||
| -rw-r--r-- | test/922-properties/properties.h | 30 | ||||
| -rwxr-xr-x | test/922-properties/run | 19 | ||||
| -rw-r--r-- | test/922-properties/src/Main.java | 155 | ||||
| -rw-r--r-- | test/Android.bp | 1 | ||||
| -rw-r--r-- | test/Android.run-test.mk | 1 | ||||
| -rw-r--r-- | test/ti-agent/common_helper.cc | 20 | ||||
| -rw-r--r-- | test/ti-agent/common_helper.h | 2 | ||||
| -rw-r--r-- | test/ti-agent/common_load.cc | 2 |
18 files changed, 672 insertions, 32 deletions
diff --git a/runtime/openjdkjvmti/Android.bp b/runtime/openjdkjvmti/Android.bp index d486380038..be06dd7b4c 100644 --- a/runtime/openjdkjvmti/Android.bp +++ b/runtime/openjdkjvmti/Android.bp @@ -25,6 +25,7 @@ cc_defaults { "ti_heap.cc", "ti_method.cc", "ti_object.cc", + "ti_properties.cc", "ti_stack.cc", "ti_redefine.cc", "transform.cc"], diff --git a/runtime/openjdkjvmti/OpenjdkJvmTi.cc b/runtime/openjdkjvmti/OpenjdkJvmTi.cc index c472b54b5b..936049fe3d 100644 --- a/runtime/openjdkjvmti/OpenjdkJvmTi.cc +++ b/runtime/openjdkjvmti/OpenjdkJvmTi.cc @@ -51,6 +51,7 @@ #include "ti_heap.h" #include "ti_method.h" #include "ti_object.h" +#include "ti_properties.h" #include "ti_redefine.h" #include "ti_stack.h" #include "transform.h" @@ -1034,15 +1035,15 @@ class JvmtiFunctions { } static jvmtiError GetSystemProperties(jvmtiEnv* env, jint* count_ptr, char*** property_ptr) { - return ERR(NOT_IMPLEMENTED); + return PropertiesUtil::GetSystemProperties(env, count_ptr, property_ptr); } static jvmtiError GetSystemProperty(jvmtiEnv* env, const char* property, char** value_ptr) { - return ERR(NOT_IMPLEMENTED); + return PropertiesUtil::GetSystemProperty(env, property, value_ptr); } static jvmtiError SetSystemProperty(jvmtiEnv* env, const char* property, const char* value) { - return ERR(NOT_IMPLEMENTED); + return PropertiesUtil::SetSystemProperty(env, property, value); } static jvmtiError GetPhase(jvmtiEnv* env, jvmtiPhase* phase_ptr) { diff --git a/runtime/openjdkjvmti/art_jvmti.h b/runtime/openjdkjvmti/art_jvmti.h index 48b29a3ac1..5eadc5a8e0 100644 --- a/runtime/openjdkjvmti/art_jvmti.h +++ b/runtime/openjdkjvmti/art_jvmti.h @@ -105,9 +105,10 @@ class JvmtiDeleter { using JvmtiUniquePtr = std::unique_ptr<unsigned char, JvmtiDeleter>; +template <typename T> ALWAYS_INLINE -static inline JvmtiUniquePtr MakeJvmtiUniquePtr(jvmtiEnv* env, unsigned char* mem) { - return JvmtiUniquePtr(mem, JvmtiDeleter(env)); +static inline JvmtiUniquePtr MakeJvmtiUniquePtr(jvmtiEnv* env, T* mem) { + return JvmtiUniquePtr(reinterpret_cast<unsigned char*>(mem), JvmtiDeleter(env)); } ALWAYS_INLINE diff --git a/runtime/openjdkjvmti/ti_properties.cc b/runtime/openjdkjvmti/ti_properties.cc new file mode 100644 index 0000000000..46b9e71b13 --- /dev/null +++ b/runtime/openjdkjvmti/ti_properties.cc @@ -0,0 +1,192 @@ +/* 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 "art_jvmti.h" +#include "runtime.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"; + +static jvmtiError Copy(jvmtiEnv* env, const char* in, char** out) { + unsigned char* data = nullptr; + jvmtiError result = CopyString(env, in, &data); + *out = reinterpret_cast<char*>(data); + return result; +} + +jvmtiError PropertiesUtil::GetSystemProperties(jvmtiEnv* env, + jint* count_ptr, + char*** property_ptr) { + if (count_ptr == nullptr || property_ptr == nullptr) { + return ERR(NULL_POINTER); + } + unsigned char* array_data; + jvmtiError array_alloc_result = env->Allocate((kPropertiesSize + 2) * sizeof(char*), &array_data); + if (array_alloc_result != ERR(NONE)) { + return array_alloc_result; + } + JvmtiUniquePtr array_data_ptr = MakeJvmtiUniquePtr(env, array_data); + char** array = reinterpret_cast<char**>(array_data); + + std::vector<JvmtiUniquePtr> property_copies; + + { + char* libpath_data; + jvmtiError libpath_result = Copy(env, kPropertyLibraryPath, &libpath_data); + if (libpath_result != ERR(NONE)) { + return libpath_result; + } + array[0] = libpath_data; + property_copies.push_back(MakeJvmtiUniquePtr(env, libpath_data)); + } + + { + char* classpath_data; + jvmtiError classpath_result = Copy(env, kPropertyClassPath, &classpath_data); + if (classpath_result != ERR(NONE)) { + return classpath_result; + } + array[1] = classpath_data; + property_copies.push_back(MakeJvmtiUniquePtr(env, classpath_data)); + } + + for (size_t i = 0; i != kPropertiesSize; ++i) { + char* data; + jvmtiError data_result = Copy(env, kProperties[i][0], &data); + if (data_result != ERR(NONE)) { + return data_result; + } + array[i + 2] = data; + property_copies.push_back(MakeJvmtiUniquePtr(env, data)); + } + + // Everything is OK, release the data. + array_data_ptr.release(); + for (auto& uptr : property_copies) { + uptr.release(); + } + + *count_ptr = kPropertiesSize + 2; + *property_ptr = array; + + return ERR(NONE); +} + +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) { + // TODO: In the live phase, we should probably compare to System.getProperty. java.library.path + // may not be set initially, and is then freely modifiable. + 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); + } + } + } + return ERR(NOT_AVAILABLE); + } + + if (strcmp(property, kPropertyClassPath) == 0) { + return Copy(env, art::Runtime::Current()->GetClassPathString().c_str(), 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 diff --git a/runtime/openjdkjvmti/ti_properties.h b/runtime/openjdkjvmti/ti_properties.h new file mode 100644 index 0000000000..70734813bd --- /dev/null +++ b/runtime/openjdkjvmti/ti_properties.h @@ -0,0 +1,51 @@ +/* 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. + */ + +#ifndef ART_RUNTIME_OPENJDKJVMTI_TI_PROPERTIES_H_ +#define ART_RUNTIME_OPENJDKJVMTI_TI_PROPERTIES_H_ + +#include "jni.h" +#include "jvmti.h" + +namespace openjdkjvmti { + +class PropertiesUtil { + public: + static jvmtiError GetSystemProperties(jvmtiEnv* env, jint* count_ptr, char*** property_ptr); + + static jvmtiError GetSystemProperty(jvmtiEnv* env, const char* property, char** value_ptr); + + static jvmtiError SetSystemProperty(jvmtiEnv* env, const char* property, const char* value); +}; + +} // namespace openjdkjvmti + +#endif // ART_RUNTIME_OPENJDKJVMTI_TI_PROPERTIES_H_ diff --git a/test/910-methods/methods.cc b/test/910-methods/methods.cc index 0f8892e508..fa9679db4b 100644 --- a/test/910-methods/methods.cc +++ b/test/910-methods/methods.cc @@ -114,33 +114,13 @@ extern "C" JNIEXPORT jint JNICALL Java_Main_getMethodModifiers( return modifiers; } -static bool ErrorToException(JNIEnv* env, jvmtiError error) { - if (error == JVMTI_ERROR_NONE) { - return false; - } - - ScopedLocalRef<jclass> rt_exception(env, env->FindClass("java/lang/RuntimeException")); - if (rt_exception.get() == nullptr) { - // CNFE should be pending. - return true; - } - - char* err; - jvmti_env->GetErrorName(error, &err); - - env->ThrowNew(rt_exception.get(), err); - - jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err)); - return true; -} - extern "C" JNIEXPORT jint JNICALL Java_Main_getMaxLocals( JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jobject method) { jmethodID id = env->FromReflectedMethod(method); jint max_locals; jvmtiError result = jvmti_env->GetMaxLocals(id, &max_locals); - if (ErrorToException(env, result)) { + if (JvmtiErrorToException(env, result)) { return -1; } @@ -153,7 +133,7 @@ extern "C" JNIEXPORT jint JNICALL Java_Main_getArgumentsSize( jint arguments; jvmtiError result = jvmti_env->GetArgumentsSize(id, &arguments); - if (ErrorToException(env, result)) { + if (JvmtiErrorToException(env, result)) { return -1; } @@ -167,7 +147,7 @@ extern "C" JNIEXPORT jlong JNICALL Java_Main_getMethodLocationStart( jlong start; jlong end; jvmtiError result = jvmti_env->GetMethodLocation(id, &start, &end); - if (ErrorToException(env, result)) { + if (JvmtiErrorToException(env, result)) { return -1; } @@ -181,7 +161,7 @@ extern "C" JNIEXPORT jlong JNICALL Java_Main_getMethodLocationEnd( jlong start; jlong end; jvmtiError result = jvmti_env->GetMethodLocation(id, &start, &end); - if (ErrorToException(env, result)) { + if (JvmtiErrorToException(env, result)) { return -1; } @@ -194,7 +174,7 @@ extern "C" JNIEXPORT jboolean JNICALL Java_Main_isMethodNative( jboolean is_native; jvmtiError result = jvmti_env->IsMethodNative(id, &is_native); - if (ErrorToException(env, result)) { + if (JvmtiErrorToException(env, result)) { return JNI_FALSE; } @@ -207,7 +187,7 @@ extern "C" JNIEXPORT jboolean JNICALL Java_Main_isMethodObsolete( jboolean is_obsolete; jvmtiError result = jvmti_env->IsMethodObsolete(id, &is_obsolete); - if (ErrorToException(env, result)) { + if (JvmtiErrorToException(env, result)) { return JNI_FALSE; } @@ -220,7 +200,7 @@ extern "C" JNIEXPORT jboolean JNICALL Java_Main_isMethodSynthetic( jboolean is_synthetic; jvmtiError result = jvmti_env->IsMethodSynthetic(id, &is_synthetic); - if (ErrorToException(env, result)) { + if (JvmtiErrorToException(env, result)) { return JNI_FALSE; } diff --git a/test/922-properties/build b/test/922-properties/build new file mode 100755 index 0000000000..898e2e54a2 --- /dev/null +++ b/test/922-properties/build @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Copyright 2016 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +./default-build "$@" --experimental agents diff --git a/test/922-properties/expected.txt b/test/922-properties/expected.txt new file mode 100644 index 0000000000..0be939be3d --- /dev/null +++ b/test/922-properties/expected.txt @@ -0,0 +1,59 @@ +Recommended properties: + "java.class.path": OK + Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE + "java.library.path": OK + Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE + "java.vm.info": OK !!!JVMTI_ERROR_NOT_AVAILABLE + Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE + "java.vm.name": OK + Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE + "java.vm.vendor": OK + Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE + "java.vm.version": OK + Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE +Missing recommended properties: [java.vm.info] +Other properties: + "file.encoding": OK + Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE + "file.separator": OK + Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE + "java.class.version": OK + Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE + "java.compiler": OK + Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE + "java.ext.dirs": OK + Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE + "java.net.preferIPv6Addresses": OK + Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE + "java.specification.name": OK + Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE + "java.specification.vendor": OK + Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE + "java.specification.version": OK + Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE + "java.vendor": OK + Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE + "java.vendor.url": OK + Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE + "java.version": OK + Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE + "java.vm.specification.name": OK + Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE + "java.vm.specification.vendor": OK + Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE + "java.vm.specification.version": OK + Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE + "java.vm.vendor.url": OK + Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE + "line.separator": OK + Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE + "os.name": OK + Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE + "path.separator": OK + Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE +Non-specified property: + "java.boot.class.path": ERROR !!!JVMTI_ERROR_NOT_AVAILABLE + Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE +Non-specified property (2): + "a": OK !!!JVMTI_ERROR_NOT_AVAILABLE + Setting value to "abc": !!!JVMTI_ERROR_NOT_AVAILABLE diff --git a/test/922-properties/info.txt b/test/922-properties/info.txt new file mode 100644 index 0000000000..875a5f6ec1 --- /dev/null +++ b/test/922-properties/info.txt @@ -0,0 +1 @@ +Tests basic functions in the jvmti plugin. diff --git a/test/922-properties/properties.cc b/test/922-properties/properties.cc new file mode 100644 index 0000000000..b1e7fce3b5 --- /dev/null +++ b/test/922-properties/properties.cc @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "properties.h" + +#include <stdio.h> + +#include "base/macros.h" +#include "jni.h" +#include "openjdkjvmti/jvmti.h" +#include "ScopedUtfChars.h" + +#include "ti-agent/common_helper.h" +#include "ti-agent/common_load.h" + +namespace art { +namespace Test922Properties { + +extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getSystemProperties( + JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED) { + jint count; + char** properties; + jvmtiError result = jvmti_env->GetSystemProperties(&count, &properties); + if (JvmtiErrorToException(env, result)) { + return nullptr; + } + + auto callback = [&](jint i) -> jstring { + char* data = properties[i]; + if (data == nullptr) { + return nullptr; + } + jstring ret = env->NewStringUTF(data); + jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(data)); + return ret; + }; + jobjectArray ret = CreateObjectArray(env, count, "java/lang/String", callback); + + jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(properties)); + + return ret; +} + +extern "C" JNIEXPORT jstring JNICALL Java_Main_getSystemProperty( + JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jstring key) { + ScopedUtfChars string(env, key); + if (string.c_str() == nullptr) { + return nullptr; + } + + char* value = nullptr; + jvmtiError result = jvmti_env->GetSystemProperty(string.c_str(), &value); + if (JvmtiErrorToException(env, result)) { + return nullptr; + } + + jstring ret = (value == nullptr) ? nullptr : env->NewStringUTF(value); + + jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(value)); + + return ret; +} + +extern "C" JNIEXPORT void JNICALL Java_Main_setSystemProperty( + JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jstring key, jstring value) { + ScopedUtfChars key_string(env, key); + if (key_string.c_str() == nullptr) { + return; + } + ScopedUtfChars value_string(env, value); + if (value_string.c_str() == nullptr) { + return; + } + + jvmtiError result = jvmti_env->SetSystemProperty(key_string.c_str(), value_string.c_str()); + if (JvmtiErrorToException(env, result)) { + return; + } +} + +// Don't do anything +jint OnLoad(JavaVM* vm, + char* options ATTRIBUTE_UNUSED, + void* reserved ATTRIBUTE_UNUSED) { + if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) { + printf("Unable to get jvmti env!\n"); + return 1; + } + SetAllCapabilities(jvmti_env); + return 0; +} + +} // namespace Test922Properties +} // namespace art diff --git a/test/922-properties/properties.h b/test/922-properties/properties.h new file mode 100644 index 0000000000..84feb10758 --- /dev/null +++ b/test/922-properties/properties.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_TEST_922_PROPERTIES_PROPERTIES_H_ +#define ART_TEST_922_PROPERTIES_PROPERTIES_H_ + +#include <jni.h> + +namespace art { +namespace Test922Properties { + +jint OnLoad(JavaVM* vm, char* options, void* reserved); + +} // namespace Test922Properties +} // namespace art + +#endif // ART_TEST_922_PROPERTIES_PROPERTIES_H_ diff --git a/test/922-properties/run b/test/922-properties/run new file mode 100755 index 0000000000..4379349cb2 --- /dev/null +++ b/test/922-properties/run @@ -0,0 +1,19 @@ +#!/bin/bash +# +# Copyright 2016 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +./default-run "$@" --experimental agents \ + --experimental runtime-plugins \ + --jvmti diff --git a/test/922-properties/src/Main.java b/test/922-properties/src/Main.java new file mode 100644 index 0000000000..6cec6e97f2 --- /dev/null +++ b/test/922-properties/src/Main.java @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.Set; +import java.util.TreeSet; + +public class Main { + public static void main(String[] args) throws Exception { + System.loadLibrary(args[1]); + + doTest(); + } + + public static void doTest() throws Exception { + Set<String> recommendedProperties = getRecommendedProperties(); + + System.out.println("Recommended properties:"); + for (String key : recommendedProperties) { + checkProperty(key); + } + + Set<String> allProperties = getAllProperties(); + + Set<String> retained = new TreeSet<String>(recommendedProperties); + retained.retainAll(allProperties); + if (!retained.equals(recommendedProperties)) { + Set<String> missing = new TreeSet<String>(recommendedProperties); + missing.removeAll(retained); + System.out.println("Missing recommended properties: " + missing); + } + + Set<String> nonRecommended = new TreeSet<String>(allProperties); + nonRecommended.removeAll(recommendedProperties); + + System.out.println("Other properties:"); + for (String key : nonRecommended) { + checkProperty(key); + } + + System.out.println("Non-specified property:"); + String key = generate(allProperties); + checkProperty(key); + + System.out.println("Non-specified property (2):"); + String key2 = generateUnique(allProperties); + checkProperty(key2); + } + + private static Set<String> getRecommendedProperties() { + Set<String> keys = new TreeSet<String>(); + keys.add("java.vm.vendor"); + keys.add("java.vm.version"); + keys.add("java.vm.name"); + keys.add("java.vm.info"); + keys.add("java.library.path"); + keys.add("java.class.path"); + return keys; + } + + private static Set<String> getAllProperties() { + Set<String> keys = new TreeSet<String>(); + String[] props = getSystemProperties(); + for (String p : props) { + keys.add(p); + } + return keys; + } + + private static boolean equals(String s1, String s2) { + if (s1 == null && s2 == null) { + return true; + } else if (s1 != null) { + return s1.equals(s2); + } else { + return false; + } + } + + private static void checkProperty(String key) { + System.out.print(" \"" + key + "\": "); + String err = null; + String value = null; + try { + value = getSystemProperty(key); + } catch (RuntimeException e) { + err = e.getMessage(); + } + String sysValue = System.getProperty(key); + if (equals(value, sysValue)) { + System.out.print("OK"); + if (err != null) { + System.out.println(" !!!" + err); + } else { + System.out.println(); + } + } else { + System.out.println("ERROR !!!" + err); + } + + System.out.print(" Setting value to \"abc\": "); + try { + setSystemProperty(key, "abc"); + System.out.println("SUCCEEDED"); + } catch (RuntimeException e) { + System.out.println("!!!" + e.getMessage()); + } + } + + private static String generateUnique(Set<String> others) { + // Construct something. To be deterministic, just use "a+". + StringBuilder sb = new StringBuilder("a"); + for (;;) { + String key = sb.toString(); + if (!others.contains(key)) { + return key; + } + sb.append('a'); + } + } + + private static String generate(Set<String> others) { + // First check for something in the overall System properties. + TreeSet<String> sysProps = new TreeSet<String>(System.getProperties().stringPropertyNames()); + sysProps.removeAll(others); + if (!sysProps.isEmpty()) { + // Find something that starts with "java" or "os," trying to be platform-independent. + for (String s: sysProps) { + if (s.startsWith("java.") || s.startsWith("os.")) { + return s; + } + } + // Just return the first thing. + return sysProps.iterator().next(); + } + + return generateUnique(others); + } + + private static native String[] getSystemProperties(); + private static native String getSystemProperty(String key); + private static native void setSystemProperty(String key, String value); +} diff --git a/test/Android.bp b/test/Android.bp index 5a8f43e20e..f6648d1cdc 100644 --- a/test/Android.bp +++ b/test/Android.bp @@ -262,6 +262,7 @@ art_cc_defaults { "913-heaps/heaps.cc", "918-fields/fields.cc", "920-objects/objects.cc", + "922-properties/properties.cc", ], shared_libs: [ "libbase", diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk index c48f57350d..a3f6864883 100644 --- a/test/Android.run-test.mk +++ b/test/Android.run-test.mk @@ -294,6 +294,7 @@ TEST_ART_BROKEN_TARGET_TESTS += \ 919-obsolete-fields \ 920-objects \ 921-hello-failure \ + 922-properties \ ifneq (,$(filter target,$(TARGET_TYPES))) ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,target,$(RUN_TYPES),$(PREBUILD_TYPES), \ diff --git a/test/ti-agent/common_helper.cc b/test/ti-agent/common_helper.cc index 01b6c989cc..6f98f10072 100644 --- a/test/ti-agent/common_helper.cc +++ b/test/ti-agent/common_helper.cc @@ -40,6 +40,26 @@ void SetAllCapabilities(jvmtiEnv* env) { env->AddCapabilities(&caps); } +bool JvmtiErrorToException(JNIEnv* env, jvmtiError error) { + if (error == JVMTI_ERROR_NONE) { + return false; + } + + ScopedLocalRef<jclass> rt_exception(env, env->FindClass("java/lang/RuntimeException")); + if (rt_exception.get() == nullptr) { + // CNFE should be pending. + return true; + } + + char* err; + jvmti_env->GetErrorName(error, &err); + + env->ThrowNew(rt_exception.get(), err); + + jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err)); + return true; +} + namespace common_redefine { static void throwRedefinitionError(jvmtiEnv* jvmti, JNIEnv* env, jclass target, jvmtiError res) { diff --git a/test/ti-agent/common_helper.h b/test/ti-agent/common_helper.h index 76543fed23..642ca03274 100644 --- a/test/ti-agent/common_helper.h +++ b/test/ti-agent/common_helper.h @@ -65,6 +65,8 @@ static jobjectArray CreateObjectArray(JNIEnv* env, void SetAllCapabilities(jvmtiEnv* env); +bool JvmtiErrorToException(JNIEnv* env, jvmtiError error); + } // namespace art #endif // ART_TEST_TI_AGENT_COMMON_HELPER_H_ diff --git a/test/ti-agent/common_load.cc b/test/ti-agent/common_load.cc index d7579ca022..e309a8920b 100644 --- a/test/ti-agent/common_load.cc +++ b/test/ti-agent/common_load.cc @@ -39,6 +39,7 @@ #include "913-heaps/heaps.h" #include "918-fields/fields.h" #include "920-objects/objects.h" +#include "922-properties/properties.h" namespace art { @@ -76,6 +77,7 @@ AgentLib agents[] = { { "919-obsolete-fields", common_redefine::OnLoad, nullptr }, { "920-objects", Test920Objects::OnLoad, nullptr }, { "921-hello-failure", common_redefine::OnLoad, nullptr }, + { "922-properties", Test922Properties::OnLoad, nullptr }, }; static AgentLib* FindAgent(char* name) { |