ART: Add system properties support
Add simple support for GetSystemProperties, GetSystemProperty and
SetSystemProperty. Add a test.
Bug: 31455788
Test: m test-art-host-run-test-922-properties
Change-Id: I02914f04643f0f8fab96f1b372925c2c5306fc9b
diff --git a/runtime/openjdkjvmti/Android.bp b/runtime/openjdkjvmti/Android.bp
index d486380..be06dd7 100644
--- a/runtime/openjdkjvmti/Android.bp
+++ b/runtime/openjdkjvmti/Android.bp
@@ -25,6 +25,7 @@
"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 c472b54..936049f 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 @@
}
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 48b29a3..5eadc5a 100644
--- a/runtime/openjdkjvmti/art_jvmti.h
+++ b/runtime/openjdkjvmti/art_jvmti.h
@@ -105,9 +105,10 @@
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 0000000..46b9e71
--- /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 0000000..7073481
--- /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 0f8892e..fa9679d 100644
--- a/test/910-methods/methods.cc
+++ b/test/910-methods/methods.cc
@@ -114,33 +114,13 @@
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 @@
jint arguments;
jvmtiError result = jvmti_env->GetArgumentsSize(id, &arguments);
- if (ErrorToException(env, result)) {
+ if (JvmtiErrorToException(env, result)) {
return -1;
}
@@ -167,7 +147,7 @@
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 @@
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 @@
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 @@
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 @@
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 0000000..898e2e5
--- /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 0000000..0be939b
--- /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 0000000..875a5f6
--- /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 0000000..b1e7fce
--- /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 0000000..84feb10
--- /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 0000000..4379349
--- /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 0000000..6cec6e9
--- /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 5a8f43e..f6648d1 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -262,6 +262,7 @@
"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 c48f573..a3f6864 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -294,6 +294,7 @@
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 01b6c98..6f98f10 100644
--- a/test/ti-agent/common_helper.cc
+++ b/test/ti-agent/common_helper.cc
@@ -40,6 +40,26 @@
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 76543fe..642ca03 100644
--- a/test/ti-agent/common_helper.h
+++ b/test/ti-agent/common_helper.h
@@ -65,6 +65,8 @@
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 d7579ca..e309a89 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 @@
{ "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) {