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.Method; 18 import java.nio.ByteBuffer; 19 20 public class Main { main(String[] args)21 public static void main(String[] args) throws Exception { 22 String name = System.getProperty("java.vm.name"); 23 if (!"Dalvik".equals(name)) { 24 System.out.println("This test is not supported on " + name); 25 return; 26 } 27 testRecentAllocationTracking(); 28 } 29 testRecentAllocationTracking()30 private static void testRecentAllocationTracking() throws Exception { 31 System.out.println("Confirm empty"); 32 Allocations empty = new Allocations(DdmVmInternal.getRecentAllocations()); 33 System.out.println("empty=" + empty); 34 35 System.out.println("Confirm enable"); 36 System.out.println("status=" + DdmVmInternal.getRecentAllocationStatus()); 37 DdmVmInternal.enableRecentAllocations(true); 38 System.out.println("status=" + DdmVmInternal.getRecentAllocationStatus()); 39 40 System.out.println("Capture some allocations (note just this causes allocations)"); 41 Allocations before = new Allocations(DdmVmInternal.getRecentAllocations()); 42 System.out.println("before > 0=" + (before.numberOfEntries > 0)); 43 44 System.out.println("Confirm when we overflow, we don't roll over to zero. b/17392248"); 45 final int overflowAllocations = 64 * 1024; // Won't fit in unsigned 16-bit value. 46 for (int i = 0; i < overflowAllocations; i++) { 47 new Object() { 48 // Add a finalizer so that the allocation won't be eliminated. 49 public void finalize() { 50 System.out.print(""); 51 } 52 }; 53 } 54 Allocations after = new Allocations(DdmVmInternal.getRecentAllocations()); 55 System.out.println("before < overflowAllocations=" + (before.numberOfEntries < overflowAllocations)); 56 System.out.println("after > before=" + (after.numberOfEntries > before.numberOfEntries)); 57 System.out.println("after.numberOfEntries=" + after.numberOfEntries); 58 59 System.out.println("Disable and confirm back to empty"); 60 DdmVmInternal.enableRecentAllocations(false); 61 System.out.println("status=" + DdmVmInternal.getRecentAllocationStatus()); 62 Allocations reset = new Allocations(DdmVmInternal.getRecentAllocations()); 63 System.out.println("reset=" + reset); 64 65 System.out.println("Confirm we can disable twice in a row"); 66 DdmVmInternal.enableRecentAllocations(false); 67 System.out.println("status=" + DdmVmInternal.getRecentAllocationStatus()); 68 DdmVmInternal.enableRecentAllocations(false); 69 System.out.println("status=" + DdmVmInternal.getRecentAllocationStatus()); 70 71 System.out.println("Confirm we can reenable twice in a row without losing allocations"); 72 DdmVmInternal.enableRecentAllocations(true); 73 System.out.println("status=" + DdmVmInternal.getRecentAllocationStatus()); 74 for (int i = 0; i < 16 * 1024; i++) { 75 new String("fnord"); 76 } 77 Allocations first = new Allocations(DdmVmInternal.getRecentAllocations()); 78 DdmVmInternal.enableRecentAllocations(true); 79 System.out.println("status=" + DdmVmInternal.getRecentAllocationStatus()); 80 Allocations second = new Allocations(DdmVmInternal.getRecentAllocations()); 81 System.out.println("second > first =" + (second.numberOfEntries > first.numberOfEntries)); 82 83 System.out.println("Goodbye"); 84 DdmVmInternal.enableRecentAllocations(false); 85 Allocations goodbye = new Allocations(DdmVmInternal.getRecentAllocations()); 86 System.out.println("goodbye=" + goodbye); 87 } 88 89 private static class Allocations { 90 final int messageHeaderLen; 91 final int entryHeaderLen; 92 final int stackFrameLen; 93 final int numberOfEntries; 94 final int offsetToStringTableFromStartOfMessage; 95 final int numberOfClassNameStrings; 96 final int numberOfMethodNameStrings; 97 final int numberOfSourceFileNameStrings; 98 Allocations(byte[] allocations)99 Allocations(byte[] allocations) { 100 ByteBuffer b = ByteBuffer.wrap(allocations); 101 messageHeaderLen = b.get() & 0xff; 102 if (messageHeaderLen != 15) { 103 throw new IllegalArgumentException("Unexpected messageHeaderLen " + messageHeaderLen); 104 } 105 entryHeaderLen = b.get() & 0xff; 106 if (entryHeaderLen != 9) { 107 throw new IllegalArgumentException("Unexpected entryHeaderLen " + entryHeaderLen); 108 } 109 stackFrameLen = b.get() & 0xff; 110 if (stackFrameLen != 8) { 111 throw new IllegalArgumentException("Unexpected messageHeaderLen " + stackFrameLen); 112 } 113 numberOfEntries = b.getShort() & 0xffff; 114 offsetToStringTableFromStartOfMessage = b.getInt(); 115 numberOfClassNameStrings = b.getShort() & 0xffff; 116 numberOfMethodNameStrings = b.getShort() & 0xffff; 117 numberOfSourceFileNameStrings = b.getShort() & 0xffff; 118 } 119 toString()120 public String toString() { 121 return ("Allocations[message header len: " + messageHeaderLen + 122 " entry header len: " + entryHeaderLen + 123 " stack frame len: " + stackFrameLen + 124 " number of entries: " + numberOfEntries + 125 " offset to string table from start of message: " + offsetToStringTableFromStartOfMessage + 126 " number of class name strings: " + numberOfClassNameStrings + 127 " number of method name strings: " + numberOfMethodNameStrings + 128 " number of source file name strings: " + numberOfSourceFileNameStrings + 129 "]"); 130 } 131 } 132 133 private static class DdmVmInternal { 134 private static final Method enableRecentAllocationsMethod; 135 private static final Method getRecentAllocationStatusMethod; 136 private static final Method getRecentAllocationsMethod; 137 static { 138 try { 139 Class<?> c = Class.forName("org.apache.harmony.dalvik.ddmc.DdmVmInternal"); 140 enableRecentAllocationsMethod = c.getDeclaredMethod("enableRecentAllocations", 141 Boolean.TYPE); 142 getRecentAllocationStatusMethod = c.getDeclaredMethod("getRecentAllocationStatus"); 143 getRecentAllocationsMethod = c.getDeclaredMethod("getRecentAllocations"); 144 } catch (Exception e) { 145 throw new RuntimeException(e); 146 } 147 } 148 enableRecentAllocations(boolean enable)149 public static void enableRecentAllocations(boolean enable) throws Exception { 150 enableRecentAllocationsMethod.invoke(null, enable); 151 } getRecentAllocationStatus()152 public static boolean getRecentAllocationStatus() throws Exception { 153 return (boolean) getRecentAllocationStatusMethod.invoke(null); 154 } getRecentAllocations()155 public static byte[] getRecentAllocations() throws Exception { 156 return (byte[]) getRecentAllocationsMethod.invoke(null); 157 } 158 } 159 } 160