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