/// <summary> /// Sets the client to accept debugger connection on the custom "Selected debug port". </summary> /// <param name="selectedClient"> the client. Can be null. </param> void selectedClientent(Client selectedClient) { lock (this) { if (mInstance == null) { return; } if (mSelectedClient != selectedClient) { Client oldClient = mSelectedClient; mSelectedClient = selectedClient; if (oldClient != null) { oldClient.update(Client.CHANGE_PORT); } if (mSelectedClient != null) { mSelectedClient.update(Client.CHANGE_PORT); } } } }
/// <summary> /// Chunk handler entry point. /// </summary> internal override void handleChunk(Client client, int type, ByteBuffer data, bool 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.clientData.nativeHeapData.clearHeapData(); } else if (type == CHUNK_NHEN) { // end chunk after NHSG chunk(s) client.clientData.nativeHeapData.sealHeapData(); } else if (type == CHUNK_NHSG) { handleNHSG(client, data); } else { handleUnknownChunk(client, type, data, isReply, msgId); } client.update(Client.CHANGE_NATIVE_HEAP_DATA); }
/// <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); }
/* * 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); }
/* * 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 heap segment series end message. */ private void handleHPEN(Client client, ByteBuffer data) { /* Let the UI know that we've received all of the * data for this heap. */ //xxx todo: only seal data that belongs to the heap mentioned in <data>. client.clientData.vmHeapData.sealHeapData(); client.update(Client.CHANGE_HEAP_DATA); }
/* * Handle a thread death message. */ private void handleTHDE(Client client, ByteBuffer data) { int threadId; threadId = data.getInt(); Log.v("ddm-thread", "THDE: " + threadId); client.clientData.removeThread(threadId); client.update(Client.CHANGE_THREAD_DATA); }
/* * 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); }
/// <summary> /// Parse an incoming STKL. /// </summary> private void handleSTKL(Client client, ByteBuffer data) { StackTraceElement[] trace; int i, threadId, stackDepth; //JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes: //ORIGINAL LINE: @SuppressWarnings("unused") int future; int future; future = data.getInt(); threadId = data.getInt(); Log.v("ddms", "STKL: " + threadId); /* un-serialize the StackTraceElement[] */ stackDepth = data.getInt(); trace = new StackTraceElement[stackDepth]; for (i = 0; i < stackDepth; i++) { string className, methodName, fileName; int len, lineNumber; len = data.getInt(); className = getString(data, len); len = data.getInt(); methodName = getString(data, len); len = data.getInt(); if (len == 0) { fileName = null; } else { fileName = getString(data, len); } lineNumber = data.getInt(); trace[i] = new StackTraceElement(className, methodName, fileName, lineNumber); } ThreadInfo threadInfo = client.clientData.getThread(threadId); if (threadInfo != null) { threadInfo.stackCall = trace; client.update(Client.CHANGE_THREAD_STACKTRACE); } else { Log.d("STKL", string.Format("Got stackcall for thread {0:D}, which does not exists (anymore?).", threadId)); //$NON-NLS-1$ } }
/* * Handle a thread creation message. * * We should be tolerant of receiving a duplicate create message. (It * shouldn't happen with the current implementation.) */ private void handleTHCR(Client client, ByteBuffer data) { int threadId, nameLen; string name; threadId = data.getInt(); nameLen = data.getInt(); name = getString(data, nameLen); Log.v("ddm-thread", "THCR: " + threadId + " '" + name + "'"); client.clientData.addThread(threadId, name); client.update(Client.CHANGE_THREAD_DATA); }
/* * 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); }
/// <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); }
/// <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> /// Close the data connection only. /// </summary> /*lock*/ internal void closeData() { try { if (mChannel != null) { mChannel.close(); mChannel = null; mConnState = ST_NOT_CONNECTED; ClientData cd = mClient.clientData; cd.debuggerConnectionStatus = ClientData.DebuggerStatus.DEFAULT; mClient.update(Client.CHANGE_DEBUGGER_STATUS); } } catch (IOException) { Log.w("ddms", "Failed to close data " + this); } }
/* * Handle a reply to our HELO message. */ private static void handleHELO(Client client, ByteBuffer data) { int version, pid, vmIdentLen, appNameLen; string vmIdent, appName; version = data.getInt(); pid = data.getInt(); vmIdentLen = data.getInt(); appNameLen = data.getInt(); vmIdent = getString(data, vmIdentLen); appName = getString(data, appNameLen); Log.d("ddm-hello", "HELO: v=" + version + ", pid=" + pid + ", vm='" + vmIdent + "', app='" + appName + "'"); ClientData cd = client.clientData; lock (cd) { if (cd.pid == pid) { cd.vmIdentifier = vmIdent; cd.clientDescription = appName; cd.isDdmAware(true); } else { Log.e("ddm-hello", "Received pid (" + pid + ") does not match client pid (" + cd.pid + ")"); } } client = checkDebuggerPortForAppName(client, appName); if (client != null) { client.update(Client.CHANGE_NAME); } }
/// <summary> /// Opens (or reopens) the "debug selected" port and listen for connections. </summary> /// <returns> true if the port was opened successfully. </returns> /// <exception cref="IOException"> </exception> private bool reopenDebugSelectedPort() { Log.d("ddms", "reopen debug-selected port: " + mNewDebugSelectedPort); if (mDebugSelectedChan != null) { mDebugSelectedChan.close(); } mDebugSelectedChan = ServerSocketChannel.open(); mDebugSelectedChan.configureBlocking(false); // required for Selector var addr = new DnsEndPoint("localhost", mNewDebugSelectedPort); //$NON-NLS-1$ mDebugSelectedChan.socket().ExclusiveAddressUse = false; // enable SO_REUSEADDR try { mDebugSelectedChan.socket().Bind(addr); if (mSelectedClient != null) { mSelectedClient.update(Client.CHANGE_PORT); } mDebugSelectedChan.register(mSelector, SelectionKey.OP_ACCEPT, this); return(true); } catch (Exception) { displayDebugSelectedBindError(mNewDebugSelectedPort); // do not attempt to reopen it. mDebugSelectedChan = null; mNewDebugSelectedPort = -1; return(false); } }
/* * Handle a THNM (THread NaMe) message. We get one of these after * somebody calls Thread.setName() on a running thread. */ private void handleTHNM(Client client, ByteBuffer data) { int threadId, nameLen; string name; threadId = data.getInt(); nameLen = data.getInt(); name = getString(data, nameLen); Log.v("ddm-thread", "THNM: " + threadId + " '" + name + "'"); ThreadInfo threadInfo = client.clientData.getThread(threadId); if (threadInfo != null) { threadInfo.threadName = name; client.update(Client.CHANGE_THREAD_DATA); } else { Log.d("ddms", "Thread with id=" + threadId + " not found"); } }
/* * Handle a reply to our APNM message. */ private static void handleAPNM(Client client, ByteBuffer data) { int appNameLen; string appName; appNameLen = data.getInt(); appName = getString(data, appNameLen); Log.d("ddm-appname", "APNM: app='" + appName + "'"); ClientData cd = client.clientData; lock (cd) { cd.clientDescription = appName; } client = checkDebuggerPortForAppName(client, appName); if (client != null) { client.update(Client.CHANGE_NAME); } }
/* * 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 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); }