1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5  * in compliance with the License. You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the License
10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11  * or implied. See the License for the specific language governing permissions and limitations under
12  * the License.
13  */
14 package android.jvmti.cts;
15 
16 import static org.junit.Assert.assertEquals;
17 import static org.junit.Assert.assertTrue;
18 
19 import java.util.ArrayList;
20 import org.junit.Before;
21 import org.junit.Test;
22 
23 import art.Main;
24 
25 /**
26  * Check tracking-related functionality.
27  */
28 public class JvmtiTrackingTest extends JvmtiTestBase {
29 
30     @Before
setUp()31     public void setUp() throws Exception {
32         prefetchClassNames();
33     }
34 
35     // Pre-resolve class names so the strings don't have to be allocated as a side effect of
36     // callback printing.
prefetchClassNames()37     private static void prefetchClassNames() {
38         Object.class.getName();
39         Integer.class.getName();
40         Float.class.getName();
41         Short.class.getName();
42         Byte.class.getName();
43         Double.class.getName();
44     }
45 
46     private ArrayList<Object> l = new ArrayList<>(100);
47 
48     @Test
testTracking()49     public void testTracking() throws Exception {
50         // Disable the global registration from OnLoad, to get into a known state.
51         enableAllocationTracking(null, false);
52 
53         assertEquals(null, getAndResetAllocationTrackingString());
54 
55         // Enable actual logging callback.
56         setupObjectAllocCallback(true);
57 
58         enableAllocationTracking(null, true);
59 
60         l.add(new Object());
61         l.add(new Integer(1));
62 
63         enableAllocationTracking(null, false);
64 
65         String trackingString = getAndResetAllocationTrackingString();
66         String object_line = "ObjectAllocated type java.lang.Object/java.lang.Object size 8#";
67         String integer_line = "ObjectAllocated type java.lang.Integer/java.lang.Integer size 16#";
68         assertTrue("does not contain " + object_line, trackingString.contains(object_line));
69         assertTrue("does not contain " + integer_line, trackingString.contains(integer_line));
70 
71         l.add(new Float(1.0f));
72 
73         assertEquals(null, getAndResetAllocationTrackingString());
74 
75         enableAllocationTracking(Thread.currentThread(), true);
76 
77         l.add(new Short((short) 0));
78 
79         enableAllocationTracking(Thread.currentThread(), false);
80 
81         assertEquals("ObjectAllocated type java.lang.Short/java.lang.Short size 16#",
82                 getAndResetAllocationTrackingString());
83 
84         l.add(new Byte((byte) 0));
85 
86         assertEquals(null, getAndResetAllocationTrackingString());
87 
88         testThread(l, true, true);
89 
90         l.add(new Byte((byte) 0));
91 
92         assertEquals("ObjectAllocated type java.lang.Double/java.lang.Double size 16#",
93                 getAndResetAllocationTrackingString());
94 
95         testThread(l, true, false);
96 
97         assertEquals("ObjectAllocated type java.lang.Double/java.lang.Double size 16#",
98                 getAndResetAllocationTrackingString());
99 
100         System.out.println("Tracking on different thread");
101 
102         testThread(l, false, true);
103 
104         l.add(new Byte((byte) 0));
105 
106         // Disable actual logging callback and re-enable tracking, so we can keep the event enabled
107         // and
108         // check that shutdown works correctly.
109         setupObjectAllocCallback(false);
110         enableAllocationTracking(null, true);
111 
112         assertEquals(null, getAndResetAllocationTrackingString());
113     }
114 
testThread(final ArrayList<Object> l, final boolean sameThread, final boolean disableTracking)115     private static void testThread(final ArrayList<Object> l, final boolean sameThread,
116             final boolean disableTracking) throws Exception {
117         final SimpleBarrier startBarrier = new SimpleBarrier(1);
118         final SimpleBarrier trackBarrier = new SimpleBarrier(1);
119 
120         final Thread thisThread = Thread.currentThread();
121 
122         Thread t = new Thread() {
123             @Override
124             public void run() {
125                 try {
126                     startBarrier.dec();
127                     trackBarrier.waitFor();
128                 } catch (Exception e) {
129                     e.printStackTrace(System.out);
130                     System.exit(1);
131                 }
132 
133                 l.add(new Double(0.0));
134 
135                 if (disableTracking) {
136                     enableAllocationTracking(sameThread ? this : thisThread, false);
137                 }
138             }
139         };
140 
141         t.start();
142         startBarrier.waitFor();
143         enableAllocationTracking(sameThread ? t : Thread.currentThread(), true);
144         trackBarrier.dec();
145 
146         t.join();
147     }
148 
149     // Our own little barrier, to avoid behind-the-scenes allocations.
150     private static class SimpleBarrier {
151         int count;
152 
SimpleBarrier(int i)153         public SimpleBarrier(int i) {
154             count = i;
155         }
156 
dec()157         public synchronized void dec() throws Exception {
158             count--;
159             notifyAll();
160         }
161 
waitFor()162         public synchronized void waitFor() throws Exception {
163             while (count != 0) {
164                 wait();
165             }
166         }
167     }
168 
setupObjectAllocCallback(boolean enable)169     private static native void setupObjectAllocCallback(boolean enable);
170 
enableAllocationTracking(Thread thread, boolean enable)171     private static native void enableAllocationTracking(Thread thread, boolean enable);
172 
getAndResetAllocationTrackingString()173     private static native String getAndResetAllocationTrackingString();
174 }
175