
com.android.ddmlib.HandleNativeHeap Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ddmlib Show documentation
Show all versions of ddmlib Show documentation
Library providing APIs to talk to Android devices
/*
* 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.ddmlib;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
/**
* Handle thread status updates.
*/
final class HandleNativeHeap extends ChunkHandler {
public static final int CHUNK_NHGT = type("NHGT"); //$NON-NLS-1$
public static final int CHUNK_NHSG = type("NHSG"); //$NON-NLS-1$
public static final int CHUNK_NHST = type("NHST"); //$NON-NLS-1$
public static final int CHUNK_NHEN = type("NHEN"); //$NON-NLS-1$
private static final HandleNativeHeap mInst = new HandleNativeHeap();
/**
* Handle getting different sized size_t and pointer reads.
*/
abstract class NativeBuffer {
public NativeBuffer(ByteBuffer buffer) {
mBuffer = buffer;
}
public abstract int getSizeT();
public abstract long getPtr();
protected ByteBuffer mBuffer;
}
/**
* This class treats size_t and pointer values as 32 bit.
*/
final class NativeBuffer32 extends NativeBuffer {
public NativeBuffer32(ByteBuffer buffer) {
super(buffer);
}
@Override
public int getSizeT() {
return mBuffer.getInt();
}
@Override
public long getPtr() {
return (long)mBuffer.getInt() & 0x00000000ffffffffL;
}
}
/**
* This class treats size_t and pointer values as 64 bit.
*/
final class NativeBuffer64 extends NativeBuffer {
public NativeBuffer64(ByteBuffer buffer) {
super(buffer);
}
@Override
public int getSizeT() {
return (int)mBuffer.getLong();
}
@Override
public long getPtr() {
return mBuffer.getLong();
}
}
private HandleNativeHeap() {
}
/**
* Register for the packets we expect to get from the client.
*/
public static void register(MonitorThread mt) {
mt.registerChunkHandler(CHUNK_NHGT, mInst);
mt.registerChunkHandler(CHUNK_NHSG, mInst);
mt.registerChunkHandler(CHUNK_NHST, mInst);
mt.registerChunkHandler(CHUNK_NHEN, mInst);
}
/**
* Client is ready.
*/
@Override
public void clientReady(Client client) throws IOException {}
/**
* Client went away.
*/
@Override
public void clientDisconnected(Client client) {}
/**
* Chunk handler entry point.
*/
@Override
public void handleChunk(Client client, int type, ByteBuffer data, boolean isReply, int msgId) {
Log.d("ddm-nativeheap", "handling " + ChunkHandler.name(type));
if (type == CHUNK_NHGT) {
handleNHGT(client, data);
} else if (type == CHUNK_NHST) {
// start chunk before any NHSG chunk(s)
client.getClientData().getNativeHeapData().clearHeapData();
} else if (type == CHUNK_NHEN) {
// end chunk after NHSG chunk(s)
client.getClientData().getNativeHeapData().sealHeapData();
} else if (type == CHUNK_NHSG) {
handleNHSG(client, data);
} else {
handleUnknownChunk(client, type, data, isReply, msgId);
}
client.update(Client.CHANGE_NATIVE_HEAP_DATA);
}
/**
* Send an NHGT (Native Thread GeT) request to the client.
*/
public static void sendNHGT(Client client) throws IOException {
ByteBuffer rawBuf = allocBuffer(0);
JdwpPacket packet = new JdwpPacket(rawBuf);
ByteBuffer buf = getChunkDataBuf(rawBuf);
// no data in request message
finishChunkPacket(packet, CHUNK_NHGT, buf.position());
Log.d("ddm-nativeheap", "Sending " + name(CHUNK_NHGT));
client.send(packet, mInst);
rawBuf = allocBuffer(2);
packet = new JdwpPacket(rawBuf);
buf = getChunkDataBuf(rawBuf);
buf.put((byte)HandleHeap.WHEN_DISABLE);
buf.put((byte)HandleHeap.WHAT_OBJ);
finishChunkPacket(packet, CHUNK_NHSG, buf.position());
Log.d("ddm-nativeheap", "Sending " + name(CHUNK_NHSG));
client.send(packet, mInst);
}
/*
* Handle our native heap data.
*/
private void handleNHGT(Client client, ByteBuffer data) {
ClientData clientData = client.getClientData();
Log.d("ddm-nativeheap", "NHGT: " + data.limit() + " bytes");
data.order(ByteOrder.LITTLE_ENDIAN);
// There are two supported header formats.
//
// The original version of the header for 32 bit processes:
//
// uint32_t mapSize;
// uint32_t mapSize;
// uint32_t allocSize;
// uint32_t allocInfoSize;
// uint32_t totalMemory;
// uint32_t backtrace_size;
//
// The new header which includes a signature and pointer size:
//
// uint32_t signature; (Which is always 0x812345dd)
// uint16_t version; (Only version 2 of the new format supported)
// uint16_t pointerSize; (Size in bytes of size_t/pointer values)
// size_t mapSize;
// size_t allocSize;
// size_t allocInfoSize;
// size_t totalMemory;
// size_t backtrace_size;
//
// If the signature doesn't match, then the code uses the original
// header format. If the signature matches, then use the new
// header format with variable sizes of size_t and pointers.
int signature = data.getInt(0);
short pointerSize = 4;
if (signature == 0x812345dd) {
// Consume signature value.
int ignore = data.getInt();
short version = data.getShort();
if (version != 2) {
Log.e("ddms", "Unknown header version: " + version);
return;
}
pointerSize = data.getShort();
}
NativeBuffer buffer;
if (pointerSize == 4) {
buffer = new NativeBuffer32(data);
} else if (pointerSize == 8) {
buffer = new NativeBuffer64(data);
} else {
Log.e("ddms", "Unknown pointer size: " + pointerSize);
return;
}
// clear the previous run
clientData.clearNativeAllocationInfo();
int mapSize = buffer.getSizeT();
int allocSize = buffer.getSizeT();
int allocInfoSize = buffer.getSizeT();
int totalMemory = buffer.getSizeT();
int backtraceSize = buffer.getSizeT();
Log.d("ddms", "mapSize: " + mapSize);
Log.d("ddms", "allocSize: " + allocSize);
Log.d("ddms", "allocInfoSize: " + allocInfoSize);
Log.d("ddms", "totalMemory: " + totalMemory);
clientData.setTotalNativeMemory(totalMemory);
// this means that updates aren't turned on.
if (allocInfoSize == 0) {
return;
}
if (mapSize > 0) {
byte[] maps = new byte[mapSize];
data.get(maps, 0, mapSize);
parseMaps(clientData, maps);
}
int iterations = allocSize / allocInfoSize;
for (int i = 0 ; i < iterations ; i++) {
NativeAllocationInfo info = new NativeAllocationInfo(
buffer.getSizeT() /* size */,
buffer.getSizeT() /* allocations */);
for (int j = 0 ; j < backtraceSize ; j++) {
long addr = buffer.getPtr();
if (addr == 0x0) {
// skip past null addresses
continue;
}
info.addStackCallAddress(addr);
}
clientData.addNativeAllocation(info);
}
}
private void handleNHSG(Client client, ByteBuffer data) {
byte dataCopy[] = new byte[data.limit()];
data.rewind();
data.get(dataCopy);
data = ByteBuffer.wrap(dataCopy);
client.getClientData().getNativeHeapData().addHeapData(data);
if (true) {
return;
}
byte[] copy = new byte[data.limit()];
data.get(copy);
ByteBuffer buffer = ByteBuffer.wrap(copy);
buffer.order(ByteOrder.BIG_ENDIAN);
int id = buffer.getInt();
int unitsize = buffer.get();
long startAddress = buffer.getInt() & 0x00000000ffffffffL;
int offset = buffer.getInt();
int allocationUnitCount = buffer.getInt();
// read the usage
while (buffer.position() < buffer.limit()) {
int eState = buffer.get() & 0x000000ff;
int eLen = (buffer.get() & 0x000000ff) + 1;
}
}
private void parseMaps(ClientData clientData, byte[] maps) {
InputStreamReader input = new InputStreamReader(new ByteArrayInputStream(maps));
BufferedReader reader = new BufferedReader(input);
String line;
try {
while ((line = reader.readLine()) != null) {
Log.d("ddms", "line: " + line);
// Expected format:
// 7fe51f2000-7fe5213000 rw-p 00000000 00:00 0 [stack]
int library_start = line.lastIndexOf(' ');
if (library_start == -1) {
continue;
}
// Assume that any string that starts with a / is a
// shared library or executable that we will try to symbolize.
String library = line.substring(library_start+1);
if (!library.startsWith("/")) {
continue;
}
// Parse the start and end address range.
int dashIndex = line.indexOf('-');
int spaceIndex = line.indexOf(' ', dashIndex);
if (dashIndex == -1 || spaceIndex == -1) {
continue;
}
long startAddr = 0;
long endAddr = 0;
try {
startAddr = Long.parseLong(line.substring(0, dashIndex), 16);
endAddr = Long.parseLong(line.substring(dashIndex+1, spaceIndex), 16);
} catch (NumberFormatException e) {
e.printStackTrace();
continue;
}
clientData.addNativeLibraryMapInfo(startAddr, endAddr, library);
Log.d("ddms", library + "(" + Long.toHexString(startAddr) +
" - " + Long.toHexString(endAddr) + ")");
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy