diff options
| author | 2020-09-22 15:35:59 -0700 | |
|---|---|---|
| committer | 2020-10-02 18:58:58 +0000 | |
| commit | 8d9c6048caa5ac3051e05540c04ea7cb3dfff9a7 (patch) | |
| tree | e18df218572fc3d745af384ccfa5308a352239ae | |
| parent | 8b247625f58ba8a0f616594dc774089678aa57e3 (diff) | |
Add test for thread-attach naming behavior
The interaction between pthread_setname_np and AttachCurrrentThread is
not always obvious. Add a test to codify the interaction. Basically
AttachCurrentThread will always override the current
pthread_setname_np thread name, including if AttachCurrentThread is
called without an explicit name, in which case the pthread-name will
be changed to the name selected by java.
Test: ./test.py --host
Bug: 168655382
Change-Id: If0319b733dc808a4cb892b6199030657c3e69f81
| -rw-r--r-- | test/2037-thread-name-inherit/Android.bp | 19 | ||||
| -rw-r--r-- | test/2037-thread-name-inherit/expected.txt | 1 | ||||
| -rw-r--r-- | test/2037-thread-name-inherit/info.txt | 1 | ||||
| -rw-r--r-- | test/2037-thread-name-inherit/src/Main.java | 101 | ||||
| -rw-r--r-- | test/2037-thread-name-inherit/thread_name_inherit.cc | 111 | ||||
| -rw-r--r-- | test/Android.bp | 1 |
6 files changed, 234 insertions, 0 deletions
diff --git a/test/2037-thread-name-inherit/Android.bp b/test/2037-thread-name-inherit/Android.bp new file mode 100644 index 0000000000..8cda6b59b4 --- /dev/null +++ b/test/2037-thread-name-inherit/Android.bp @@ -0,0 +1,19 @@ +// Generated by `regen-test-files`. Do not edit manually. + +// Build rules for ART run-test `2037-thread-name-inherit`. + +// Test's Dex code. +java_test { + name: "art-run-test-2037-thread-name-inherit", + defaults: ["art-run-test-defaults"], + srcs: ["src/**/*.java"], + data: [":art-run-test-2037-thread-name-inherit-expected"], +} + +// Test's expected output. +genrule { + name: "art-run-test-2037-thread-name-inherit-expected", + out: ["art-run-test-2037-thread-name-inherit-expected.txt"], + srcs: ["expected.txt"], + cmd: "cp -f $(in) $(out)", +} diff --git a/test/2037-thread-name-inherit/expected.txt b/test/2037-thread-name-inherit/expected.txt new file mode 100644 index 0000000000..6a5618ebc6 --- /dev/null +++ b/test/2037-thread-name-inherit/expected.txt @@ -0,0 +1 @@ +JNI_OnLoad called diff --git a/test/2037-thread-name-inherit/info.txt b/test/2037-thread-name-inherit/info.txt new file mode 100644 index 0000000000..f659e84ac8 --- /dev/null +++ b/test/2037-thread-name-inherit/info.txt @@ -0,0 +1 @@ +Test that thread's names are correctly inherited. diff --git a/test/2037-thread-name-inherit/src/Main.java b/test/2037-thread-name-inherit/src/Main.java new file mode 100644 index 0000000000..18049d7658 --- /dev/null +++ b/test/2037-thread-name-inherit/src/Main.java @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2020 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.function.*; + +public class Main { + public static final boolean IS_ART = System.getProperty("java.vm.name").equals("Dalvik"); + + public static final class Names { + public final String native_name; + public final String java_name; + + public Names(String ntv, String java) { + this.native_name = ntv; + this.java_name = java; + } + + public boolean equals(Object o) { + if (o instanceof Names) { + Names on = (Names) o; + return on.native_name.equals(native_name) && on.java_name.equals(java_name); + } else { + return false; + } + } + + public String toString() { + return "Names{native: \"" + native_name + "\", java: \"" + java_name + "\"}"; + } + } + + public static void checkDefaultNames(Names res) { + if (IS_ART) { + if (!res.native_name.matches("Thread-[0-9]+")) { + throw new Error("Bad thread name! " + res); + } + } else { + if (!res.native_name.equals("native-thread")) { + throw new Error("Bad thread name! " + res); + } + } + if (!res.java_name.matches("Thread-[0-9]+")) { + throw new Error("Bad thread name! " + res); + } + } + + public static void checkNames(Names res, Names art_exp, Names ri_exp) { + if (IS_ART) { + if (!res.equals(art_exp)) { + throw new Error("Not equal " + res + " != " + art_exp); + } + } else { + if (!res.equals(ri_exp)) { + throw new Error("Not equal " + res + " != " + ri_exp); + } + } + } + + public static void main(String[] args) throws Exception { + System.loadLibrary(args[0]); + Names[] name = new Names[1]; + BiConsumer<String, Thread> thdResult = + (String native_name, Thread jthread) -> { + name[0] = new Names(native_name, jthread.getName()); + }; + + runThreadTest(thdResult); + checkDefaultNames(name[0]); + + runThreadTestWithName(thdResult); + checkNames( + name[0], + new Names("java-native-thr", "java-native-thread"), + new Names("native-thread", "java-native-thread")); + + runThreadTestSetJava(thdResult); + checkNames( + name[0], + new Names("native-thread-s", "native-thread-set-java"), + new Names("native-thread", "native-thread-set-java")); + } + + public static native void runThreadTest(BiConsumer<String, Thread> results); + + public static native void runThreadTestWithName(BiConsumer<String, Thread> results); + + public static native void runThreadTestSetJava(BiConsumer<String, Thread> results); +} diff --git a/test/2037-thread-name-inherit/thread_name_inherit.cc b/test/2037-thread-name-inherit/thread_name_inherit.cc new file mode 100644 index 0000000000..1cca514ea0 --- /dev/null +++ b/test/2037-thread-name-inherit/thread_name_inherit.cc @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2020 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 <jni.h> + +#include <iostream> + +#include "android-base/logging.h" + +struct ThreadArgs { + JavaVM* jvm; + jobject consumer; + JavaVMAttachArgs* attach_args; + bool set_in_java; +}; + +// The main method of the test thread. The ThreadArgs controls what this does. +void* ThreadMain(void* arg) { + ThreadArgs* args = reinterpret_cast<ThreadArgs*>(arg); + JNIEnv* env = nullptr; + pthread_t self = pthread_self(); + + int err = pthread_setname_np(self, "native-thread"); + CHECK_EQ(err, 0); + + args->jvm->AttachCurrentThread(&env, args->attach_args); + + jclass thread_class = env->FindClass("java/lang/Thread"); + jclass consumer_class = env->FindClass("java/util/function/BiConsumer"); + jmethodID current_thread_method = + env->GetStaticMethodID(thread_class, "currentThread", "()Ljava/lang/Thread;"); + jmethodID accept_method = + env->GetMethodID(consumer_class, "accept", "(Ljava/lang/Object;Ljava/lang/Object;)V"); + jobject current_thread = env->CallStaticObjectMethod(thread_class, current_thread_method); + if (args->set_in_java) { + jmethodID set_name_method = env->GetMethodID(thread_class, "setName", "(Ljava/lang/String;)V"); + jobject str_name = env->NewStringUTF("native-thread-set-java"); + env->CallVoidMethod(current_thread, set_name_method, str_name); + } + + char name_chars[1024]; + err = pthread_getname_np(self, name_chars, sizeof(name_chars)); + CHECK_EQ(err, 0); + jobject str_name = env->NewStringUTF(name_chars); + + env->CallVoidMethod(args->consumer, accept_method, str_name, current_thread); + + args->jvm->DetachCurrentThread(); + + return nullptr; +} + +extern "C" JNIEXPORT void Java_Main_runThreadTestWithName(JNIEnv* env, + jclass /*clazz*/, + jobject consumer) { + jobject global_consumer = env->NewGlobalRef(consumer); + JavaVMAttachArgs args; + args.group = nullptr; + args.name = "java-native-thread"; + args.version = JNI_VERSION_1_6; + ThreadArgs ta { + .jvm = nullptr, .consumer = global_consumer, .attach_args = &args, .set_in_java = false + }; + env->GetJavaVM(&ta.jvm); + pthread_t child; + pthread_create(&child, nullptr, ThreadMain, &ta); + void* ret; + pthread_join(child, &ret); + env->DeleteGlobalRef(ta.consumer); +} + +extern "C" JNIEXPORT void Java_Main_runThreadTest(JNIEnv* env, jclass /*clazz*/, jobject consumer) { + jobject global_consumer = env->NewGlobalRef(consumer); + ThreadArgs ta { + .jvm = nullptr, .consumer = global_consumer, .attach_args = nullptr, .set_in_java = false + }; + env->GetJavaVM(&ta.jvm); + pthread_t child; + pthread_create(&child, nullptr, ThreadMain, &ta); + void* ret; + pthread_join(child, &ret); + env->DeleteGlobalRef(ta.consumer); +} + +extern "C" JNIEXPORT void Java_Main_runThreadTestSetJava(JNIEnv* env, + jclass /*clazz*/, + jobject consumer) { + jobject global_consumer = env->NewGlobalRef(consumer); + ThreadArgs ta { + .jvm = nullptr, .consumer = global_consumer, .attach_args = nullptr, .set_in_java = true + }; + env->GetJavaVM(&ta.jvm); + pthread_t child; + pthread_create(&child, nullptr, ThreadMain, &ta); + void* ret; + pthread_join(child, &ret); + env->DeleteGlobalRef(ta.consumer); +} diff --git a/test/Android.bp b/test/Android.bp index d31de87de9..514b54ddb0 100644 --- a/test/Android.bp +++ b/test/Android.bp @@ -644,6 +644,7 @@ cc_defaults { "2031-zygote-compiled-frame-deopt/native-wait.cc", "2033-shutdown-mechanics/native_shutdown.cc", "2036-jni-filechannel/jni_filechannel.cc", + "2037-thread-name-inherit/thread_name_inherit.cc", "common/runtime_state.cc", "common/stack_inspect.cc", ], |