1 /* 2 * Copyright (C) 2008 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 package com.android.ddmlib; 18 19 import java.util.Comparator; 20 import java.util.Locale; 21 22 /** 23 * Holds an Allocation information. 24 */ 25 public class AllocationInfo implements IStackTraceInfo { 26 private final String mAllocatedClass; 27 private final int mAllocNumber; 28 private final int mAllocationSize; 29 private final short mThreadId; 30 private final StackTraceElement[] mStackTrace; 31 32 public static enum SortMode { 33 NUMBER, SIZE, CLASS, THREAD, IN_CLASS, IN_METHOD; 34 } 35 36 public final static class AllocationSorter implements Comparator<AllocationInfo> { 37 38 private SortMode mSortMode = SortMode.SIZE; 39 private boolean mDescending = true; 40 AllocationSorter()41 public AllocationSorter() { 42 } 43 setSortMode(SortMode mode)44 public void setSortMode(SortMode mode) { 45 if (mSortMode == mode) { 46 mDescending = !mDescending; 47 } else { 48 mSortMode = mode; 49 } 50 } 51 getSortMode()52 public SortMode getSortMode() { 53 return mSortMode; 54 } 55 isDescending()56 public boolean isDescending() { 57 return mDescending; 58 } 59 60 @Override compare(AllocationInfo o1, AllocationInfo o2)61 public int compare(AllocationInfo o1, AllocationInfo o2) { 62 int diff = 0; 63 switch (mSortMode) { 64 case NUMBER: 65 diff = o1.mAllocNumber - o2.mAllocNumber; 66 break; 67 case SIZE: 68 // pass, since diff is init with 0, we'll use SIZE compare below 69 // as a back up anyway. 70 break; 71 case CLASS: 72 diff = o1.mAllocatedClass.compareTo(o2.mAllocatedClass); 73 break; 74 case THREAD: 75 diff = o1.mThreadId - o2.mThreadId; 76 break; 77 case IN_CLASS: 78 String class1 = o1.getFirstTraceClassName(); 79 String class2 = o2.getFirstTraceClassName(); 80 diff = compareOptionalString(class1, class2); 81 break; 82 case IN_METHOD: 83 String method1 = o1.getFirstTraceMethodName(); 84 String method2 = o2.getFirstTraceMethodName(); 85 diff = compareOptionalString(method1, method2); 86 break; 87 } 88 89 if (diff == 0) { 90 // same? compare on size 91 diff = o1.mAllocationSize - o2.mAllocationSize; 92 } 93 94 if (mDescending) { 95 diff = -diff; 96 } 97 98 return diff; 99 } 100 101 /** compares two strings that could be null */ compareOptionalString(String str1, String str2)102 private int compareOptionalString(String str1, String str2) { 103 if (str1 != null) { 104 if (str2 == null) { 105 return -1; 106 } else { 107 return str1.compareTo(str2); 108 } 109 } else { 110 if (str2 == null) { 111 return 0; 112 } else { 113 return 1; 114 } 115 } 116 } 117 } 118 119 /* 120 * Simple constructor. 121 */ AllocationInfo(int allocNumber, String allocatedClass, int allocationSize, short threadId, StackTraceElement[] stackTrace)122 AllocationInfo(int allocNumber, String allocatedClass, int allocationSize, 123 short threadId, StackTraceElement[] stackTrace) { 124 mAllocNumber = allocNumber; 125 mAllocatedClass = allocatedClass; 126 mAllocationSize = allocationSize; 127 mThreadId = threadId; 128 mStackTrace = stackTrace; 129 } 130 131 /** 132 * Returns the allocation number. Allocations are numbered as they happen with the most 133 * recent one having the highest number 134 */ getAllocNumber()135 public int getAllocNumber() { 136 return mAllocNumber; 137 } 138 139 /** 140 * Returns the name of the allocated class. 141 */ getAllocatedClass()142 public String getAllocatedClass() { 143 return mAllocatedClass; 144 } 145 146 /** 147 * Returns the size of the allocation. 148 */ getSize()149 public int getSize() { 150 return mAllocationSize; 151 } 152 153 /** 154 * Returns the id of the thread that performed the allocation. 155 */ getThreadId()156 public short getThreadId() { 157 return mThreadId; 158 } 159 160 /* 161 * (non-Javadoc) 162 * @see com.android.ddmlib.IStackTraceInfo#getStackTrace() 163 */ 164 @Override getStackTrace()165 public StackTraceElement[] getStackTrace() { 166 return mStackTrace; 167 } 168 compareTo(AllocationInfo otherAlloc)169 public int compareTo(AllocationInfo otherAlloc) { 170 return otherAlloc.mAllocationSize - mAllocationSize; 171 } 172 getFirstTraceClassName()173 public String getFirstTraceClassName() { 174 if (mStackTrace.length > 0) { 175 return mStackTrace[0].getClassName(); 176 } 177 178 return null; 179 } 180 getFirstTraceMethodName()181 public String getFirstTraceMethodName() { 182 if (mStackTrace.length > 0) { 183 return mStackTrace[0].getMethodName(); 184 } 185 186 return null; 187 } 188 189 /** 190 * Returns true if the given filter matches case insensitively (according to 191 * the given locale) this allocation info. 192 */ filter(String filter, boolean fullTrace, Locale locale)193 public boolean filter(String filter, boolean fullTrace, Locale locale) { 194 if (mAllocatedClass.toLowerCase(locale).contains(filter)) { 195 return true; 196 } 197 198 if (mStackTrace.length > 0) { 199 // check the top of the stack trace always 200 final int length = fullTrace ? mStackTrace.length : 1; 201 202 for (int i = 0 ; i < length ; i++) { 203 if (mStackTrace[i].getClassName().toLowerCase(locale).contains(filter)) { 204 return true; 205 } 206 207 if (mStackTrace[i].getMethodName().toLowerCase(locale).contains(filter)) { 208 return true; 209 } 210 } 211 } 212 213 return false; 214 } 215 } 216