/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.ddmuilib; import com.android.ddmlib.HeapSegment; import com.android.ddmlib.ClientData.HeapData; import com.android.ddmlib.HeapSegment.HeapSegmentElement; import org.eclipse.swt.graphics.ImageData; import org.eclipse.swt.graphics.PaletteData; import java.io.ByteArrayOutputStream; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.Map; import java.util.TreeMap; /** * Base Panel for heap panels. */ public abstract class BaseHeapPanel extends TablePanel { /** store the processed heap segment, so that we don't recompute Image for nothing */ protected byte[] mProcessedHeapData; private Map<Integer, ArrayList<HeapSegmentElement>> mHeapMap; /** * Serialize the heap data into an array. The resulting array is available through * <code>getSerializedData()</code>. * @param heapData The heap data to serialize * @return true if the data changed. */ protected boolean serializeHeapData(HeapData heapData) { Collection<HeapSegment> heapSegments; // Atomically get and clear the heap data. synchronized (heapData) { // get the segments heapSegments = heapData.getHeapSegments(); if (heapSegments != null) { // if they are not null, we never processed them. // Before we process then, we drop them from the HeapData heapData.clearHeapData(); // process them into a linear byte[] doSerializeHeapData(heapSegments); heapData.setProcessedHeapData(mProcessedHeapData); heapData.setProcessedHeapMap(mHeapMap); } else { // the heap segments are null. Let see if the heapData contains a // list that is already processed. byte[] pixData = heapData.getProcessedHeapData(); // and compare it to the one we currently have in the panel. if (pixData == mProcessedHeapData) { // looks like its the same return false; } else { mProcessedHeapData = pixData; } Map<Integer, ArrayList<HeapSegmentElement>> heapMap = heapData.getProcessedHeapMap(); mHeapMap = heapMap; } } return true; } /** * Returns the serialized heap data */ protected byte[] getSerializedData() { return mProcessedHeapData; } /** * Processes and serialize the heapData. * <p/> * The resulting serialized array is {@link #mProcessedHeapData}. * <p/> * the resulting map is {@link #mHeapMap}. * @param heapData the collection of {@link HeapSegment} that forms the heap data. */ private void doSerializeHeapData(Collection<HeapSegment> heapData) { mHeapMap = new TreeMap<Integer, ArrayList<HeapSegmentElement>>(); Iterator<HeapSegment> iterator; ByteArrayOutputStream out; out = new ByteArrayOutputStream(4 * 1024); iterator = heapData.iterator(); while (iterator.hasNext()) { HeapSegment hs = iterator.next(); HeapSegmentElement e = null; while (true) { int v; e = hs.getNextElement(null); if (e == null) { break; } if (e.getSolidity() == HeapSegmentElement.SOLIDITY_FREE) { v = 1; } else { v = e.getKind() + 2; } // put the element in the map ArrayList<HeapSegmentElement> elementList = mHeapMap.get(v); if (elementList == null) { elementList = new ArrayList<HeapSegmentElement>(); mHeapMap.put(v, elementList); } elementList.add(e); int len = e.getLength() / 8; while (len > 0) { out.write(v); --len; } } } mProcessedHeapData = out.toByteArray(); // sort the segment element in the heap info. Collection<ArrayList<HeapSegmentElement>> elementLists = mHeapMap.values(); for (ArrayList<HeapSegmentElement> elementList : elementLists) { Collections.sort(elementList); } } /** * Creates a linear image of the heap data. * @param pixData * @param h * @param palette * @return */ protected ImageData createLinearHeapImage(byte[] pixData, int h, PaletteData palette) { int w = pixData.length / h; if (pixData.length % h != 0) { w++; } // Create the heap image. ImageData id = new ImageData(w, h, 8, palette); int x = 0; int y = 0; for (byte b : pixData) { if (b >= 0) { id.setPixel(x, y, b); } y++; if (y >= h) { y = 0; x++; } } return id; } }