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