1 /*
2  * Copyright (C) 2014 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 
17 import java.lang.reflect.Field;
18 import java.util.Map;
19 
20 public class Main implements Runnable {
21     static final int NUMBER_OF_THREADS = 5;
22     static final int TOTAL_OPERATIONS = 900;
23 
main(String[] args)24     public static void main(String[] args) throws Exception {
25         final Thread[] threads = new Thread[NUMBER_OF_THREADS];
26         for (int t = 0; t < threads.length; t++) {
27             threads[t] = new Thread(new Main());
28             threads[t].start();
29         }
30         for (Thread t : threads) {
31             t.join();
32         }
33         // Do this test after the other part to leave some time for the heap task daemon to start
34         // up.
35         test_getStackTraces();
36         System.out.println("Finishing");
37     }
38 
getHeapTaskDaemon()39     static Thread getHeapTaskDaemon() throws Exception {
40         Field f = ThreadGroup.class.getDeclaredField("systemThreadGroup");
41         f.setAccessible(true);
42         ThreadGroup systemThreadGroup = (ThreadGroup) f.get(null);
43 
44         while (true) {
45             int activeCount = systemThreadGroup.activeCount();
46             Thread[] array = new Thread[activeCount];
47             systemThreadGroup.enumerate(array);
48             for (Thread thread : array) {
49                if (thread.getName().equals("HeapTaskDaemon") &&
50                    thread.getState() != Thread.State.NEW) {
51                   return thread;
52                 }
53             }
54             // Yield to eventually get the daemon started.
55             Thread.sleep(10);
56         }
57     }
58 
test_getStackTraces()59     static void test_getStackTraces() throws Exception {
60         Thread heapDaemon = getHeapTaskDaemon();
61 
62         // Force a GC to ensure the daemon truly started.
63         Runtime.getRuntime().gc();
64         // Check all the current threads for positive IDs.
65         Map<Thread, StackTraceElement[]> map = Thread.getAllStackTraces();
66         for (Map.Entry<Thread, StackTraceElement[]> pair : map.entrySet()) {
67             Thread thread = pair.getKey();
68             // Expect empty stack trace since we do not support suspending the GC thread for
69             // obtaining stack traces. See b/28261069.
70             if (thread == heapDaemon) {
71                 System.out.println(thread.getName() + " depth " + pair.getValue().length);
72             }
73         }
74     }
75 
test_getId()76     public void test_getId() {
77         if (Thread.currentThread().getId() <= 0) {
78             System.out.println("current thread's ID is not positive");
79         }
80         // Check all the current threads for positive IDs.
81         Map<Thread, StackTraceElement[]> stMap = Thread.getAllStackTraces();
82         for (Thread thread : stMap.keySet()) {
83             if (thread.getId() <= 0) {
84                 System.out.println("thread's ID is not positive: " + thread.getName());
85             }
86         }
87     }
88 
run()89     public void run() {
90         for (int i = 0; i < TOTAL_OPERATIONS; ++i) {
91             test_getId();
92         }
93     }
94 }
95