1/* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package art; 18 19import java.util.ArrayList; 20import java.util.Arrays; 21import java.util.Comparator; 22import java.util.Collections; 23import java.util.Iterator; 24import java.util.List; 25 26public class Test925 { 27 public static void run() throws Exception { 28 doTest(); 29 } 30 31 private static void doTest() throws Exception { 32 Thread t1 = Thread.currentThread(); 33 ThreadGroup curGroup = t1.getThreadGroup(); 34 35 ThreadGroup rootGroup = curGroup; 36 while (rootGroup.getParent() != null) { 37 rootGroup = rootGroup.getParent(); 38 } 39 40 ThreadGroup topGroups[] = getTopThreadGroups(); 41 if (topGroups == null || topGroups.length != 1 || topGroups[0] != rootGroup) { 42 System.out.println(Arrays.toString(topGroups)); 43 throw new RuntimeException("Unexpected topGroups"); 44 } 45 46 printThreadGroupInfo(curGroup); 47 printThreadGroupInfo(rootGroup); 48 49 waitGroupChildren(rootGroup, 5 /* # daemons */, 30 /* timeout in seconds */); 50 51 checkChildren(curGroup); 52 } 53 54 private static void printThreadGroupInfo(ThreadGroup tg) { 55 Object[] threadGroupInfo = getThreadGroupInfo(tg); 56 if (threadGroupInfo == null || threadGroupInfo.length != 4) { 57 System.out.println(Arrays.toString(threadGroupInfo)); 58 throw new RuntimeException("threadGroupInfo length wrong"); 59 } 60 61 System.out.println(tg); 62 System.out.println(" " + threadGroupInfo[0]); // Parent 63 System.out.println(" " + threadGroupInfo[1]); // Name 64 System.out.println(" " + threadGroupInfo[2]); // Priority 65 System.out.println(" " + threadGroupInfo[3]); // Daemon 66 } 67 68 private static void checkChildren(ThreadGroup tg) { 69 Object[] data = getThreadGroupChildren(tg); 70 Thread[] threads = (Thread[])data[0]; 71 ThreadGroup[] groups = (ThreadGroup[])data[1]; 72 73 List<Thread> threadList = new ArrayList<>(Arrays.asList(threads)); 74 75 // Filter out JIT thread. It may or may not be there depending on configuration. 76 Iterator<Thread> it = threadList.iterator(); 77 while (it.hasNext()) { 78 Thread t = it.next(); 79 if (t.getName().startsWith("Jit thread pool worker")) { 80 it.remove(); 81 break; 82 } 83 } 84 85 Collections.sort(threadList, THREAD_COMP); 86 87 Arrays.sort(groups, THREADGROUP_COMP); 88 System.out.println(tg.getName() + ":"); 89 System.out.println(" " + threadList); 90 System.out.println(" " + Arrays.toString(groups)); 91 92 if (tg.getParent() != null) { 93 checkChildren(tg.getParent()); 94 } 95 } 96 97 private static void waitGroupChildren(ThreadGroup tg, int expectedChildCount, int timeoutS) 98 throws Exception { 99 for (int i = 0; i < timeoutS; i++) { 100 Object[] data = getThreadGroupChildren(tg); 101 Thread[] threads = (Thread[])data[0]; 102 if (threads.length == expectedChildCount) { 103 return; 104 } 105 Thread.sleep(1000); 106 } 107 108 Object[] data = getThreadGroupChildren(tg); 109 Thread[] threads = (Thread[])data[0]; 110 System.out.println(Arrays.toString(threads)); 111 throw new RuntimeException("Waited unsuccessfully for " + expectedChildCount + " children."); 112 } 113 114 private final static Comparator<Thread> THREAD_COMP = new Comparator<Thread>() { 115 public int compare(Thread o1, Thread o2) { 116 return o1.getName().compareTo(o2.getName()); 117 } 118 }; 119 120 private final static Comparator<ThreadGroup> THREADGROUP_COMP = new Comparator<ThreadGroup>() { 121 public int compare(ThreadGroup o1, ThreadGroup o2) { 122 return o1.getName().compareTo(o2.getName()); 123 } 124 }; 125 126 private static native ThreadGroup[] getTopThreadGroups(); 127 private static native Object[] getThreadGroupInfo(ThreadGroup tg); 128 // Returns an array where element 0 is an array of threads and element 1 is an array of groups. 129 private static native Object[] getThreadGroupChildren(ThreadGroup tg); 130} 131