/* * Handle a reply to our WAIT message. */ private static void handleWAIT(Client client, ByteBuffer data) { var reason = data.get(); Log.d("ddm-wait", "WAIT: reason=" + reason); ClientData cd = client.clientData; lock (cd) { cd.debuggerConnectionStatus = ClientData.DebuggerStatus.WAITING; } client.update(Client.CHANGE_DEBUGGER_STATUS); }
/* * Handle HeaP Dump Streaming response. "data" contains the full * hprof dump. */ private void handleHPDS(Client client, ByteBuffer data) { ClientData.IHprofDumpHandler handler = ClientData.hprofDumpHandler; if (handler != null) { var stuff = new byte[data.capacity]; data.get(stuff, 0, stuff.Length); Log.d("ddm-hprof", "got hprof file, size: " + data.capacity + " bytes"); handler.onSuccess(stuff, client); } }
/* * Handle notification of completion of a HeaP DUmp. */ private void handleHPDU(Client client, ByteBuffer data) { // get the filename and make the client not have pending HPROF dump anymore. string filename = client.clientData.pendingHprofDump; client.clientData.pendingHprofDump = null; // get the dump result var result = data.get(); // get the app-level handler for HPROF dump ClientData.IHprofDumpHandler handler = ClientData.hprofDumpHandler; if (handler != null) { if (result == 0) { handler.onSuccess(filename, client); Log.d("ddm-heap", "Heap dump request has finished"); } else { handler.onEndFailure(client, null); Log.w("ddm-heap", "Heap dump request failed (check device log)"); } } }
/* * Handle a heap segment message. */ private void handleHPSG(Client client, ByteBuffer data) { var dataCopy = new byte[data.limit]; data.rewind(); data.get(dataCopy); data = ByteBuffer.wrap(dataCopy); client.clientData.vmHeapData.addHeapData(data); //xxx todo: add to the heap mentioned in <data> }
/* * Handle a heap info message. */ private void handleHPIF(Client client, ByteBuffer data) { Log.d("ddm-heap", "HPIF!"); try { int numHeaps = data.getInt(); for (int i = 0; i < numHeaps; i++) { int heapId = data.getInt(); //JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes: //ORIGINAL LINE: @SuppressWarnings("unused") long timeStamp = data.getLong(); long timeStamp = data.getLong(); //JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes: //ORIGINAL LINE: @SuppressWarnings("unused") byte reason = data.get(); var reason = data.get(); long maxHeapSize = (long)data.getInt() & 0x00ffffffff; long heapSize = (long)data.getInt() & 0x00ffffffff; long bytesAllocated = (long)data.getInt() & 0x00ffffffff; long objectsAllocated = (long)data.getInt() & 0x00ffffffff; client.clientData.setHeapInfo(heapId, maxHeapSize, heapSize, bytesAllocated, objectsAllocated); client.update(Client.CHANGE_HEAP_DATA); } } catch (BufferUnderflowException) { Log.w("ddm-heap", "malformed HPIF chunk from client"); } }
/* * Handle a thread creation message. */ private void handleTEST(Client client, ByteBuffer data) { /* * Can't call data.array() on a read-only ByteBuffer, so we make * a copy. */ var copy = new byte[data.limit]; data.get(copy); Log.d("ddm-test", "Received:"); Log.hexDump("ddm-test", Log.LogLevel.DEBUG, copy, 0, copy.Length); }
/// <summary> /// Receive response to query. /// </summary> private void handleMPRQ(Client client, ByteBuffer data) { var result = data.get(); if (result == 0) { client.clientData.methodProfilingStatus = ClientData.MethodProfilingStatus.OFF; Log.d("ddm-prof", "Method profiling is not running"); } else { client.clientData.methodProfilingStatus = ClientData.MethodProfilingStatus.ON; Log.d("ddm-prof", "Method profiling is running"); } client.update(Client.CHANGE_METHOD_PROFILING_STATUS); }
/* * Handle our native heap data. */ private void handleNHGT(Client client, ByteBuffer data) { ClientData cd = client.clientData; Log.d("ddm-nativeheap", "NHGT: " + data.limit + " bytes"); // TODO - process incoming data and save in "cd" var copy = new byte[data.limit]; data.get(copy); // clear the previous run cd.clearNativeAllocationInfo(); ByteBuffer buffer = ByteBuffer.wrap(copy); buffer.order = ByteOrder.LITTLE_ENDIAN; // read the header // typedef struct Header { // uint32_t mapSize; // uint32_t allocSize; // uint32_t allocInfoSize; // uint32_t totalMemory; // uint32_t backtraceSize; // }; int mapSize = buffer.getInt(); int allocSize = buffer.getInt(); int allocInfoSize = buffer.getInt(); int totalMemory = buffer.getInt(); int backtraceSize = buffer.getInt(); Log.d("ddms", "mapSize: " + mapSize); Log.d("ddms", "allocSize: " + allocSize); Log.d("ddms", "allocInfoSize: " + allocInfoSize); Log.d("ddms", "totalMemory: " + totalMemory); cd.totalNativeMemory = totalMemory; // this means that updates aren't turned on. if (allocInfoSize == 0) { return; } if (mapSize > 0) { var maps = new byte[mapSize]; buffer.get(maps, 0, mapSize); parseMaps(cd, maps); } int iterations = allocSize / allocInfoSize; for (int i = 0 ; i < iterations ; i++) { NativeAllocationInfo info = new NativeAllocationInfo(buffer.getInt(), buffer.getInt()); // allocations - size for (int j = 0 ; j < backtraceSize ; j++) { long addr = (buffer.getInt()) & 0x00000000ffffffffL; if (addr == 0x0) { // skip past null addresses continue; } info.addStackCallAddress(addr); } cd.addNativeAllocation(info); } }
/// <summary> /// Handle notification that method profiling has finished writing /// data to disk. /// </summary> private void handleMPRE(Client client, ByteBuffer data) { // get the filename and make the client not have pending HPROF dump anymore. string filename = client.clientData.pendingMethodProfiling; client.clientData.pendingMethodProfiling = null; byte result = data.get(); // get the app-level handler for method tracing dump ClientData.IMethodProfilingHandler handler = ClientData.methodProfilingHandler; if (handler != null) { if (result == 0) { handler.onSuccess(filename, client); Log.d("ddm-prof", "Method profiling has finished"); } else { handler.onEndFailure(client, null); //message Log.w("ddm-prof", "Method profiling has failed (check device log)"); } } client.clientData.methodProfilingStatus = ClientData.MethodProfilingStatus.OFF; client.update(Client.CHANGE_METHOD_PROFILING_STATUS); }
/// <summary> /// Handle incoming profiling data. The MPSE packet includes the /// complete .trace file. /// </summary> private void handleMPSE(Client client, ByteBuffer data) { ClientData.IMethodProfilingHandler handler = ClientData.methodProfilingHandler; if (handler != null) { var stuff = new byte[data.capacity]; data.get(stuff, 0, stuff.Length); Log.d("ddm-prof", "got trace file, size: " + stuff.Length + " bytes"); handler.onSuccess(stuff, client); } client.clientData.methodProfilingStatus = ClientData.MethodProfilingStatus.OFF; client.update(Client.CHANGE_METHOD_PROFILING_STATUS); }
/// <summary> /// Find the JDWP packet at the start of "buf". The start is known, /// but the length has to be parsed out. /// /// On entry, the packet data in "buf" must start at offset 0 and end /// at "position". "limit" should be set to the buffer capacity. This /// method does not alter "buf"s attributes. /// /// Returns a new JdwpPacket if a full one is found in the buffer. If /// not, returns null. Throws an exception if the data doesn't look like /// a valid JDWP packet. /// </summary> internal static JdwpPacket findPacket(ByteBuffer buf) { int count = buf.position; int length, id, flags, cmdSet, cmd; if (count < JDWP_HEADER_LEN) { return null; } ByteOrder oldOrder = buf.order; buf.order =(ChunkHandler.CHUNK_ORDER); length = buf.getInt(0x00); id = buf.getInt(0x04); flags = buf.get(0x08) & 0xff; cmdSet = buf.get(0x09) & 0xff; cmd = buf.get(0x0a) & 0xff; buf.order = oldOrder; if (length < JDWP_HEADER_LEN) { throw new BadPacketException(); } if (count < length) { return null; } JdwpPacket pkt = new JdwpPacket(buf); //pkt.mBuffer = buf; pkt.mLength = length; pkt.mId = id; pkt.mFlags = flags; if ((flags & REPLY_PACKET) == 0) { pkt.mCmdSet = cmdSet; pkt.mCmd = cmd; pkt.mErrCode = -1; } else { pkt.mCmdSet = -1; pkt.mCmd = -1; pkt.mErrCode = cmdSet | (cmd << 8); } return pkt; }
/// <summary> /// Like findPacket(), but when we're expecting the JDWP handshake. /// /// Returns one of: /// HANDSHAKE_GOOD - found handshake, looks good /// HANDSHAKE_BAD - found enough data, but it's wrong /// HANDSHAKE_NOTYET - not enough data has been read yet /// </summary> internal static int findHandshake(ByteBuffer buf) { int count = buf.position; int i; if (count < mHandshake.Length) { return HANDSHAKE_NOTYET; } for (i = mHandshake.Length - 1; i >= 0; --i) { if (buf.get(i) != mHandshake[i]) { return HANDSHAKE_BAD; } } return HANDSHAKE_GOOD; }
private void handleNHSG(Client client, ByteBuffer data) { var dataCopy = new byte[data.limit]; data.rewind(); data.get(dataCopy); data = ByteBuffer.wrap(dataCopy); client.clientData.nativeHeapData.addHeapData(data); if (true) { return; } /* WORK IN PROGRESS // Log.e("ddm-nativeheap", "NHSG: ----------------------------------"); // Log.e("ddm-nativeheap", "NHSG: " + data.limit() + " bytes"); var 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(); // Log.e("ddm-nativeheap", "id: " + id); // Log.e("ddm-nativeheap", "unitsize: " + unitsize); // Log.e("ddm-nativeheap", "startAddress: 0x" + Long.toHexString(startAddress)); // Log.e("ddm-nativeheap", "offset: " + offset); // Log.e("ddm-nativeheap", "allocationUnitCount: " + allocationUnitCount); // Log.e("ddm-nativeheap", "end: 0x" + // Long.toHexString(startAddress + unitsize * allocationUnitCount)); // read the usage while (buffer.position < buffer.limit) { int eState = buffer.get() & 0x000000ff; int eLen = (buffer.get() & 0x000000ff) + 1; //Log.e("ddm-nativeheap", "solidity: " + (eState & 0x7) + " - kind: " // + ((eState >> 3) & 0x7) + " - len: " + eLen); } // count += unitsize * allocationUnitCount; // Log.e("ddm-nativeheap", "count = " + count); */ }
/* * Handle the response from our REcent Allocation Query message. */ private void handleREAQ(Client client, ByteBuffer data) { bool enabled; enabled = (data.get() != 0); Log.d("ddm-heap", "REAQ says: enabled=" + enabled); client.clientData.allocationStatus = enabled ? ClientData.AllocationTrackingStatus.ON : ClientData.AllocationTrackingStatus.OFF; client.update(Client.CHANGE_HEAP_ALLOCATION_STATUS); }
private void handleFAIL(Client client, ByteBuffer data) { /*int errorCode =*/ data.getInt(); int length = data.getInt() * 2; string message = null; if (length > 0) { var messageBuffer = new byte[length]; data.get(messageBuffer, 0, length); message = Encoding.Default.GetString(messageBuffer); } // this can be sent if // - MPRS failed (like wrong permission) // - MPSE failed for whatever reason string filename = client.clientData.pendingMethodProfiling; if (filename != null) { // reset the pending file. client.clientData.pendingMethodProfiling = null; // and notify of failure ClientData.IMethodProfilingHandler handler = ClientData.methodProfilingHandler; if (handler != null) { handler.onStartFailure(client, message); } } else { // this is MPRE // notify of failure ClientData.IMethodProfilingHandler handler = ClientData.methodProfilingHandler; if (handler != null) { handler.onEndFailure(client, message); } } // send a query to know the current status try { sendMPRQ(client); } catch (IOException e) { Log.e("HandleProfiling", e); } }
/* * Handle a REcent ALlocation response. * * Message header (all values big-endian): * (1b) message header len (to allow future expansion); includes itself * (1b) entry header len * (1b) stack frame len * (2b) number of entries * (4b) offset to string table from start of message * (2b) number of class name strings * (2b) number of method name strings * (2b) number of source file name strings * For each entry: * (4b) total allocation size * (2b) threadId * (2b) allocated object's class name index * (1b) stack depth * For each stack frame: * (2b) method's class name * (2b) method name * (2b) method source file * (2b) line number, clipped to 32767; -2 if native; -1 if no source * (xb) class name strings * (xb) method name strings * (xb) source file strings * * As with other DDM traffic, strings are sent as a 4-byte length * followed by UTF-16 data. */ private void handleREAL(Client client, ByteBuffer data) { Log.e("ddm-heap", "*** Received " + name(CHUNK_REAL)); int messageHdrLen, entryHdrLen, stackFrameLen; int numEntries, offsetToStrings; int numClassNames, numMethodNames, numFileNames; /* * Read the header. */ messageHdrLen = (data.get() & 0xff); entryHdrLen = (data.get() & 0xff); stackFrameLen = (data.get() & 0xff); numEntries = (data.getShort() & 0xffff); offsetToStrings = data.getInt(); numClassNames = (data.getShort() & 0xffff); numMethodNames = (data.getShort()& 0xffff); numFileNames = (data.getShort()& 0xffff); /* * Skip forward to the strings and read them. */ data.position = offsetToStrings; string[] classNames = new string[numClassNames]; string[] methodNames = new string[numMethodNames]; string[] fileNames = new string[numFileNames]; readStringTable(data, classNames); readStringTable(data, methodNames); //System.out.println("METHODS: " // + java.util.Arrays.deepToString(methodNames)); readStringTable(data, fileNames); /* * Skip back to a point just past the header and start reading * entries. */ data.position = messageHdrLen; List<AllocationInfo> list = new List<AllocationInfo>(numEntries); int allocNumber = numEntries; // order value for the entry. This is sent in reverse order. for (int i = 0; i < numEntries; i++) { int totalSize; int threadId, classNameIndex, stackDepth; totalSize = data.getInt(); threadId = (data.getShort() & 0xffff); classNameIndex = (data.getShort() & 0xffff); stackDepth = (data.get() & 0xff); /* we've consumed 9 bytes; gobble up any extra */ for (int skip = 9; skip < entryHdrLen; skip++) { data.get(); } StackTraceElement[] steArray = new StackTraceElement[stackDepth]; /* * Pull out the stack trace. */ for (int sti = 0; sti < stackDepth; sti++) { int methodClassNameIndex, methodNameIndex; int methodSourceFileIndex; short lineNumber; string methodClassName, methodName, methodSourceFile; methodClassNameIndex = (data.getShort() & 0xffff); methodNameIndex = (data.getShort()& 0xffff); methodSourceFileIndex = (data.getShort()& 0xffff); lineNumber = data.getShort(); methodClassName = classNames[methodClassNameIndex]; methodName = methodNames[methodNameIndex]; methodSourceFile = fileNames[methodSourceFileIndex]; steArray[sti] = new StackTraceElement(methodClassName, methodName, methodSourceFile, lineNumber); /* we've consumed 8 bytes; gobble up any extra */ for (int skip = 9; skip < stackFrameLen; skip++) { data.get(); } } list.Add(new AllocationInfo(allocNumber--, classNames[classNameIndex], totalSize, (short) threadId, steArray)); } client.clientData.allocations = list.ToArray(); client.update(Client.CHANGE_HEAP_ALLOCATIONS); }
/* * Handle a thread status update message. * * Response has: * (1b) header len * (1b) bytes per entry * (2b) thread count * Then, for each thread: * (4b) threadId (matches value from THCR) * (1b) thread status * (4b) tid * (4b) utime * (4b) stime */ private void handleTHST(Client client, ByteBuffer data) { int headerLen, bytesPerEntry, extraPerEntry; int threadCount; headerLen = (data.get() & 0xff); bytesPerEntry = (data.get() & 0xff); threadCount = data.getShort(); headerLen -= 4; // we've read 4 bytes while (headerLen-- > 0) { data.get(); } extraPerEntry = bytesPerEntry - 18; // we want 18 bytes Log.v("ddm-thread", "THST: threadCount=" + threadCount); /* * For each thread, extract the data, find the appropriate * client, and add it to the ClientData. */ for (int i = 0; i < threadCount; i++) { int threadId, status, tid, utime, stime; bool isDaemon = false; threadId = data.getInt(); status = data.get(); tid = data.getInt(); utime = data.getInt(); stime = data.getInt(); if (bytesPerEntry >= 18) { isDaemon = (data.get() != 0); } Log.v("ddm-thread", " id=" + threadId + ", status=" + status + ", tid=" + tid + ", utime=" + utime + ", stime=" + stime); ClientData cd = client.clientData; ThreadInfo threadInfo = cd.getThread(threadId); if (threadInfo != null) { threadInfo.updateThread(status, tid, utime, stime, isDaemon); } else { Log.d("ddms", "Thread with id=" + threadId + " not found"); } // slurp up any extra for (int slurp = extraPerEntry; slurp > 0; slurp--) { data.get(); } } client.update(Client.CHANGE_THREAD_DATA); }