Brian Carlstrom | 306db81 | 2014-09-05 13:01:41 -0700 | [diff] [blame] | 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 { |
| 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 | |
| 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 String("fnord"); |
| 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 | |
| 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 | |
| 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 | |
| 144 | public static void enableRecentAllocations(boolean enable) throws Exception { |
| 145 | enableRecentAllocationsMethod.invoke(null, enable); |
| 146 | } |
| 147 | public static boolean getRecentAllocationStatus() throws Exception { |
| 148 | return (boolean) getRecentAllocationStatusMethod.invoke(null); |
| 149 | } |
| 150 | public static byte[] getRecentAllocations() throws Exception { |
| 151 | return (byte[]) getRecentAllocationsMethod.invoke(null); |
| 152 | } |
| 153 | } |
| 154 | } |