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 } 49 Allocations after = new Allocations(DdmVmInternal.getRecentAllocations()); 50 System.out.println("before < overflowAllocations=" + (before.numberOfEntries < overflowAllocations)); 51 System.out.println("after > before=" + (after.numberOfEntries > before.numberOfEntries)); 52 System.out.println("after.numberOfEntries=" + after.numberOfEntries); 53 54 System.out.println("Disable and confirm back to empty"); 55 DdmVmInternal.enableRecentAllocations(false); 56 System.out.println("status=" + DdmVmInternal.getRecentAllocationStatus()); 57 Allocations reset = new Allocations(DdmVmInternal.getRecentAllocations()); 58 System.out.println("reset=" + reset); 59 60 System.out.println("Confirm we can disable twice in a row"); 61 DdmVmInternal.enableRecentAllocations(false); 62 System.out.println("status=" + DdmVmInternal.getRecentAllocationStatus()); 63 DdmVmInternal.enableRecentAllocations(false); 64 System.out.println("status=" + DdmVmInternal.getRecentAllocationStatus()); 65 66 System.out.println("Confirm we can reenable twice in a row without losing allocations"); 67 DdmVmInternal.enableRecentAllocations(true); 68 System.out.println("status=" + DdmVmInternal.getRecentAllocationStatus()); 69 for (int i = 0; i < 16 * 1024; i++) { 70 new String("fnord"); 71 } 72 Allocations first = new Allocations(DdmVmInternal.getRecentAllocations()); 73 DdmVmInternal.enableRecentAllocations(true); 74 System.out.println("status=" + DdmVmInternal.getRecentAllocationStatus()); 75 Allocations second = new Allocations(DdmVmInternal.getRecentAllocations()); 76 System.out.println("second > first =" + (second.numberOfEntries > first.numberOfEntries)); 77 78 System.out.println("Goodbye"); 79 DdmVmInternal.enableRecentAllocations(false); 80 Allocations goodbye = new Allocations(DdmVmInternal.getRecentAllocations()); 81 System.out.println("goodbye=" + goodbye); 82 } 83 84 private static class Allocations { 85 final int messageHeaderLen; 86 final int entryHeaderLen; 87 final int stackFrameLen; 88 final int numberOfEntries; 89 final int offsetToStringTableFromStartOfMessage; 90 final int numberOfClassNameStrings; 91 final int numberOfMethodNameStrings; 92 final int numberOfSourceFileNameStrings; 93 Allocations(byte[] allocations)94 Allocations(byte[] allocations) { 95 ByteBuffer b = ByteBuffer.wrap(allocations); 96 messageHeaderLen = b.get() & 0xff; 97 if (messageHeaderLen != 15) { 98 throw new IllegalArgumentException("Unexpected messageHeaderLen " + messageHeaderLen); 99 } 100 entryHeaderLen = b.get() & 0xff; 101 if (entryHeaderLen != 9) { 102 throw new IllegalArgumentException("Unexpected entryHeaderLen " + entryHeaderLen); 103 } 104 stackFrameLen = b.get() & 0xff; 105 if (stackFrameLen != 8) { 106 throw new IllegalArgumentException("Unexpected messageHeaderLen " + stackFrameLen); 107 } 108 numberOfEntries = b.getShort() & 0xffff; 109 offsetToStringTableFromStartOfMessage = b.getInt(); 110 numberOfClassNameStrings = b.getShort() & 0xffff; 111 numberOfMethodNameStrings = b.getShort() & 0xffff; 112 numberOfSourceFileNameStrings = b.getShort() & 0xffff; 113 } 114 toString()115 public String toString() { 116 return ("Allocations[message header len: " + messageHeaderLen + 117 " entry header len: " + entryHeaderLen + 118 " stack frame len: " + stackFrameLen + 119 " number of entries: " + numberOfEntries + 120 " offset to string table from start of message: " + offsetToStringTableFromStartOfMessage + 121 " number of class name strings: " + numberOfClassNameStrings + 122 " number of method name strings: " + numberOfMethodNameStrings + 123 " number of source file name strings: " + numberOfSourceFileNameStrings + 124 "]"); 125 } 126 } 127 128 private static class DdmVmInternal { 129 private static final Method enableRecentAllocationsMethod; 130 private static final Method getRecentAllocationStatusMethod; 131 private static final Method getRecentAllocationsMethod; 132 static { 133 try { 134 Class c = Class.forName("org.apache.harmony.dalvik.ddmc.DdmVmInternal"); 135 enableRecentAllocationsMethod = c.getDeclaredMethod("enableRecentAllocations", 136 Boolean.TYPE); 137 getRecentAllocationStatusMethod = c.getDeclaredMethod("getRecentAllocationStatus"); 138 getRecentAllocationsMethod = c.getDeclaredMethod("getRecentAllocations"); 139 } catch (Exception e) { 140 throw new RuntimeException(e); 141 } 142 } 143 enableRecentAllocations(boolean enable)144 public static void enableRecentAllocations(boolean enable) throws Exception { 145 enableRecentAllocationsMethod.invoke(null, enable); 146 } getRecentAllocationStatus()147 public static boolean getRecentAllocationStatus() throws Exception { 148 return (boolean) getRecentAllocationStatusMethod.invoke(null); 149 } getRecentAllocations()150 public static byte[] getRecentAllocations() throws Exception { 151 return (byte[]) getRecentAllocationsMethod.invoke(null); 152 } 153 } 154 } 155